Custom Integration FAQ

Last updated at:


If you’re building a custom integration to Klaviyo using our JavaScript and server-side APIs, here are some common questions and answers to keep in mind.

How should I name my metrics?

We recommend using action words for metric names. An event of a particular metric is triggered when someone takes an action so the name should reflect the kind of action that was taken to trigger that event. Examples of events in our standard action-word-first naming scheme include Viewed Product, Started Checkout, and Placed Order.

Why do your code examples have so many curly brackets {{ }}?

Many templating languages have a markup that uses curly brackets ({{ }}) to retrieve server-side information when the page loads. The actual language/words we use as well as the curly bracket notation itself may need to be altered for your platform. The important part is that values for each property are dynamically rendered based on the information needed for that property.

My customers can create accounts. How do I cookie them?

If visitors or customers can create accounts for your website, add the following snippet such that it appears on snippet:

   var _learnq = _learnq || [];
   {% if user.is_logged_in %}
   _learnq.push(['identify', {'$email': '{{ }}'}]);
   {% endif %}

Depending on the types of templates you use for your website, the {% if user.is_logged_in %} and {{ }} syntax may be different. Using the template language available, you want to check if the person viewing the current page is logged in then, if so, output their email address.

You can also send other properties about the logged in user with this Identify request, including $first_name and $last_name if those are available through your templating language or data layer.

How do I enable personalized recommendations?

Setting up personalized recommendations based on your catalog requires three items:

  1. A Catalog Feed.
  2. A metric on which you want to base recommendations (we recommend Ordered Product but this may be different depending on your business).
  3. A top-level property on that metric which represents the ID for a given product. This must be a string or number (not an array) and must match the type and value of the product ID ($id) field for a product in your catalog.

After the above are complete, please reach out to our Support Team to enable this feature.

How should I structure my data for segmentation and flow filtering?

If you are building your own custom integration, and are deciding what data to send to Klaviyo and how to structure this data, make sure that all properties you want to segment on are sent as top-level properties and are not nested.

For example, if you create a Placed Order metric where an event will track whenever someone completes a purchase on your site, you may want to filter events based on what item(s) someone purchased.

