Skip to main content

Products

The Products page displays your complete product catalog with filtering and search capabilities.

Dashboard Features​

Catalog Statistics​

A single catalogue-health strip at the top, not a row of tiles. It reads N products · N categories · N brands, and beside it sits a pill for each thing that needs attention: products out of stock, products low on stock, and products missing a category or a brand. When there is nothing to flag it says Catalogue is complete instead. The counts cover the whole catalogue, not the page you are looking at.

Filters​

Filter products using multiple criteria:

FilterDescription
SearchFind products by name, description, or SKU
CategoryFilter by product category
BrandFilter by brand name
Stock StatusAll stock, In stock, Low stock, or Out of stock

Product Table​

A sortable table displaying:

ColumnDescription
ImageProduct thumbnail or placeholder
NameProduct name and SKU
PriceCurrent price and compare-at price (strikethrough)
CategoryProduct categories (badges)
BrandBrand name
StockIn stock (green), a low-stock warning with the units left (amber), or Out of stock (red)
Revenue 30dRevenue over the last 30 days, with an arrow for the change against the previous 30, and the units sold underneath. Products with no sales in the window say so

Viewing Products​

  1. Navigate to E-Commerce > Products
  2. Use the search box to find specific products
  3. Apply filters to narrow results
  4. Browse paginated results

Understanding Product Data​

Product Fields​

FieldDescription
externalIdYour unique product identifier (e.g., SKU)
nameProduct display name
priceCurrent selling price. Empty when the store gives the product no price: the catalog shows "No price", and the product never matches a price condition ("price below 10" does not treat it as 0). A price of 0 set in the store stays 0
compareAtPriceOriginal price (shows discount)
currencyPrice currency code
categoriesArray of category names
tagsArray of product tags
brandBrand or vendor name
imageUrlMain product image
inStockAvailability status
variantsSize/color variations

Variants​

Products can have multiple variants with different:

  • Prices
  • SKUs
  • Stock status
  • Options (size, color, etc.)

Syncing Products​

Products are typically synced from your e-commerce platform. Joryio supports:

  • Shopify - Automatic sync via webhook
  • WooCommerce - REST API integration
  • Magento - Joryio Connect extension
  • Custom platforms - Use the Products API

Bulk Import​

Use the bulk upsert API to import products - POST a bare JSON array (max 500) to the products endpoint:

POST /catalog/products
[
{ "productId": "SKU-001", "name": "Product 1", "price": 19.99, "source": "shopify" },
{ "productId": "SKU-002", "name": "Product 2", "price": 29.99, "source": "shopify" }
]

Using Products in Campaigns​

Product Recommendations​

Include products in email campaigns using Liquid templates:

{% assign picks = 'featured' | products %}
{% for product in picks %}
<div class="product">
<img src="{{ product.imageUrl }}" alt="{{ product.name }}">
<h3>{{ product.name }}</h3>
<p>${{ product.price }}</p>
<a href="{{ product.url }}">Shop Now</a>
</div>
{% endfor %}

'featured' is the name of a product selection saved on the Products page. The products filter runs on every send and in preview; see the Liquid reference.

For per-customer picks (personalized, bought together, similar items, new arrivals and more) in any channel, see Product recommendations.

Personalization​

Three variables describe what the recipient bought, or is about to. They resolve per contact at send time and in preview, in every channel, for campaigns and journeys alike - and they are empty for a contact with no store orders, so wrap each in {% if %}.

VariableWhat it holdsUse it when
cartThe store cart synced for the contact: items, value, subtotal (the items subtotal, before shipping), currency, itemCount, checkoutUrl. Empty when the cart is emptyCart recovery - "you left these behind", with the checkout link
last_orderTheir most recent order that was not cancelled or refunded: id, placedAt, total, currency, status, itemCount, items, orderUrlReorder and follow-up - "how was your order?", "order it again"
top_productsThe products they order most often, up to 5, most frequent first: name, sku, imageUrl, url, timesOrdered, lastOrderedAtHabit-based offers - "your usual?"

Items on cart.items and last_order.items share one shape - name, quantity, price, total, imageUrl, url, sku - so a loop written for one works over the other.

Abandoned cart:

{% if cart %}
{% for item in cart.items %}
<p>{{ item.name }} x {{ item.quantity }} - {{ item.total | currency: cart.currency }}</p>
{% endfor %}
<p>Cart total: {{ cart.value | currency: cart.currency }}</p>
<a href="{{ cart.checkoutUrl }}">Complete purchase</a>
{% endif %}

Which link. {{ cart.checkoutUrl }} is the store's own recovery link for the cart (WooCommerce, Magento and PrestaShop: the link the Joryio plugin sends when the cart is abandoned; Shopify: the checkout's recovery link), so it rebuilds the cart on any device. Only a cart the store sent no recovery link for falls back to the store's checkout page. A link that is not on the connected store's own address is never used. A cart abandoned before this rule (2026-11-01) keeps the plain checkout page until the store reports it abandoned again.

A contact with no cart. A cart email whose button links {{ cart.checkoutUrl }} is not sent to someone with no synced cart (or a cart the store gave no recovery link): the link would render empty, a button that goes nowhere. It is recorded as skipped, reason No cart link to send (cart_link_missing). To send anyway, give the link a fallback: {{ cart.checkoutUrl | default: 'https://your-store.com/cart' }}. The email preview shows a labelled sample cart for a preview contact with none, and Launch Review warns when a journey message reads cart but the journey does not start on a cart event (Cart Abandoned, Checkout Started, Product Added, Cart Updated, Cart Viewed).

Last order and usual products:

{% if top_products.size > 0 %}
<p>Your usual, {{ user.firstName }}? {{ top_products | map: "name" | join: " + " }}</p>
{% endif %}
{% if last_order %}
<p>Last time ({{ last_order.placedAt | date_format }}) you ordered:</p>
{% for item in last_order.items %}
<p><a href="{{ item.url }}">{{ item.name }}</a> x {{ item.quantity }}</p>
{% endfor %}
{% endif %}

Pick one from the personalization picker's Shopping group in any editor to insert a ready-made snippet. The full list is in the Liquid reference.

Product Selections​

A Selection is a saved, reusable filter over your product catalog - for example "discounted footwear", "in-stock items under $50", or "everything tagged new-arrival". Build them once and reuse them wherever you show products.

Create one: on the Products page click Selections → New Selection. Give it a name, add one or more rules over product fields (name, brand, price, in-stock, categories, tags, …) with type-aware operators, choose whether to match all or any of the rules, and set a max number of products. Preview shows exactly which products match right now.

Selections are the product-catalog counterpart of entity Selections - a saved filter tree you can point content and recommendations at instead of hand-listing product IDs.

Best Practices​

  1. Keep products synced: Ensure regular sync with your e-commerce platform
  2. Use high-quality images: Product images improve email engagement
  3. Maintain accurate stock: Out-of-stock notifications require accurate data
  4. Categorize consistently: Use consistent categories for better filtering
  5. Include URLs: Product URLs enable click-through tracking

Troubleshooting​

Products Not Appearing​

  • Check your API authentication
  • Verify workspace ID is correct
  • Ensure products have required fields (externalId, name, price)

Images Not Loading​

  • Verify image URLs are publicly accessible
  • Check for HTTPS requirements
  • Ensure image URLs aren't expired

Stock Status Incorrect​

  • Sync interval may need adjustment
  • Check webhook configuration
  • Verify inventory tracking is enabled

Next Steps​