20 added
20 removed
Original
2026-01-01
Modified
2026-03-10
1
<p><em>Solution Recipes are tutorials to achieve specific objectives in Klaviyo. They can also help you master Klaviyo, learn new third-party technologies, and come up with creative ideas. They are written mainly for developers & technically-advanced users.</em></p>
1
<p><em>Solution Recipes are tutorials to achieve specific objectives in Klaviyo. They can also help you master Klaviyo, learn new third-party technologies, and come up with creative ideas. They are written mainly for developers & technically-advanced users.</em></p>
2
-
<p><strong><em>Note:</em></strong><em>We do our best to make sure any code and API references are accurate and current when this is published, but you might need to update code and it’s always a best practice to leverage our</em><a><em>latest API versions</em></a><em>. If you have questions, feel free to hop over to our</em><a><em>Developer Community</em></a><em>.</em></p>
2
+
<p><em><strong>Note:</strong>We do our best to make sure any code and API references are accurate and current when this is published, but you might need to update code and it’s always a best practice to leverage our<a>latest API versions</a>. If you have questions, feel free to hop over to our<a>Developer Community</a>.</em></p>
3
<p>What you’ll learn</p>
3
<p>What you’ll learn</p>
4
<p>How to build custom product blocks using the drag and drop editor sourcing product data from Klaviyo product recommendations engine, and as a bonus, Google Sheets.</p>
4
<p>How to build custom product blocks using the drag and drop editor sourcing product data from Klaviyo product recommendations engine, and as a bonus, Google Sheets.</p>
5
<p>Why it matters</p>
5
<p>Why it matters</p>
6
<p>Klaviyo products blocks provide the ability to quickly add products to an email. However, they can be limiting in many use cases as the standard block is not extensible. This solution provides email marketers with the ability to build custom blocks utilising all product metadata, including brand, sale price, descriptions, any additional product images and localisation data.</p>
6
<p>Klaviyo products blocks provide the ability to quickly add products to an email. However, they can be limiting in many use cases as the standard block is not extensible. This solution provides email marketers with the ability to build custom blocks utilising all product metadata, including brand, sale price, descriptions, any additional product images and localisation data.</p>
7
<p>Level of sophistication</p>
7
<p>Level of sophistication</p>
8
<p>Easy to moderate</p>
8
<p>Easy to moderate</p>
9
<h2>Introduction</h2>
9
<h2>Introduction</h2>
10
<p>Klaviyo offers an out of the box Product Block available within the Klaviyo email editor. While this offers a fantastic way to add product data to an email, it is limited to the following product fields only:</p>
10
<p>Klaviyo offers an out of the box Product Block available within the Klaviyo email editor. While this offers a fantastic way to add product data to an email, it is limited to the following product fields only:</p>
11
<ul><li>Name</li>
11
<ul><li>Name</li>
12
<li>Price</li>
12
<li>Price</li>
13
<li>Main Image</li>
13
<li>Main Image</li>
14
<li>Link</li>
14
<li>Link</li>
15
</ul><p>Additionally, the product block is limited to styling edits only, layout changes are not possible.</p>
15
</ul><p>Additionally, the product block is limited to styling edits only, layout changes are not possible.</p>
16
<p>Many retailers would like to extend this product block functionality to make use of additional product metadata that maybe passed in to the product catalog. Commonly, these include:</p>
16
<p>Many retailers would like to extend this product block functionality to make use of additional product metadata that maybe passed in to the product catalog. Commonly, these include:</p>
17
<ul><li>Sale price</li>
17
<ul><li>Sale price</li>
18
<li>Brand</li>
18
<li>Brand</li>
19
<li>Description</li>
19
<li>Description</li>
20
<li>Additional product images</li>
20
<li>Additional product images</li>
21
<li>Product translations</li>
21
<li>Product translations</li>
22
</ul><p>This solution will show how you can build custom product blocks utilising Klaviyo’s AI driven product recommendation feeds. As a bonus, this guide will also show how you can hook up your product block with a Google Sheet to provide a source for manually created product feeds.</p>
22
</ul><p>This solution will show how you can build custom product blocks utilising Klaviyo’s AI driven product recommendation feeds. As a bonus, this guide will also show how you can hook up your product block with a Google Sheet to provide a source for manually created product feeds.</p>
23
<h2>Challenge</h2>
23
<h2>Challenge</h2>
24
<p>Traditionally, customisation of the products would require a custom product block where advanced CSS and HTML knowledge is required. This option is still available for marketers who wish to retain full control of the HTML/CSS (<a>see guide here</a>)</p>
24
<p>Traditionally, customisation of the products would require a custom product block where advanced CSS and HTML knowledge is required. This option is still available for marketers who wish to retain full control of the HTML/CSS (<a>see guide here</a>)</p>
25
<p>This article will show how email marketers can build the custom product block using the drag and drop elements available, with no HTML or CSS knowledge required.</p>
25
<p>This article will show how email marketers can build the custom product block using the drag and drop elements available, with no HTML or CSS knowledge required.</p>
26
<h2>Ingredients</h2>
26
<h2>Ingredients</h2>
27
<ul><li>Product Catalog</li>
27
<ul><li>Product Catalog</li>
28
<li>Product Feeds configured</li>
28
<li>Product Feeds configured</li>
29
</ul><p><strong>BONUS Requirements:</strong></p>
29
</ul><p><strong>BONUS Requirements:</strong></p>
30
<ul><li><a>Napkin.io</a>Account</li>
30
<ul><li><a>Napkin.io</a>Account</li>
31
<li>Google Sheets</li>
31
<li>Google Sheets</li>
32
</ul><h2>Instructions</h2>
32
</ul><h2>Instructions</h2>
33
<h3>1. Create a product feed.</h3>
33
<h3>1. Create a product feed.</h3>
34
-
<p>Product feeds take in data from your product catalog and customer behavior (e.g., the products they’ve viewed or purchased in the past) and use this information to provide custom product recommendations for your subscribers. <a>How to use product feeds and recommendations</a></p>
34
+
<p>Product feeds take in data from your product catalog and customer behavior (e.g., the products they’ve viewed or purchased in the past) and use this information to provide custom product recommendations for your subscribers.<a>How to use product feeds and recommendations</a></p>
35
<p>To create a feed, simply:</p>
35
<p>To create a feed, simply:</p>
36
<ol><li>In Klaviyo, select Content in the left hand menu.</li>
36
<ol><li>In Klaviyo, select Content in the left hand menu.</li>
37
<li>In the dropdown, click Products.</li>
37
<li>In the dropdown, click Products.</li>
38
<li>In the upper right, click Manage Product Feeds, then click Create Product Feed.</li>
38
<li>In the upper right, click Manage Product Feeds, then click Create Product Feed.</li>
39
<li>Set up the conditions & rules for your product feed.</li>
39
<li>Set up the conditions & rules for your product feed.</li>
40
<li>Make a note of the product feed name your used.</li>
40
<li>Make a note of the product feed name your used.</li>
41
-
</ol><p>Full instructions can be found here: <a>Configure a product feed</a>.</p>
41
+
</ol><p>Full instructions can be found here:<a>Configure a product feed</a>.</p>
42
<h3>2. Build your custom product block</h3>
42
<h3>2. Build your custom product block</h3>
43
-
<p>We will need to now add a section that repeats for every product in the recommended product feed. This section will perform a <a>catalog lookup</a> on the ‘<strong>item_id’</strong> from the feed, and then provide you with the content to display to your requirements.</p>
43
+
<p>We will need to now add a section that repeats for every product in the recommended product feed. This section will perform a<a>catalog lookup</a>on the ‘<strong>item_id’</strong>from the feed, and then provide you with the content to display to your requirements.</p>
44
<h4>How to add a vertically stacked product recommendation block</h4>
44
<h4>How to add a vertically stacked product recommendation block</h4>
45
<p>Drag in a section block</p>
45
<p>Drag in a section block</p>
46
<p>Click on display conditions and set the repeating region to use ‘<strong>feeds.ProductFeedName|slice:3</strong>’ (replacing ProductFeedName with the name of your product feed defined in step 1 and the number 3 with the number of products you wish to pull from the feed), and set it ‘as item’.</p>
46
<p>Click on display conditions and set the repeating region to use ‘<strong>feeds.ProductFeedName|slice:3</strong>’ (replacing ProductFeedName with the name of your product feed defined in step 1 and the number 3 with the number of products you wish to pull from the feed), and set it ‘as item’.</p>
47
<p>To ensure that we ‘load’ the feed into the template, we must add a product block to the template. This will then provide us with access to the product feed for our custom product block. We will then hide this product block so that it does not show.</p>
47
<p>To ensure that we ‘load’ the feed into the template, we must add a product block to the template. This will then provide us with access to the product feed for our custom product block. We will then hide this product block so that it does not show.</p>
48
<p>Drag a product item into the top of the section</p>
48
<p>Drag a product item into the top of the section</p>
49
<p>Configure the product to use a ‘<strong>Dynamic</strong>’ source, and select the product feed you have created. Also, disable all fields and choose to display only one product. It should look similar to this:</p>
49
<p>Configure the product to use a ‘<strong>Dynamic</strong>’ source, and select the product feed you have created. Also, disable all fields and choose to display only one product. It should look similar to this:</p>
50
<p>Now select ‘Display Options’ and in the display conditions set the value to ‘<strong>false</strong>’</p>
50
<p>Now select ‘Display Options’ and in the display conditions set the value to ‘<strong>false</strong>’</p>
51
<p>Next we need to perform a catalog lookup so that we can pull the catalog content from the current item in the feed. Drag a text block into the section and add the catalog lookup based upon the item that we’re looping over from the repeating section, in this case, we set this to ‘<strong>item</strong>’ and the value of ‘<strong>item_id</strong>’.</p>
51
<p>Next we need to perform a catalog lookup so that we can pull the catalog content from the current item in the feed. Drag a text block into the section and add the catalog lookup based upon the item that we’re looping over from the repeating section, in this case, we set this to ‘<strong>item</strong>’ and the value of ‘<strong>item_id</strong>’.</p>
52
{% catalog item.item_id %}<p>Add another text block under this one, this time closing the catalog lookup with:</p>
52
{% catalog item.item_id %}<p>Add another text block under this one, this time closing the catalog lookup with:</p>
53
-
{% endcatalog %}<p>The resulting template will look like this:</p>
53
+
<p>The resulting template will look like this:</p>
54
<p>Now you can build your custom product block using the Klaviyo content blocks. Simply drag elements between these two blocks and utilise the catalog_item values</p>
54
<p>Now you can build your custom product block using the Klaviyo content blocks. Simply drag elements between these two blocks and utilise the catalog_item values</p>
55
-
<p>The standard catalog_item values can be found here: <a>https://help.klaviyo.com/hc/en-us/articles/360004785571-Catalog-lookup-tag-reference</a></p>
55
+
<p>The standard catalog_item values can be found here:<a>https://help.klaviyo.com/hc/en-us/articles/360004785571-Catalog-lookup-tag-reference</a></p>
56
<p>For example:</p>
56
<p>For example:</p>
57
-
<p>To add an image, drag the image block, and click on <strong>‘Dynamic URL’</strong> and add</p>
57
+
<p>To add an image, drag the image block, and click on<strong>‘Dynamic URL’</strong>and add</p>
58
{{ catalog_item.featured_image.thumbnail.src }}<p>To add text, drag a text field and add content such as the product title, description and price:</p>
58
{{ catalog_item.featured_image.thumbnail.src }}<p>To add text, drag a text field and add content such as the product title, description and price:</p>
59
{{ catalog_item.title }} {{ catalog_item.description }} {% currency_format catalog_item.metadata|lookup:"$price" %}<p>You are then able to use the editor to style these values as required.</p>
59
{{ catalog_item.title }} {{ catalog_item.description }} {% currency_format catalog_item.metadata|lookup:"$price" %}<p>You are then able to use the editor to style these values as required.</p>
60
<p>To add a Shop Now button, drop in the button block, and add the following as the URL.</p>
60
<p>To add a Shop Now button, drop in the button block, and add the following as the URL.</p>
61
-
{{ catalog_item.url }}<p>You can also use any custom catalog attributes. These can all be found within the ‘<strong>catalog_item.metadata</strong><em>’</em> object.</p>
61
+
<p>You can also use any custom catalog attributes. These can all be found within the ‘<strong>catalog_item.metadata</strong><em>’</em>object.</p>
62
<p>Once you’re happy with the block, you can now save as a ‘<strong>Universal Content Block</strong>’. This will allow you to drop the content block into any email within a flow or campaign.</p>
62
<p>Once you’re happy with the block, you can now save as a ‘<strong>Universal Content Block</strong>’. This will allow you to drop the content block into any email within a flow or campaign.</p>
63
<p>Now to preview. The result should be similar to this:</p>
63
<p>Now to preview. The result should be similar to this:</p>
64
<h4>How to add a column based product recommendation block</h4>
64
<h4>How to add a column based product recommendation block</h4>
65
<p>Drag in a section block</p>
65
<p>Drag in a section block</p>
66
<p>To ensure that we ‘load’ the feed into the template, we must add a product block to the template. This will then provide us with access to the product feed for our custom product block. We will then hide this product block so that it does not show.</p>
66
<p>To ensure that we ‘load’ the feed into the template, we must add a product block to the template. This will then provide us with access to the product feed for our custom product block. We will then hide this product block so that it does not show.</p>
67
<p>Drag a product item into the top of the section</p>
67
<p>Drag a product item into the top of the section</p>
68
<p>Configure the product to use a ‘Dynamic’ source, and select the product feed you have created. Also, disable all fields and choose to display only one product. It should look similar to this:</p>
68
<p>Configure the product to use a ‘Dynamic’ source, and select the product feed you have created. Also, disable all fields and choose to display only one product. It should look similar to this:</p>
69
<p>Next we create the columns we wish to use. Simply drag the columns block into the section below the product block, and select the style & number of columns you wish to use.</p>
69
<p>Next we create the columns we wish to use. Simply drag the columns block into the section below the product block, and select the style & number of columns you wish to use.</p>
70
<p>As the number of columns is not dynamic, we will need to call the product item directly for each column.</p>
70
<p>As the number of columns is not dynamic, we will need to call the product item directly for each column.</p>
71
<p>To achieve this, we need to perform a catalog lookup so that we can pull the catalog content from the current item in the feed. Drag a text block into the first column and add the catalog lookup based upon the first item (index of 0) in the feed, and pull the the item_id.</p>
71
<p>To achieve this, we need to perform a catalog lookup so that we can pull the catalog content from the current item in the feed. Drag a text block into the first column and add the catalog lookup based upon the first item (index of 0) in the feed, and pull the the item_id.</p>
72
{% catalog feeds.ProductFeedName.0.item_id %}<p>Add another text block under this one, this time closing the catalog lookup with:</p>
72
{% catalog feeds.ProductFeedName.0.item_id %}<p>Add another text block under this one, this time closing the catalog lookup with:</p>
73
-
{% endcatalog %}<p>Now you can build your custom product block using the Klaviyo content blocks. Simply drag elements between these two blocks and utilise the catalog_item values</p>
73
+
<p>Now you can build your custom product block using the Klaviyo content blocks. Simply drag elements between these two blocks and utilise the catalog_item values</p>
74
-
<p>The standard catalog_item values can be found here: <a>https://help.klaviyo.com/hc/en-us/articles/360004785571-Catalog-lookup-tag-reference</a></p>
74
+
<p>The standard catalog_item values can be found here:<a>https://help.klaviyo.com/hc/en-us/articles/360004785571-Catalog-lookup-tag-reference</a></p>
75
<p>For example:</p>
75
<p>For example:</p>
76
-
<p>To add an image, drag the image block, and click on <strong>‘Dynamic URL’</strong> and add</p>
76
+
<p>To add an image, drag the image block, and click on<strong>‘Dynamic URL’</strong>and add</p>
77
{{ catalog_item.featured_image.thumbnail.src }}<p>To add text, drag a text field and add content such as the product title, description and price:</p>
77
{{ catalog_item.featured_image.thumbnail.src }}<p>To add text, drag a text field and add content such as the product title, description and price:</p>
78
{{ catalog_item.title }} {{ catalog_item.description }} {% currency_format catalog_item.metadata|lookup:"$price" %}<h4>Bonus: Sale price strike through</h4>
78
{{ catalog_item.title }} {{ catalog_item.description }} {% currency_format catalog_item.metadata|lookup:"$price" %}<h4>Bonus: Sale price strike through</h4>
79
<p>The below script is an example of how you can show a sale price with a strikethrough the old one.</p>
79
<p>The below script is an example of how you can show a sale price with a strikethrough the old one.</p>
80
{% if catalog_item.metadata|lookup:"compare_at_price" != None %} <s>{% currency_format catalog_item.metadata|lookup:"compare_at_price" %}</s> {% currency_format catalog_item.metadata|lookup:"$price" %}{% else %} {% currency_format catalog_item.metadata|lookup:"$price" %} {% endif %}<p>You are then able to use the editor to style these values as required.</p>
80
{% if catalog_item.metadata|lookup:"compare_at_price" != None %} <s>{% currency_format catalog_item.metadata|lookup:"compare_at_price" %}</s> {% currency_format catalog_item.metadata|lookup:"$price" %}{% else %} {% currency_format catalog_item.metadata|lookup:"$price" %} {% endif %}<p>You are then able to use the editor to style these values as required.</p>
81
<p>To add a Shop Now button, drop in the button block, and add the following as the URL:</p>
81
<p>To add a Shop Now button, drop in the button block, and add the following as the URL:</p>
82
-
{{ catalog_item.url }}<p>Once you’re happy with the column, you can now duplicate each block in this column, and drag them in the same order into the remaining columns. In each subsequent column, you will need to change the item index in the catalog lookup, for example, the first three items will be using the following:</p>
82
+
<p>Once you’re happy with the column, you can now duplicate each block in this column, and drag them in the same order into the remaining columns. In each subsequent column, you will need to change the item index in the catalog lookup, for example, the first three items will be using the following:</p>
83
{% catalog feeds.ProductFeedName.0.item_id %} {% catalog feeds.ProductFeedName.1.item_id %} {% catalog feeds.ProductFeedName.2.item_id %}<p>Once you’re happy with all the columns, you can now save as a ‘Universal Content Block’. This will allow you to drop the content block into any email within a flow or campaign.</p>
83
{% catalog feeds.ProductFeedName.0.item_id %} {% catalog feeds.ProductFeedName.1.item_id %} {% catalog feeds.ProductFeedName.2.item_id %}<p>Once you’re happy with all the columns, you can now save as a ‘Universal Content Block’. This will allow you to drop the content block into any email within a flow or campaign.</p>
84
<h2>Bonus</h2>
84
<h2>Bonus</h2>
85
<p>The previous section described how to use a custom product block with product recommendations, but what about manually curated products? This section will dive into how you can use a Google Sheet to manage your product curations, and feed this automatically into your Klaviyo product blocks, ready for any campaign or flow. This will require you to set up a Google Sheet and a Napkin.io account which will send the data from Google Sheets to Klaviyo.</p>
85
<p>The previous section described how to use a custom product block with product recommendations, but what about manually curated products? This section will dive into how you can use a Google Sheet to manage your product curations, and feed this automatically into your Klaviyo product blocks, ready for any campaign or flow. This will require you to set up a Google Sheet and a Napkin.io account which will send the data from Google Sheets to Klaviyo.</p>
86
<h3>1. Create a Recommendations Google Sheet</h3>
86
<h3>1. Create a Recommendations Google Sheet</h3>
87
<p>The first step is to create a Google Sheet where you will manage the product recommendations.</p>
87
<p>The first step is to create a Google Sheet where you will manage the product recommendations.</p>
88
<p>This is a simple single column layout, with a single header: “recommendation”.</p>
88
<p>This is a simple single column layout, with a single header: “recommendation”.</p>
89
<p>ach row after the ‘<em>recommendation</em>’ header will contain the Product ID of the product you wish to recommend. This Product ID needs to match the Product ID of the product within the Klaviyo catalog.</p>
89
<p>ach row after the ‘<em>recommendation</em>’ header will contain the Product ID of the product you wish to recommend. This Product ID needs to match the Product ID of the product within the Klaviyo catalog.</p>
90
-
<p>Make a note of the Sheet ID, which can be found in the URL of the sheet as follows, the ID in this example is <em>1bNFRWoRvQwsuhduHHiuaqvfTQw3FHck9jXeVmzng</em>:</p>
90
+
<p>Make a note of the Sheet ID, which can be found in the URL of the sheet as follows, the ID in this example is<em>1bNFRWoRvQwsuhduHHiuaqvfTQw3FHck9jXeVmzng</em>:</p>
91
<p><a>https://docs.google.com/spreadsheets/d/1bNFRWoRvQwsuhduHHiuaqvfTQw3FHck9jXeVmzng/edit</a></p>
91
<p><a>https://docs.google.com/spreadsheets/d/1bNFRWoRvQwsuhduHHiuaqvfTQw3FHck9jXeVmzng/edit</a></p>
92
<h3>2. Generate a Google Service Account</h3>
92
<h3>2. Generate a Google Service Account</h3>
93
<p>To pull the data from the Google Sheet, we need to convert it to a JSON file. Google does not offer this functionality natively, and so we will need to use Napkin.io to connect to the Google Sheet, and convert to JSON.</p>
93
<p>To pull the data from the Google Sheet, we need to convert it to a JSON file. Google does not offer this functionality natively, and so we will need to use Napkin.io to connect to the Google Sheet, and convert to JSON.</p>
94
<p>A Google Service Account is used to allow API access to your Google Sheet. After creating a service account, you will need to download the JSON file. Instructions for this can be found here:</p>
94
<p>A Google Service Account is used to allow API access to your Google Sheet. After creating a service account, you will need to download the JSON file. Instructions for this can be found here:</p>
95
<p><a>https://cloud.google.com/iam/docs/keys-create-delete#iam-service-account-keys-create-console</a></p>
95
<p><a>https://cloud.google.com/iam/docs/keys-create-delete#iam-service-account-keys-create-console</a></p>
96
-
<p>Rename the file: <strong>service_account.json</strong></p>
96
+
<p>Rename the file:<strong>service_account.json</strong></p>
97
<p>Once you have created the key, you will be provided a Service Account email address, for example:</p>
97
<p>Once you have created the key, you will be provided a Service Account email address, for example:</p>
98
<p><a>klaviyo-napkin@molten-topic-368815.iam.gserviceaccount.com</a></p>
98
<p><a>klaviyo-napkin@molten-topic-368815.iam.gserviceaccount.com</a></p>
99
<p>You can also find this within the JSON file:</p>
99
<p>You can also find this within the JSON file:</p>
100
"client_email": "klaviyo-napkin@molten-topic-368815.iam.gserviceaccount.com"<p>Finally, you will need to share your Google Sheet with this email address so that it can access its content.</p>
100
"client_email": "klaviyo-napkin@molten-topic-368815.iam.gserviceaccount.com"<p>Finally, you will need to share your Google Sheet with this email address so that it can access its content.</p>
101
<h3>3. Setup Napkin.io to create a JSON feed</h3>
101
<h3>3. Setup Napkin.io to create a JSON feed</h3>
102
<p>Napkin will now read from this Google Sheet and provide a JSON feed that Klaviyo can read from.</p>
102
<p>Napkin will now read from this Google Sheet and provide a JSON feed that Klaviyo can read from.</p>
103
-
<p>Firstly, create a <a>napkin.io</a> account.</p>
103
+
<p>Firstly, create a<a>napkin.io</a>account.</p>
104
<p>Next, create a new Napkin function. In this example, we will choose ‘<strong>Blank Javascript Function’</strong>.</p>
104
<p>Next, create a new Napkin function. In this example, we will choose ‘<strong>Blank Javascript Function’</strong>.</p>
105
<p>Copy the following script into your blank Napkin:</p>
105
<p>Copy the following script into your blank Napkin:</p>
106
/** * @param {NapkinRequest} req * @param {NapkinResponse} res */ import { GoogleSpreadsheet } from 'google-spreadsheet' import fs from 'fs' const getGoogleData = async(sheetId) => { //Use Google Service Account to create API connections to Google Sheet const credsFilePath = '/opt/files/service_account.json' const creds = await fs.promises.readFile(credsFilePath, 'utf8') const doc = new GoogleSpreadsheet(sheetId); await doc.useServiceAccountAuth(JSON.parse(creds)); await doc.loadInfo(); const sheet = doc.sheetsByIndex[0] const rows = await sheet.getRows() const headerValues = sheet.headerValues; let json = [] for (const row of rows) { let val = {} for (const key of headerValues) { val[key]=row[key] } json.push(val) } return json } //App export default async (req, res) => { const { sheet_id } = req.params const rows = await getGoogleData(sheet_id) res.set({ 'content-type': 'application/json; charset=utf-8' }); res.json(rows) }<p>Upload your JSON key to Napkin by clicking on the ‘<strong><em>Other</em></strong>’ tab at the top of your screen, and adding the file to the ‘<strong>Files</strong>’ section.</p>
106
/** * @param {NapkinRequest} req * @param {NapkinResponse} res */ import { GoogleSpreadsheet } from 'google-spreadsheet' import fs from 'fs' const getGoogleData = async(sheetId) => { //Use Google Service Account to create API connections to Google Sheet const credsFilePath = '/opt/files/service_account.json' const creds = await fs.promises.readFile(credsFilePath, 'utf8') const doc = new GoogleSpreadsheet(sheetId); await doc.useServiceAccountAuth(JSON.parse(creds)); await doc.loadInfo(); const sheet = doc.sheetsByIndex[0] const rows = await sheet.getRows() const headerValues = sheet.headerValues; let json = [] for (const row of rows) { let val = {} for (const key of headerValues) { val[key]=row[key] } json.push(val) } return json } //App export default async (req, res) => { const { sheet_id } = req.params const rows = await getGoogleData(sheet_id) res.set({ 'content-type': 'application/json; charset=utf-8' }); res.json(rows) }<p>Upload your JSON key to Napkin by clicking on the ‘<strong><em>Other</em></strong>’ tab at the top of your screen, and adding the file to the ‘<strong>Files</strong>’ section.</p>
107
<p>Add the ‘<strong>google-spreadsheet</strong>’ module by clicking on ‘<strong>Modules</strong>’ in the top menu, and searching the NPM modules for ‘<strong>google-spreadsheet</strong>’ and clicking the download arrow.</p>
107
<p>Add the ‘<strong>google-spreadsheet</strong>’ module by clicking on ‘<strong>Modules</strong>’ in the top menu, and searching the NPM modules for ‘<strong>google-spreadsheet</strong>’ and clicking the download arrow.</p>
108
-
<p>Now we need to add a path parameter to your Napkin function. You can do this by clicking on the pencil next to your Napkin URL, and add <strong>{sheet_id}</strong>. It should then look like this:</p>
108
+
<p>Now we need to add a path parameter to your Napkin function. You can do this by clicking on the pencil next to your Napkin URL, and add<strong>{sheet_id}</strong>. It should then look like this:</p>
109
-
<p>Finally, you can now deploy this Napkin function by hitting the <strong>‘Deploy’</strong> button. Make a note of your Napkin function URL.</p>
109
+
<p>Finally, you can now deploy this Napkin function by hitting the<strong>‘Deploy’</strong>button. Make a note of your Napkin function URL.</p>
110
<h3>4. Setup the feed in Klaviyo</h3>
110
<h3>4. Setup the feed in Klaviyo</h3>
111
-
<p>A custom web feed allows you to dynamically populate a feed of data from an external URL within a Klaviyo email. Before sending an email, Klaviyo makes an HTTP request to the URL and fetches the data. The content of the web feed is then available for use in your email. Full details on web feeds can be found here: <a>How to add a custom web feed in an email</a>.</p>
111
+
<p>A custom web feed allows you to dynamically populate a feed of data from an external URL within a Klaviyo email. Before sending an email, Klaviyo makes an HTTP request to the URL and fetches the data. The content of the web feed is then available for use in your email. Full details on web feeds can be found here:<a>How to add a custom web feed in an email</a>.</p>
112
-
<p>Visit <a>https://www.klaviyo.com/account#data-feeds-tab</a></p>
112
+
<p>Visit<a>https://www.klaviyo.com/account#data-feeds-tab</a></p>
113
-
<p>Click on <strong>‘Add Web Feed’</strong></p>
113
+
<p>Click on<strong>‘Add Web Feed’</strong></p>
114
<p>Provide a name for the feed, for example, ‘recommendations’.</p>
114
<p>Provide a name for the feed, for example, ‘recommendations’.</p>
115
<p>Add the Napkin URL followed by the Sheet ID, for example:<a>https://account.npkn.net/function_name/1bNFRWoRvQwsuhduHHiuaqvfTQw3FHck9jXeVmzng</a></p>
115
<p>Add the Napkin URL followed by the Sheet ID, for example:<a>https://account.npkn.net/function_name/1bNFRWoRvQwsuhduHHiuaqvfTQw3FHck9jXeVmzng</a></p>
116
<p>All other fields can be left</p>
116
<p>All other fields can be left</p>
117
<p>Save the feed by clicking ‘<strong>Add Data Feed</strong>’.</p>
117
<p>Save the feed by clicking ‘<strong>Add Data Feed</strong>’.</p>
118
<h3>5. Create the product block</h3>
118
<h3>5. Create the product block</h3>
119
<p>Similar to section 2 above, you can now utilise this feed to push data into your custom product block.</p>
119
<p>Similar to section 2 above, you can now utilise this feed to push data into your custom product block.</p>
120
<p>This section will perform a catalog lookup on the ID from the Google Sheet, and then provide you with the content to display to your requirements.</p>
120
<p>This section will perform a catalog lookup on the ID from the Google Sheet, and then provide you with the content to display to your requirements.</p>
121
<p>Drag in a section block</p>
121
<p>Drag in a section block</p>
122
<p>Now, instead of using the product feed as a source, you can replace this with the Web Feed defined in step 4 above, for example: ‘<strong>feeds.recommendations|slice:3</strong>’.</p>
122
<p>Now, instead of using the product feed as a source, you can replace this with the Web Feed defined in step 4 above, for example: ‘<strong>feeds.recommendations|slice:3</strong>’.</p>
123
<p>Continue to build out your block as required.</p>
123
<p>Continue to build out your block as required.</p>
124
<h2>Conclusion - Extend it!</h2>
124
<h2>Conclusion - Extend it!</h2>
125
<p>Now you have the basics, you can extend this custom block. Some examples:</p>
125
<p>Now you have the basics, you can extend this custom block. Some examples:</p>
126
<ol><li>Add multiple feeds in Klaviyo by changing the SheetID in each new feed. This can provide you with different recommendation feeds per region, product type, section etc.</li>
126
<ol><li>Add multiple feeds in Klaviyo by changing the SheetID in each new feed. This can provide you with different recommendation feeds per region, product type, section etc.</li>
127
<li>Add additional product data from the product metadata object, for example sale prices, alternative currencies, etc.</li>
127
<li>Add additional product data from the product metadata object, for example sale prices, alternative currencies, etc.</li>
128
<li>Get creative and build a full custom product catalog with multiple translations and prices for different regions.</li>
128
<li>Get creative and build a full custom product catalog with multiple translations and prices for different regions.</li>
129
</ol>
129
</ol>