In order to do this, there has to be a top-level ItemNames array that includes all purchased product names -- this would be in addition to a nested array with details for each item. The nested data becomes helpful when iterating over the items in the order and displaying multiple properties about each item, one at a time (eg. ProductName, ItemPrice, and Quantity). Below, you can see the ItemNames array in the payload for this Placed Order event in addition to the Items array that contains detailed information about each product:

   "token": "API_KEY",
   "event": "Placed Order",
   "customer_properties": {
     "$email": "",
     "$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,
     "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": "",
         "ImageURL": "",
         "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": "",
         "ImageURL": "",
         "Categories": ["Fiction", "Classics"],
         "Brand": "Harcourt Classics"
   "time": 1387302423

How come some values aren't appearing in my segment and flow filters?

Our filters will populate with any event property values or profile property values that have previously been sent to us. Until we receive an event or profile property with that data, it will not appear in the drop-down for filtering.

If an event property shares a name with a profile property, only the profile property will appear in the filter. Make sure to choose different names for your event properties and profile properties.

Should I use $email or $id as my unique identifier?

Before you begin building a custom integration, note that the Identify method -- which allows you to identify and set properties on an individual -- allows you to identify any individual by including either their email address, with the $email key, or a unique identifier such as their user ID, with the $id key.

We highly recommend that you consistently identify all individuals using their email address only (with the $email key), and do not pass any $id value.

If you choose to use your own unique identifier with the $id key, you take on the full responsibility of identity management within your Klaviyo account. You must ensure that all requests are made mapping the right $id value you're setting to the right $email. If you send some requests with $id only, these profiles will exist "anonymously" without any associated $email. If requests then come in for the same person, but only $email is part of the request, a permanent duplicate profile will get created. Given the complexity of ensuring $id and $email are mapped correctly with every request across all data sources, we recommend exclusively using email address to identify individuals. This will fully safeguard against duplicate profile creation.

How do I tell if my custom integration is working?

The first thing to check is whether or not Klaviyo is receiving events correctly. To do this, you can log into your Klaviyo account, click on the Analytics tab, and click into Metrics. This tab will show all the different events (or metrics) syncing into your Klaviyo account. You should see the following metrics here: Placed Order, Ordered Product, and Started Checkout. You may also see a metric for Active on Site. If you do, that means we've received at least one event for each of those metrics.

Next, for each metric, click on the Activity Feed to view a list of the most recent events we've received. If you don't see the metrics you're expecting in Klaviyo, here are a few things to consider:

  • The Placed Order and Started Checkout metrics won't show up until someone has placed an order or checked out, respectively.
  • You should create a test checkout and a test order to see data appear.
  • Check that the public API key you're making API requests with matches the API key in your account.
  • Make sure you haven't forgotten to replace the placeholder API key.
  • For JavaScript Track requests, make sure people are being identified before you make the Track request.
  • Klaviyo doesn't Track anonymous activity because you can't take action or send emails to people who haven't been identified.

How do I backfill historical data?

Has your store or website existed before your integration with Klaviyo? We have good news:

Backfilling Via our APIs

If you have historical data on your customers, you can send that to Klaviyo using our Track and Identify APIs. If you’ve already built an integration to Klaviyo for real-time data, the process here is very similar. In order to send historical information, iterate through every historical “event” you have and send a Track request for that event using the timestamp of when it occurred. If you have historical properties about people (their email preferences, birthdays, etc) you can send that using our Identify API.

Backfilling Via CSV Uploads

Each of these can be sent via CSV uploads as well, here are a few considerations.

  • A CSV upload must be less than 50 MB.
  • Event CSVs and contact CSVs are formatted differently and uploaded in separate areas of the platform (see linked guides below).
  • Each event CSV upload must contain headers for the name of the property on the event you’re uploading.
  • Event CSVs can only contain flat structures. For example, you will not be able to make a CSV that mimics the structure of our recommended Placed Order event, but you can make a CSV that mimics the structure of our recommended Ordered Product event (note: this refers to the data structure in these examples, not the events themselves). Because each row is "flat" and represents a singular event for a given metric, nested data structures are not upload-able via this method (only top-level properties are possible).

Can I use a tag manager to integrate?

Yes. Any of our Track or Identify requests can be sent via JavaScript (and thus injected via a tag manager) but there are a few things necessary to keep in mind:

  • Our requests may not have time or be able to trigger for people who have slow computers, or ad or JavaScript blockers installed on their browsers.
  • Information stored in a frontend data layer or in the JavaScript of a website may be visible to the public internet. Be careful not to send or expose any sensitive information about your browsers or customers when integrating using only Javascript.

Should I use the server-side API or front-end API?

Our Track and Identify APIs have both server-side and front-end (JavaScript) components. Both server-side and front-end requests can be used to send the same data so theoretically an entire custom integration can be built using one or the other. That said, both have their advantages and disadvantages:

Frontend Code

  • Advantages:
    • Can be implemented on any platform that supports JavaScript
    • Does not require access to the back-end code of a platform and so can be used on hosted solutions (eg. Shopify and BigCommerce)
    • Usually more straight-forward to set up
  • Disadvantages:
    • Runs on the end-users computer
    • Can be interrupted by JavaScript blockers, slow internet connections, or slow computers
    • Exposed to the public internet

Server-Side Code

  • Advantages:
    • Runs on your own server
    • Highly reliable
    • Access to information only available on the server (eg. order status) or information passed back to the server from the front-end
    • Supports more private requests
  • Disadvantages:
    • Requires access to the back-end of a platform or at least to its APIs

What is the difference between Abandoned Carts and Abandoned Checkouts?

In your Klaviyo account, you might find that we have default flows in the Flows tab or Flows Library called Abandoned Cart. One of them uses a trigger called Added to Cart, while the other uses a trigger called Started Checkout. Because the latter is triggered when someone lands on the checkout page, other platforms may refer to this as an “Abandoned Checkout” instead of an “Abandoned Cart." In Klaviyo, we call both flows Abandoned Cart and use different triggering events since both refer to a cart that was abandoned, just at different parts of the customer journey.

My payload looks valid but I'm receiving a "0" response?

Our Track and Identify APIs will respond with a "0" if the payload sent was invalid. Here are some reasons you may be getting an unexpected response or unexpected results:

  • Since the payload of the request is a URL parameter, it will also need to be URL encoded. Make sure the payload is first base64 encoded then URL encoded. Some languages group these encodings into a single function and some do not, a payload that is only base64 encoded may still be invalid as a URL parameter.
  • There may be curly or fancy quote marks used in your payload instead of regular quote marks.
    • ' and " are valid quote marks
    • , , , and may be added by some text-editing softwares, but are not valid programming quote marks and will cause the JSON to be invalid if used outside of a string.
  • A server-side payload must contain a valid email address in it's customer_properties dictionary as the $email property.
  • Make sure all non-final elements in lists and JSON end with a comma.
  • Make sure all final elements in lists and JSON objects do not end with a comma. It is technically valid in some languages, but safer to not include as a best practice as it can cause the JSON to be invalid in some languages/validators.

I received a "1" response from the Track API but my event isn't appearing in Klaviyo?

Our Track and Identify APIs will respond with a "1" if the payload sent was valid. This does not however indicate that the event itself was saved for a given profile on the account. Here are the reasons you may receive a "1" response but the event does not appear:

  • Every event tracked to your account for a given profile must have a unique combination of event name (event) and event ID ($event_id). If you track the same combination a second time to the same profile, you will receive a "1" response but the event will not be ingested.
  • domain email addresses are technically valid but we do not accept them into our event or profile processing pipeline
  • By default, an account is limited to 200 unique metrics. Note that this is overall unique "names" of types of events (like Placed Order), you can still send as many unique events (single occurrences of a metric like individual Placed Orders) as you like. If you hit this limit, you should receive an in-app and email notification that it was hit and any further net-new metric creation via the Track API will respond with a "1" but not generate that metric on the account.

How do I set up coupons?

If you are not using one of our prebuilt integrations that include coupon functionality, you can set up coupons by using  our bulk coupon upload feature.

Was this article helpful?
56 out of 107 found this helpful