Integrate a platform without a pre-built Klaviyo integration
Learn how to integrate a platform without a pre-built Klaviyo integration.
If you’re using an ecommerce platform not currently supported by one of Klaviyo’s pre-built integrations or partner integrations, or you’ve built your own custom cart solution, you can integrate with Klaviyo using our JavaScript API, server-side API, and custom catalog integration.
Key integration components
The key components of integrating this type of ecommerce solution are:
- Customer data
Tracking information such as name, email, phone number, or other profile attributes - Subscribers
Tracking who is subscribed to your newsletter, for example - Website activity
Tracking who is active on your site, what products they view, etc. - Order activity
Tracking when a customer places an order, what products are ordered, etc. - Products
The items in your catalog
About JavaScript and server-side track and identify APIs
This guide focuses on how to sync important metrics, or key customer activities, to Klaviyo. While our JavaScript and server-side Track and Identify APIs can be used interchangeably, we recommend using the setup outlined in the following checklist for the reasons outlined in our Getting started with Track and Identify APIs.
Use our JavaScript Track API for the following:
- Active on Site
When someone visits your website - Viewed Product
When someone views a product - Added to Cart
When someone adds an item to their cart - Started Checkout
When someone lands on the checkout page
Use our server-side Track API for the following:
- Placed Order
When an order successfully processes on your system - Ordered Product
An event for each item in a processed order - Fulfilled Order
When an order is sent to the customer - Cancelled Order
When an order is cancelled - Refunded Order
When a customer’s order is refunded
Use our custom catalog feed integration for the following:
- Catalog Feed
An XML or JSON feed of your product catalog
The level of detail in the data you send to Klaviyo within these website, purchase, and checkout events will determine how you can filter and segment based on these events in Klaviyo. To understand how data must be structured so that key event details are available for segmentation, check out our articles on segment conditions and how to structure your data for segment and flow filters.
Note that the code snippets in this guide use example data. You will need to update the values of the JSON properties in these snippets so that they dynamically pull from the relevant information needed for that property.
Check out our Custom integration FAQ for any questions about custom integrations.
JavaScript Track API for onsite metrics
Active on Site tracking snippet
To be able to publish forms directly from Klaviyo to your site, add the following JavaScript snippet so it appears on every page on your website (the end of the footer is often a good place to add it). Make sure to replace PUBLIC_API_KEY
with your Klaviyo account's six character public API key:
<script type="text/javascript" async="" src="https://static.klaviyo.com/onsite/js/klaviyo.js?company_id=PUBLIC_API_KEY"></script>
Once you’ve added the snippet above, an Active on Site metric will trigger for any person who is cookied. A browser can be cookied in any of the ways listed in our article on Klaviyo onsite tracking.
Viewed Product tracking snippet
If you'd like to set up a browse abandonment flow or build segments based on product browsing activity, you'll need to add JavaScript event tracking for the Viewed Product metric. All Viewed Product metrics are tied to user profiles. On your product page template, add the following snippet:
<script type="text/javascript">
var _learnq = _learnq || [];
var item = {
"ProductName": "Winnie the Pooh",
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"Categories": ["Fiction", "Children"],
"ImageURL": "http://www.example.com/path/to/product/image.png",
"URL": "http://www.example.com/path/to/product",
"Brand": "Kids Books",
"Price": 9.99,
"CompareAtPrice": 14.99
};
_learnq.push(["track", "Viewed Product", item]);
</script>
Make sure to update the values of the JSON properties in the snippet so that they dynamically pull from the relevant information needed for that property.
Additionally, there is another snippet that allows entries to be added to a “Recently Viewed Items” list for a profile. The following snippet can be added directly below the Viewed Product snippet. For more information on how to use the “Recently Viewed Items” feature in a template, check out our article on inserting recently viewed items into an email.
<script type="text/javascript">
_learnq.push(["trackViewedItem", {
"Title": item.ProductName,
"ItemId": item.ProductID,
"Categories": item.Categories,
"ImageUrl": item.ImageURL,
"Url": item.URL,
"Metadata": {
"Brand": item.Brand,
"Price": item.Price,
"CompareAtPrice": item.CompareAtPrice
}
}]);
</script>
Added to Cart tracking snippet
If you’d like to send abandoned cart emails to visitors who add items to their cart, but don’t make it to the checkout page, you’ll need to track an Added to Cart metric. A customer must be identified, (i.e., cookied), to track this event. For the payload, you should include all of the cart information (like Started Checkout below) and information about the item that was just added (like Viewed Product above).
Here's an example Track request where the cart already contained one item (Winnie the Pooh) and another item was just added to the cart (A Tale of Two Cities):
<script type="text/javascript">
_learnq.push(["track", "Added to Cart", {
"$value": 29.98,
"AddedItemProductName": "A Tale of Two Cities",
"AddedItemProductID": "1112",
"AddedItemSKU": "TALEOFTWO",
"AddedItemCategories": ["Fiction", "Classics"],
"AddedItemImageURL": "http://www.example.com/path/to/product/image2.png",
"AddedItemURL": "http://www.example.com/path/to/product2",
"AddedItemPrice": 19.99,
"AddedItemQuantity": 1,
"ItemNames": ["Winnie the Pooh", "A Tale of Two Cities"],
"CheckoutURL": "http://www.example.com/path/to/checkout",
"Items": [{
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"ProductName": "Winnie the Pooh",
"Quantity": 1,
"ItemPrice": 9.99,
"RowTotal": 9.99,
"ProductURL": "http://www.example.com/path/to/product",
"ImageURL": "http://www.example.com/path/to/product/image.png",
"ProductCategories": ["Fiction", "Children"]
},
{
"ProductID": "1112",
"SKU": "TALEOFTWO",
"ProductName": "A Tale of Two Cities",
"Quantity": 1,
"ItemPrice": 19.99,
"RowTotal": 19.99,
"ProductURL": "http://www.example.com/path/to/product2",
"ImageURL": "http://www.example.com/path/to/product/image2.png",
"ProductCategories": ["Fiction", "Classics"]
}
]
}]);
</script>
Started Checkout
Checkout data is important if you'd like to send abandoned cart emails once a person makes it to the checkout page. Abandoned cart emails based on Started Checkout, as opposed to Added to Cart, will target shoppers who are potentially more serious about completing their purchase. When someone starts the checkout process, you'll send Klaviyo a metric indicating they’ve started checking out. The best place to trigger this event is either:
- When someone visits the checkout page after they’ve been identified
- When they enter their email address on the checkout page if they have not already been identified
Include all line items details so your abandoned checkout emails can be customized to include pictures, links, and other information about the products in someone's cart. Here's an example Track request:
<script type="text/javascript">
_learnq.push(["track", "Started Checkout", {
"$event_id": "1000123_1387299423",
"$value": 29.98,
"ItemNames": ["Winnie the Pooh", "A Tale of Two Cities"],
"CheckoutURL": "http://www.example.com/path/to/checkout",
"Categories": ["Fiction", "Children", "Classics"],
"Items": [{
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"ProductName": "Winnie the Pooh",
"Quantity": 1,
"ItemPrice": 9.99,
"RowTotal": 9.99,
"ProductURL": "http://www.example.com/path/to/product",
"ImageURL": "http://www.example.com/path/to/product/image.png",
"ProductCategories": ["Fiction", "Children"]
},
{
"ProductID": "1112",
"SKU": "TALEOFTWO",
"ProductName": "A Tale of Two Cities",
"Quantity": 1,
"ItemPrice": 19.99,
"RowTotal": 19.99,
"ProductURL": "http://www.example.com/path/to/product2",
"ImageURL": "http://www.example.com/path/to/product/image2.png",
"ProductCategories": ["Fiction", "Classics"]
}
]
}]);
</script>
The $event_id
should be a unique identifier for the cart combined with the UNIX formatted time when the event was triggered. This allows someone to trigger Started Checkout more than once when they return after adding additional items.
Server-side metrics
We recommend tracking certain metrics on the server-side due to potential limitations of frontend code, security concerns, and general availability of data on the server-side versus the front-end. For example, if someone has a slow connection or a JavaScript-blocking plugin on their browser, the JavaScript requests might not fire. In the case of more crucial metrics (e.g., transactional events and properties) or ones that may contain sensitive data, use our server-side Track API. For more information on this question, check out our custom integration FAQ on the topic.
Klaviyo has libraries in several server-side languages. Generally, the API requires making an HTTP GET request with a base64 encoded JSON payload. More information can be found in our Track and Identify API reference.
Syncing historical data
Along with your ongoing data, it is best practice to send your historical order data, which will enhance your ability to segment off past data and improve historical accuracy in revenue tracking and predictive analytics. Historical data can be sent to Klaviyo by iterating through your historical orders and generating Track API requests for each server-side event as needed. The special “time” property for these events should be the UNIX timestamp of when that order occurred.
Placed Order
After an order is placed, make a Track request to our server-side API. It is best practice to send your historical order data as well, which will enhance your ability to segment off past data and improve historical accuracy in revenue tracking and predictive analytics. Historical data can be sent to us by iterating through your historical orders and generating Placed Order and Ordered Product Track API requests for each event. The special time
property for these events should be the UNIX timestamp of when that order occurred.
For ongoing data, send order data to Klaviyo in one of two ways: real-time or batch.
- Real-time
Make requests as soon as an order is placed - Batch
Write some code that will run (for example) at least every 30 minutes (e.g., on a cron) to send all order events that occurred in that past 30 minutes
If you plan to send abandoned cart messages, you'll need to send order data at a frequency that falls within your flow time delay (at least) in order to stop the flow email from going to people who have completed their order. For example, if you have a one hour time delay between when someone triggers the abandoned cart flow and when they receive the first email, make sure that you send data over at least once every hour to fall within that window and filter them out of the flow before the email sends.
For each order, we recommend you send two types of events:
- One event named Placed Order for the entire order
- This includes a $value property that represents the total value of an entire order.
- One event for each line item named Ordered Product (see below)
- This includes a $value property that represents the total cost of an item in the order before any adjustments as well as more SKU-level detailed information about the item.
Key things to be aware of when tracking server-side events:
- Make sure to replace
PUBLIC_API_KEY
with your public API key. - The
$event_id
should be a unique identifier for the order (e.g., Order ID). - If the same combination of
event
and$event_id
are sent more than once, we will skip all tracked events after the first with the same combination. $value
is a special property that allows Klaviyo to track revenue; this should be the total numeric (not a string), monetary value of the event it’s associated with.- The "Items" array should contain one JSON block/dictionary for each line item.
time
is a special property that should be a UNIX timestamp of the order date and time.
Here’s an example Track request payload for Placed Order:
{
"token": "PUBLIC_API_KEY",
"event": "Placed Order",
"customer_properties": {
"$email": "[email protected]",
"$first_name": "John",
"$last_name": "Smith",
"$phone_number": "5551234567",
"$address1": "123 Abc st",
"$address2": "Suite 1",
"$city": "Boston",
"$zip": "02110",
"$region": "MA",
"$country": "USA"
},
"properties": {
"$event_id": "1234",
"$value": 29.98,
"OrderId": "1234",
"Categories": ["Fiction", "Classics", "Children"],
"ItemNames": ["Winnie the Pooh", "A Tale of Two Cities"],
"Brands": ["Kids Books", "Harcourt Classics"],
"DiscountCode": "Free Shipping",
"DiscountValue": 5,
"Items": [{
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"ProductName": "Winnie the Pooh",
"Quantity": 1,
"ItemPrice": 9.99,
"RowTotal": 9.99,
"ProductURL": "http://www.example.com/path/to/product",
"ImageURL": "http://www.example.com/path/to/product/image.png",
"Categories": ["Fiction", "Children"],
"Brand": "Kids Books"
},
{
"ProductID": "1112",
"SKU": "TALEOFTWO",
"ProductName": "A Tale of Two Cities",
"Quantity": 1,
"ItemPrice": 19.99,
"RowTotal": 19.99,
"ProductURL": "http://www.example.com/path/to/product2",
"ImageURL": "http://www.example.com/path/to/product/image2.png",
"Categories": ["Fiction", "Classics"],
"Brand": "Harcourt Classics"
}
],
"BillingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
},
"ShippingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
}
},
"time": 1387302423
}
Ordered Product
For each line item, you should also make a Track request payload to generate an Ordered Product event. This metric is useful if you plan to create any filters or triggers based on product-specific information (as opposed to an order as a whole) that isn't "top-level" for the Placed Order metric. This metric is also used in conjunction with your Catalog Feed in order to enable personalized recommendations and in the benchmarks feature to calculate average item value and average cart size:
{
"token": "PUBLIC_API_KEY",
"event": "Ordered Product",
"customer_properties": {
"$email": "[email protected]",
"$first_name": "John",
"$last_name": "Smith"
},
"properties": {
"$event_id": "1234_WINNIEPOOH",
"$value": 9.99,
"OrderId": "1234",
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"ProductName": "Winnie the Pooh",
"Quantity": 1,
"ProductURL": "http://www.example.com/path/to/product",
"ImageURL": "http://www.example.com/path/to/product/image.png",
"Categories": [
"Fiction",
"Children"
],
"ProductBrand": "Kids Books"
},
"time": 1387302423
}
Fulfilled Order, Cancelled Order, and Refunded Order
Depending on how your products are sent to the customer, and whether they are able to be cancelled or refunded, you may want to send additional metrics that reflect these actions. Each of these order-related metrics will have a similar payload to a Placed Order event.
For Cancelled Order and Refunded Order to be included in CLV calculations, they must have
$event_ids
that correspond to a previously tracked Placed Order event
Fulfilled Order example
For Fulfilled Order, the only update needed is the metric name and the time at which the fulfillment took place. You can also track additional details about the fulfillment itself (e.g., tracking number, shipping method):
{
"token": "PUBLIC_API_KEY",
"event": "Fulfilled Order",
"customer_properties": {
"$email": "[email protected]",
"$first_name": "John",
"$last_name": "Smith",
"$phone_number": "5551234567",
"$address1": "123 Abc st",
"$address2": "Suite 1",
"$city": "Boston",
"$zip": "02110",
"$region": "MA",
"$country": "USA"
},
"properties": {
"$event_id": "1234",
"$value": 29.98,
"OrderId": "1234",
"Categories": [
"Fiction",
"Classics",
"Children"
],
"ItemNames": [
"Winnie the Pooh",
"A Tale of Two Cities"
],
"Brands": [
"Kids Books",
"Harcourt Classics"
],
"Discount Code": "Free Shipping",
"Discount Value": 5,
"Items": [
{
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"ProductName": "Winnie the Pooh",
"Quantity": 1,
"ItemPrice": 9.99,
"RowTotal": 9.99,
"ProductURL": "http://www.example.com/path/to/product",
"ImageURL": "http://www.example.com/path/to/product/image.png",
"Categories": [
"Fiction",
"Children"
],
"Brand": "Kids Books"
},
{
"ProductID": "1112",
"SKU": "TALEOFTWO",
"ProductName": "A Tale of Two Cities",
"Quantity": 1,
"ItemPrice": 19.99,
"RowTotal": 19.99,
"ProductURL": "http://www.example.com/path/to/product2",
"ImageURL": "http://www.example.com/path/to/product/image2.png",
"Categories": [
"Fiction",
"Classics"
],
"Brand": "Harcourt Classics"
}
],
"BillingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
},
"ShippingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
}
},
"time": 1387312956
}
Cancelled Order example
For Cancelled Order, update the metric name and timestamp, and add an additional property for the cancellation reason. You can also include which items were and weren’t cancelled in the event payload, in case the order is only partially cancelled.
{
"token": "PUBLIC_API_KEY",
"event": "Cancelled Order",
"customer_properties": {
"$email": "[email protected]",
"$first_name": "John",
"$last_name": "Smith",
"$phone_number": "5551234567",
"$address1": "123 Abc st",
"$address2": "Suite 1",
"$city": "Boston",
"$zip": "02110",
"$region": "MA",
"$country": "USA"
},
"properties": {
"$event_id": "1234",
"$value": 29.98,
"OrderId": "1234",
"Reason": "No longer needed",
"Categories": [
"Fiction",
"Classics",
"Children"
],
"ItemNames": [
"Winnie the Pooh",
"A Tale of Two Cities"
],
"Brands": [
"Kids Books",
"Harcourt Classics"
],
"Discount Code": "Free Shipping",
"Discount Value": 5,
"Items": [
{
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"ProductName": "Winnie the Pooh",
"Quantity": 1,
"ItemPrice": 9.99,
"RowTotal": 9.99,
"ProductURL": "http://www.example.com/path/to/product",
"ImageURL": "http://www.example.com/path/to/product/image.png",
"Categories": [
"Fiction",
"Children"
],
"Brand": "Kids Books"
},
{
"ProductID": "1112",
"SKU": "TALEOFTWO",
"ProductName": "A Tale of Two Cities",
"Quantity": 1,
"ItemPrice": 19.99,
"RowTotal": 19.99,
"ProductURL": "http://www.example.com/path/to/product2",
"ImageURL": "http://www.example.com/path/to/product/image2.png",
"Categories": [
"Fiction",
"Classics"
],
"Brand": "Harcourt Classics"
}
],
"BillingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
},
"ShippingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
}
},
"time": 1387312956
}
Refunded Order example
For Refunded Order, update the metric name and timestamp, and add an additional property for the refund reason. You can also include which items were and weren’t refunded in the event payload, in case the order is only partially refunded.
{
"token": "PUBLIC_API_KEY",
"event": "Refunded Order",
"customer_properties": {
"$email": "[email protected]",
"$first_name": "John",
"$last_name": "Smith",
"$phone_number": "5551234567",
"$address1": "123 Abc st",
"$address2": "Suite 1",
"$city": "Boston",
"$zip": "02110",
"$region": "MA",
"$country": "USA"
},
"properties": {
"$event_id": "1234",
"$value": 29.98,
"OrderId": "1234",
"Reason": "No longer needed",
"Categories": [
"Fiction",
"Classics",
"Children"
],
"ItemNames": [
"Winnie the Pooh",
"A Tale of Two Cities"
],
"Brands": [
"Kids Books",
"Harcourt Classics"
],
"Discount Code": "Free Shipping",
"Discount Value": 5,
"Items": [
{
"ProductID": "1111",
"SKU": "WINNIEPOOH",
"ProductName": "Winnie the Pooh",
"Quantity": 1,
"ItemPrice": 9.99,
"RowTotal": 9.99,
"ProductURL": "http://www.example.com/path/to/product",
"ImageURL": "http://www.example.com/path/to/product/image.png",
"Categories": [
"Fiction",
"Children"
],
"Brand": "Kids Books"
},
{
"ProductID": "1112",
"SKU": "TALEOFTWO",
"ProductName": "A Tale of Two Cities",
"Quantity": 1,
"ItemPrice": 19.99,
"RowTotal": 19.99,
"ProductURL": "http://www.example.com/path/to/product2",
"ImageURL": "http://www.example.com/path/to/product/image2.png",
"Categories": [
"Fiction",
"Classics"
],
"Brand": "Harcourt Classics"
}
],
"BillingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
},
"ShippingAddress": {
"FirstName": "John",
"LastName": "Smith",
"Company": "",
"Address1": "123 abc street",
"Address2": "apt 1",
"City": "Boston",
"Region": "Massachusetts",
"RegionCode": "MA",
"Country": "United States",
"CountryCode": "US",
"Zip": "02110",
"Phone": "5551234567"
}
},
"time": 1387312956
}
Catalog feed integration
Integrating your catalog will allow you to utilize product blocks in emails. In order to set up a custom catalog integration, please follow the process outlined in Sync a custom catalog feed to Klaviyo.
Additional resources
Updated about 2 years ago