Skip to main content

We use Klaviyo with a custom HTML template.

We’ve created several universal blocks, including a product block that contains the product name, price, button (with URL), and image.

Now, I want to create a universal block for use in flows — for example, a “next best product” block. I want the product title, price, URL, and image to be loaded dynamically based on the customer receiving the email. For one customer this might be Product A, and for another it could be Product B.

We use WooCommerce and the product catalog is connected.

Does anyone have any idea how this can be done?

See screenshot for what I tried.

 

Hi ​@dennygoosensen 

Thank you for posting your question in the community. Hopefully, I can help. 

If I understand correctly, if a customer purchases product A, then you want to show a dynamic product block that recommends the next best product based on purchasing product A. 

This would be a little bit of work to set up, but I think you would use an If Statement such that If product A is purchased, show “the next best product X,” if else, product B is purchased, show “the next best product Y,” etc. 

There are a couple of great resources on how to set this up:
Writing If/Endif/Elif/Else Statements
Using Conditionals in Messages

You can still use the catalog lookup in the IF statements to dynamically pull in the product info (image, name, etc.) within each If statement. 

Take a look and let me know if this helps!

@In the Inbox 


Hi ​@In the Inbox thanks for your reply.

We want to setup universal blocks that we can use in different kind of flows, for example: next best product.

We want to use our own custom html product blocks.

Is this something you can help us with? We are looking for a person or company who can do this for us.


Hi ​@dennygoosensen 
Your WooCommerce product catalog must already be synced to Klaviyo. (Sounds like it is, great!)

Dynamic Product Recommendations, you want to use a personalized product per user and correct HTML Template with Klaviyo Tags.

Step-by-Step Setup

1) Loop Over a Catalog

You already have this line in your code:

{% catalog products limit:1 %}


That’s the correct way to loop through a catalog! But for personalization, you’ll want to use lookup, recommended_products, or other dynamic options but let’s keep it simple for now and use a universal block with a product recommendation tag that automatically adjusts per user.

2) Working Version for One Product (Use in Flows):

{% assign product = catalog.recommended_products_0] %}
{% if product %}
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="center" valign="top">
<table width="280" border="0" cellspacing="0" cellpadding="0" align="center" style="width: 280px;">
<tr>
<td align="left">
<a href="{{ product.url }}" target="_blank">
<img src="{{ product.image_url }}" width="280" alt="{{ product.title }}" style="display: block; font-family: Arial, sans-serif; font-size: 16px; color: #000000; font-weight: bold;">
</a>
</td>
</tr>
<tr>
<td align="left" style="padding-top: 10px; font-family: Arial, sans-serif; font-size: 16px; line-height: 22px; color: #333333;">
<a href="{{ product.url }}" target="_blank" style="text-decoration: none; color: #333333;">{{ product.title }}</a>
</td>
</tr>
<tr>
<td align="left" style="font-family: Arial, sans-serif; font-size: 16px; line-height: 22px; color: #00b4f0; padding-top: 5px;">
{{ product.price | money }}
</td>
</tr>
<tr>
<td align="left" style="padding-top: 10px;">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td bgcolor="#00b4f0" align="center" height="38" style="border-radius:4px; padding: 0 20px;">
<a href="{{ product.url }}" target="_blank" style="font-family: Arial, sans-serif; font-size: 14px; letter-spacing: 1px; font-weight: 600; color: #ffffff; text-decoration: none; display: inline-block; line-height: 38px;">Bekijk deal</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
{% endif %}

What This Does: catalog.recommended_products → automatically shows a personalized recommendation for each recipient.

    It displays:

        Image: product.image_url

        Title: product.title

        Price: product.price

        Button URL: product.url

3) How to Test It

    1) Go to Flows in Klaviyo.

    2) Insert your custom block into a flow email.

    3) Preview the email with a real user profile (with shopping/browsing history).

    4) Klaviyo will automatically choose a product per user.

Extra Tips: You can change productsp0] to productso1], products 2], etc. for “next-next best product.”

Want to show multiple products? Use a loop:

{% for product in catalog.recommended_products limit:3 %}
<!-- product block HTML here -->
{% endfor %}

Let me know if this works. 


Hi ​@dennygoosensen 
I totally get that this stuff can feel a bit overwhelming. Using dynamic catalog data in custom HTML blocks is super powerful, especially for flows like “next best product” but it does take some setup to get it running smoothly across different flows.
At Mavlers, this is exactly where our clients usually tap us for help since it’s one of our core strengths.
Feel free to shoot me a DM anytime, I’d be happy to help you build it out!


Hi ​@dennygoosensen 
Your WooCommerce product catalog must already be synced to Klaviyo. (Sounds like it is, great!)

Dynamic Product Recommendations, you want to use a personalized product per user and correct HTML Template with Klaviyo Tags.

Step-by-Step Setup

1) Loop Over a Catalog

You already have this line in your code:

{% catalog products limit:1 %}


That’s the correct way to loop through a catalog! But for personalization, you’ll want to use lookup, recommended_products, or other dynamic options but let’s keep it simple for now and use a universal block with a product recommendation tag that automatically adjusts per user.

2) Working Version for One Product (Use in Flows):

