Product Card
The Product Card component shows a single product in the chat: an image, title, price, colour swatches and a View details button. The button opens a details view over the whole page (as a bottom sheet on mobile) with an image gallery, option pickers (e.g. width, colour and size), Add to cart, a description, a list of attributes and a link to the product page.
It works for any kind of product. The option labels are configurable, so the same message can describe shoe widths, sofa fabrics or watch strap lengths.
Options
Products can have up to three levels of options, each nested inside the one above:
- Variant groups (optional), e.g. widths. Shown as option buttons in the details view when there are two or more groups. With one group, or none, the buttons are hidden.
- Variants, e.g. colours. Shown as image swatches on the card and in the details view. The card shows up to 8 swatches; with more than 8 variants it shows the first 7 and a "+N" tile that opens the details view, where every variant is shown.
- Sizes. Shown as option buttons in the details view.
Values are taken from the most specific level that sets them: size, then variant, then group, then product. For example, a group's price overrides the product's price, and a size's price overrides both.
When the customer switches group, the same variant (matched by name) and size (matched by label) stay selected if the new group has them in stock. Otherwise the group's first variant is selected and the size is cleared.
Example
{
"type": "productCard",
"enableAddToCart": true,
"payload": {
"id": "clifton-11",
"trackingId": "clifton-11",
"title": "Men's Clifton 11",
"subtitle": "Men's | Everyday Running",
"badge": "Member Exclusive",
"image": "https://example.com/clifton-white.jpg",
"price": "$155.00",
"suffixText": "Built for everyday miles, with extra cushioning for long runs.",
"externalLink": "https://example.com/products/clifton-11",
"description": "A **max-cushioned** everyday trainer with a smoother, lighter ride.",
"attributes": [
{ "label": "Drop", "value": "5mm" },
{ "label": "Weight", "value": "9.7 oz" }
],
"variantGroupLabel": "Width",
"variantLabel": "Color",
"sizeLabel": "US Size",
"variantGroups": [
{
"id": "regular",
"label": "Regular",
"variants": [
{
"id": "clifton-11-r-white",
"name": "White / Blue",
"image": "https://example.com/clifton-white.jpg",
"images": [
"https://example.com/clifton-white.jpg",
"https://example.com/clifton-white-side.jpg"
],
"sizes": [
{ "id": "clifton-11-r-white-9", "label": "9" },
{ "id": "clifton-11-r-white-10", "label": "10" },
{ "id": "clifton-11-r-white-11", "label": "11", "disabled": true }
]
},
{
"id": "clifton-11-r-black",
"name": "Black / Virtual Blue",
"image": "https://example.com/clifton-black.jpg",
"discountPrice": "$130.00",
"sizes": [
{ "id": "clifton-11-r-black-10", "label": "10" },
{ "id": "clifton-11-r-black-11", "label": "11" }
]
}
]
},
{
"id": "wide",
"label": "Wide",
"price": "$160.00",
"variants": [
{
"id": "clifton-11-w-black",
"name": "Black / Virtual Blue",
"image": "https://example.com/clifton-black.jpg",
"sizes": [
{ "id": "clifton-11-w-black-9", "label": "9" },
{ "id": "clifton-11-w-black-10", "label": "10", "disabled": true }
]
}
]
},
{ "id": "x-wide", "label": "X-Wide", "disabled": true }
]
}
}A product without groups can use variants and sizes directly on the payload, the same as a Carousel slide:
{
"type": "productCard",
"payload": {
"id": "everyday-tee",
"title": "Everyday Tee",
"image": "https://example.com/tee-white.jpg",
"price": "£25",
"variants": [
{ "id": "tee-white", "name": "White", "image": "https://example.com/tee-white.jpg" },
{ "id": "tee-navy", "name": "Navy", "image": "https://example.com/tee-navy.jpg" }
],
"sizes": [
{ "id": "tee-s", "label": "S" },
{ "id": "tee-m", "label": "M" }
]
}
}Properties
- enableAddToCart (optional): Shows an Add to cart button in the details view when add to cart is available on the site (a Shopify store,
callbacks.onAddToCart, or a configuredecomPlatformandcartrequest; see Add to Cart). When a variant has more than one size, the customer must pick a size first.
payload
- id: The product's unique identifier. Used as the add to cart id when no variant or size is selected.
- title: The product name.
- trackingId (optional): Used for analytics tracking.
- image (optional): The product image. Variant and group images override it.
- images (optional): Images for the details view gallery. Falls back to
image. - price (optional): Display price, e.g.
"$155.00". - discountPrice (optional): Sale price. When set,
priceis shown struck through. - subtitle (optional): Short text above the title in the details view, e.g. a category.
- badge (optional): A highlighted label in the details view, e.g.
"New"or"Member Exclusive". - description (optional): Shown in the details view. Supports markdown.
- attributes (optional): A list of
{ label, value }pairs shown as a table in the details view, e.g. materials or dimensions. - externalLink (optional): The product page URL. Shown as a "View full product details" link in the details view. Opens in a new tab, or in the parent window when the
openLinksInNewTabgeneral setting is disabled. - variantGroupLabel (optional): Label for the group options, e.g.
"Width". Defaults to "Option". - variantLabel (optional): Label for the variant swatches, e.g.
"Color". Defaults to "Colour". - sizeLabel (optional): Label for the size options, e.g.
"US Size". Defaults to "Size". - variantGroups (optional): See Variant group properties.
- variants (optional): Variants used when there are no groups, or when a group doesn't have its own. See Variant properties.
- sizes (optional): Sizes used when a variant and its group don't have their own. See Size properties.
- suffixText (optional): Text shown at the bottom of the card, under the View details button, e.g. why the product was recommended. Shown in bold. Supports markdown.
- cartParams (optional, requires
enableAddToCart): Extra string fields added to a configured add to cart request body. Layered with the group's, variant's and size'scartParams, with the most specific winning.
Variant group properties
{
id: string | number; // Required
label?: string; // Required when there are two or more groups — shown on the option button
disabled?: boolean; // Shown struck through and can't be selected
price?: string;
discountPrice?: string;
image?: string;
images?: string[];
externalLink?: string;
cartParams?: Record<string, string>;
variants?: Variant[]; // Falls back to the product's variants
sizes?: Size[]; // Used for variants without their own sizes
}Variant properties
{
id: string | number; // Required — the add to cart id when there's no size
image: string; // Required — shown as the swatch
name: string; // Required — shown when selected, e.g. "Black / Virtual Blue"
images?: string[]; // Gallery images for this variant
title?: string; // Overrides the product title
price?: string;
discountPrice?: string;
externalLink?: string;
trackingId?: string;
sizes?: Size[];
cartParams?: Record<string, string>;
}Size properties
{
id: string | number; // Required — the add to cart id
label: string; // Required — shown on the option button, e.g. "9"
price?: string; // Overrides every other price
disabled?: boolean; // Out of stock; shown struck through and can't be selected
cartParams?: Record<string, string>;
}A single size that's in stock is selected automatically.
Add to cart
The item passed to callbacks.onAddToCart (or used to build the configured cart request) has:
- id: The selected size's
id, otherwise the selected variant'sid, otherwise the productid. - product_id: The product
id. - title: The title followed by the selected group (when there are two or more), variant and size, e.g.
"Men's Clifton 11 - Wide - Black / Virtual Blue - 9". - image, price, discountPrice, externalLink, trackingId and cartParams for the current selection.
Localisation
The following language keys are used and can be overridden via the lang config:
- productCard.viewDetailsButtonText: The card button (default: "View details").
- productCard.viewFullDetailsText: The product page link (default: "View full product details").
- productCard.variantGroupLabel, productCard.variantLabel, productCard.sizeLabel: Default option labels when the payload doesn't set them.
- carouselAddToCartButtonText and carouselSelectSizeLabel: Shared with the carousel.
Updated about 7 hours ago
