Skip to main content
Solved

Custom html template with dynamic product content

  • June 4, 2025
  • 9 replies
  • 357 views

Forum|alt.badge.img

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.

 

Best answer by DishaM13

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 products[0] to products[1], 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. 

9 replies

In the Inbox
Partner - Platinum
Forum|alt.badge.img+31
  • 2025 Champion
  • 336 replies
  • June 4, 2025

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 


Forum|alt.badge.img
  • Author
  • Contributor I
  • 4 replies
  • June 5, 2025

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.


Forum|alt.badge.img+18
  • Partner
  • 64 replies
  • Answer
  • June 5, 2025

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 products[0] to products[1], 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. 


Forum|alt.badge.img+18
  • Partner
  • 64 replies
  • June 6, 2025

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!


Forum|alt.badge.img
  • Author
  • Contributor I
  • 4 replies
  • June 11, 2025

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 products[0] to products[1], 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).

 

 


Forum|alt.badge.img+18
  • Partner
  • 64 replies
  • June 12, 2025

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_products[0] %}
{% 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.


Forum|alt.badge.img
  • Author
  • Contributor I
  • 4 replies
  • June 12, 2025

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_products[0] %}
{% 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.


Forum|alt.badge.img+18
  • Partner
  • 64 replies
  • June 16, 2025

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.


Forum|alt.badge.img
  • Author
  • Contributor I
  • 4 replies
  • June 16, 2025

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!