{% assign product = catalog.recommended_products_0] %}
{% if product %}
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="center" valign="top">
<table width="280" border="0" cellspacing="0" cellpadding="0" align="center" style="width: 280px;">
<tr>
<td align="left">
<a href="{{ product.url }}" target="_blank">
<img src="{{ product.image_url }}" width="280" alt="{{ product.title }}" style="display: block; font-family: Arial, sans-serif; font-size: 16px; color: #000000; font-weight: bold;">
</a>
</td>
</tr>
<tr>
<td align="left" style="padding-top: 10px; font-family: Arial, sans-serif; font-size: 16px; line-height: 22px; color: #333333;">
<a href="{{ product.url }}" target="_blank" style="text-decoration: none; color: #333333;">{{ product.title }}</a>
</td>
</tr>
<tr>
<td align="left" style="font-family: Arial, sans-serif; font-size: 16px; line-height: 22px; color: #00b4f0; padding-top: 5px;">
{{ product.price | money }}
</td>
</tr>
<tr>
<td align="left" style="padding-top: 10px;">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td bgcolor="#00b4f0" align="center" height="38" style="border-radius:4px; padding: 0 20px;">
<a href="{{ product.url }}" target="_blank" style="font-family: Arial, sans-serif; font-size: 14px; letter-spacing: 1px; font-weight: 600; color: #ffffff; text-decoration: none; display: inline-block; line-height: 38px;">Bekijk deal</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
{% endif %}

What This Does: catalog.recommended_products → automatically shows a personalized recommendation for each recipient.

    It displays:

        Image: product.image_url

        Title: product.title

        Price: product.price

        Button URL: product.url

3) How to Test It

    1) Go to Flows in Klaviyo.

    2) Insert your custom block into a flow email.

    3) Preview the email with a real user profile (with shopping/browsing history).

    4) Klaviyo will automatically choose a product per user.

Extra Tips: You can change productsp0] to productso1], products 2], etc. for “next-next best product.”

Want to show multiple products? Use a loop:

{% for product in catalog.recommended_products limit:3 %}
<!-- product block HTML here -->
{% endfor %}

Let me know if this works. 

Hi, thanks for your reply. I tried your code by creating a new standard flow called “Next Best Product” and inserted your HTML. I selected a customer with Predictive Analytics enabled.

However, when I previewed the campaign, nothing was displayed (see attached screenshot).

 

 


Hi ​@dennygoosensen 

1. Confirm Catalog Sync and Product Data

Ensure your WooCommerce product catalog is syncing successfully with Klaviyo.

Check that the recommended products have valid values for:

1. image_url

2. title

3. price

4. url

If any of these fields are missing, the product block will not render.

2. Predictive Recommendations Eligibility

While you’ve chosen a customer with Predictive Analytics enabled, please ensure they also:

Have enough event data (browse/purchase history).

Aren’t excluded from product recommendations due to catalog rules (e.g. out of stock, unpublished).

3. Fallback Logic

If a recommendation doesn’t exist, the block won’t render. You can optionally add fallback content or logics like:

{% assign product = catalog.recommended_productse0] %}
{% if product %}
<!-- show recommended product block -->
{% else %}
<!-- optional fallback content -->
{% endif %}

4. Use Real Preview (Not Desktop Test Email)

When previewing the flow:

Use the "Preview and Test" feature with a real profile, not just the desktop test send.

You can also try sending a live email to yourself using a test profile with recent browsing/purchase activity to confirm.


Hi ​@dennygoosensen 

1. Confirm Catalog Sync and Product Data

Ensure your WooCommerce product catalog is syncing successfully with Klaviyo.

Check that the recommended products have valid values for:

1. image_url

2. title

3. price

4. url

If any of these fields are missing, the product block will not render.

2. Predictive Recommendations Eligibility

While you’ve chosen a customer with Predictive Analytics enabled, please ensure they also:

Have enough event data (browse/purchase history).

Aren’t excluded from product recommendations due to catalog rules (e.g. out of stock, unpublished).

3. Fallback Logic

If a recommendation doesn’t exist, the block won’t render. You can optionally add fallback content or logics like:

{% assign product = catalog.recommended_productse0] %}
{% if product %}
<!-- show recommended product block -->
{% else %}
<!-- optional fallback content -->
{% endif %}

4. Use Real Preview (Not Desktop Test Email)

When previewing the flow:

Use the "Preview and Test" feature with a real profile, not just the desktop test send.

You can also try sending a live email to yourself using a test profile with recent browsing/purchase activity to confirm.

Hi Thanks for your reply,

Yes the woocommerce catalog is synced and updated.

What do you mean by: Check that the recommended products have valid values for:
1. image_url
2. title
3. price
4. url

Yes I used a customer profile with the test and preview function with a lot of purchase history.


Thanks for confirming that your WooCommerce catalog is synced.

When I mentioned "valid values", I meant making sure that each product in your catalog has actual, non-empty data for these fields:

  1. image_url – a working image link

  2. title – a product name

  3. price – a numeric value

  4. url – a valid product page link

If any of these fields are missing or blank for a product, Klaviyo’s product block might skip rendering that product.


Thanks for confirming that your WooCommerce catalog is synced.

When I mentioned "valid values", I meant making sure that each product in your catalog has actual, non-empty data for these fields:

  1. image_url – a working image link

  2. title – a product name

  3. price – a numeric value

  4. url – a valid product page link

If any of these fields are missing or blank for a product, Klaviyo’s product block might skip rendering that product.



Hi,

No all of the fields have valid values!


Reply