Integrate an onsite personalization platform
Learn how to integrate an onsite personalization or product recommendation platform with Klaviyo.
Overview
This resource will help you as you build an integration between an onsite personalization or product recommendation platform and Klaviyo. This category is genuinely bidirectional: you pull Klaviyo segments and profile data to decide what a known shopper sees onsite, and you push recommendation-engagement events back so that behavior powers the merchant's flows and segments. This guide covers both halves, how onsite tracking works for mostly-anonymous visitors, the profile properties to sync, and the authentication and certification requirements, with an API quick reference at the end.
Why connect your onsite personalization platform to Klaviyo
Personalization works best when the storefront and the messaging know the same things about a shopper. If your recommendation engine knows a customer is a VIP but the merchant's email doesn't, or the merchant's email knows they're a lapsed customer but your homepage doesn't, both experiences are weaker. Wiring the two together closes that gap. When the platform is Klaviyo, you get measurable wins:
- Personalize the storefront by the merchant's own segments. A Klaviyo VIP segment sees an early-access grid; a lapsed segment sees a win-back angle. The merchant defines the audience once, in Klaviyo, and your platform acts on it.
- Feed recommendation behavior into flows. "Clicked a recommendation but didn't buy" becomes a flow trigger, the same way browse abandonment does.
- Enrich email with onsite affinity. Last recommended category and affinity segment become profile properties that power dynamic content in campaigns and flows.
- Attribute revenue to recommendations. Add-to-cart and purchase events tagged with the widget and algorithm let the merchant report what personalization actually drove.
- Stickier merchants. A two-way personalization integration is one of the strongest retention signals across the partner program, because it makes both the storefront and the messaging measurably better.
Short version: Klaviyo audiences shape what a shopper sees onsite, and onsite recommendation behavior flows back onto the Klaviyo profile. Both directions are core.
The flow
Bidirectional, and both halves matter equally:
- Pull: Klaviyo → your platform. Read Klaviyo segment and list membership, and profile properties, to decide what a known shopper sees onsite.
- Push: your platform → Klaviyo. Send recommendation-engagement events back, so that behavior drives flows, segments, and email personalization.
Each profile is keyed by email first, then phone, then external_id, the standard Klaviyo matching priority. But like search, most onsite behavior starts anonymous, before any identity exists, so how you identify visitors and how events reach the profile matter (see Onsite tracking below). Most personalization partners identify visitors with their own anonymous ID and only resolve a Klaviyo identity (email or phone) once the shopper is known through the merchant's login, form, or checkout.
On initial install, mirror the merchant's chosen Klaviyo audiences for the pull direction (see below). No historical backfill of past onsite behavior is needed; start writing engagement events from the first session after install.
Pull: personalize with Klaviyo segments and profiles
There are two patterns, and most integrations need both.
Real-time, single-visitor check (client-side)
Klaviyo's onsite JavaScript exposes a group-membership check built for exactly this: given a set of list or segment IDs, it returns the subset the currently identified visitor belongs to. Use it to make a render-time decision ("if in the VIP segment, show this widget") with no backend round-trip. It only works for known browsers (a visitor identified via an email link, form, or login), and it requires Klaviyo's onsite JS on the page. See the Klaviyo JavaScript API for the current method and plan requirements.
Bulk snapshot and diff (server-side)
When your rules engine needs the whole audience locally (for example, "recommend differently to anyone in this segment," computed offline), sync membership server-side. There is no webhook for list or segment membership changes today, so maintain a local snapshot and compute the delta yourself, exactly the pattern in the ad platform guide:
- Populate a picker of syncable audiences with Get Segments and Get Lists.
- Pull current membership with Get Profiles for Segment (
GET /api/segments/{id}/profiles), or read individual properties with Get Profiles. - Persist a snapshot keyed by segment or list ID.
- Run a daily (or hourly) diff: add profiles new to the segment, remove profiles that left, and apply the result to your local audience.
- Replace yesterday's snapshot with today's.
Use the real-time check for a single visitor at render time; use the snapshot pattern when you need the whole audience for offline rule computation. Scopes for the pull direction: segments:read, lists:read, profiles:read.
Push: recommendation and engagement events
As shoppers interact with your personalization surfaces, write events back onto the profile. Event names are not prefixed with your platform name; branded events handle source attribution via your OAuth token. Use Title Case payload field names. Most of these fire client-side and anonymous, since recommendation engagement happens before identification.
| Event | When it fires | Payload |
|---|---|---|
| Viewed Product | A shopper views a product detail page. | Product ID, Product Name, Category, Price |
| Recommendation Shown | A recommendation widget renders with results. | Widget ID, Placement, Recommendation Type, Product IDs, Algorithm |
| Recommendation Clicked | A shopper clicks a recommended product. | Widget ID, Placement, Product ID, Recommendation Type, Position |
| Added Recommended Product To Cart | A shopper adds a recommended product to cart. | Product ID, Widget ID, Recommendation Type, $value |
| Viewed Personalized Content | A dynamic content block or banner renders for the visitor. | Content ID, Content Type, Audience Match |
| Engaged With Widget | An interaction with a personalization surface that isn't a product click. | Widget ID, Interaction Type |
| Purchased Recommended Product | An order is confirmed containing a recommended product. | Product ID, Order ID, Widget ID, Recommendation Type, $value |
$value guidance: engagement events (Viewed Product, Recommendation Shown, Recommendation Clicked, Viewed Personalized Content, Engaged With Widget) carry no $value. The exceptions are Added Recommended Product To Cart and Purchased Recommended Product, which should carry $value set to the product or order value in the merchant's store currency, so merchants can report the share of revenue attributable to recommendations. Always pair a $value event with a Recommendation Type and Widget ID so revenue attributes back to the specific algorithm or placement, not just "a recommendation happened."
How merchants use it
- Personalize the storefront by segment. A homepage banner or early-access grid shown only to visitors in a Klaviyo VIP segment, via the real-time membership check.
- Recommendation-clicked-but-didn't-buy. A flow triggers off Recommendation Clicked with no subsequent Placed Order, re-offering the exact clicked product.
- Segment-driven merchandising strategy. A lapsed-90-day segment gets a win-back recommendation strategy onsite, different from net-new visitors.
- Affinity data in email. {Platform} Last Viewed Product and Affinity Segment power dynamic content blocks in campaigns and flows.
- Engagement-based segmentation. "Engaged With Widget 3+ times, never purchased" becomes a targeted discount flow.
Onsite tracking: client-side vs server-side
Like search, most personalization signal starts anonymous, so the client-side path is the default.
Client-side (default). Track engagement events with Klaviyo's onsite JavaScript (klaviyo.track("Event Name", {...})) or Create Client Event (POST /client/events/), authenticated with the merchant's public API key. Klaviyo resolves identity from the __kla_id cookie and backfills anonymous activity onto the profile once the visitor identifies. Send events even for anonymous visitors so history rolls up correctly later. To identify a visitor client-side when you capture an email, use Create Client Profile (POST /client/profiles/).
Server-side (Create Event, OAuth token). Use POST /api/events/ for events you can attribute to a known order or profile, such as Purchased Recommended Product tied to a checkout webhook. You supply the identifier; there's no automatic cookie resolution on this path.
Rule of thumb: anonymous, in-browser engagement goes client-side; anything your server can already attribute to a known order or profile goes server-side.
Profile properties to sync (optional)
Optional, written inline on any event. Use Title Case property names prefixed with your platform's name. Replace {Platform} below with the literal name of your platform (e.g., "Acme Affinity Segment"). These give the merchant a current-state view of each shopper's onsite affinity for segmentation and email personalization.
| Property | What it is |
|---|---|
| {Platform} Last Recommended Category | The most recent category surfaced to this shopper. |
| {Platform} Affinity Segment | Your platform's computed affinity, style, or persona bucket. |
| {Platform} Last Viewed Product | The most recent product viewed (ID or name). |
| {Platform} Recommendation Click Count | Running count of recommendation clicks. |
| {Platform} Preferred Price Tier | Inferred price-sensitivity band (optional). |
Implementation notes:
- Profile property writes go through Update Profile (
PATCH /api/profiles/{id}/), or are written inline on the event. Inline is the right default. - Pick property names up front and don't rename them. Renames break every segment, flow, and template that references them.
- Keep dates in ISO 8601 (UTC). Klaviyo treats string-typed dates as strings, which silently breaks date-property segmentation.
Auth, scopes, and certification
Build as a public OAuth app for server-side calls. Private API keys are a non-starter for the marketplace. Start with the Create a public OAuth app guide. Client-side tracking and identify use the merchant's public API key, as described in Onsite tracking.
Key OAuth specifics for onsite personalization integrations:
- PKCE is required on the authorization code exchange (
code_verifiermust be included). - Access tokens are short-lived (1 hour). Refresh tokens are long-lived but rotate on every use. Persist the latest refresh token after every refresh call, or you'll lose the integration on the next refresh.
- Tokens are scoped per Klaviyo account. Merchants with multiple Klaviyo accounts install separately for each.
Scopes to request:
segments:readandlists:readfor the pull direction (audience-based personalization).profiles:readto read profile properties for personalization and to resolve identity.events:writeto emit server-side engagement and purchase events. (Client-side events use the public key and need no scope.)profiles:writeonly if you write your affinity and recommendation properties back to profiles.
Don't over-scope. Unused scopes get flagged in marketplace review. Branded metric badges happen automatically when events flow through the OAuth token.
Once functional, submit for App Marketplace review under the Personalization category. Plan for at least one round of feedback. The review covers OAuth, scopes, install and uninstall validation, and that the integration delivers what your listing claims.
API quick reference
Concrete specs for AI coding assistants and engineers grounding on this doc. The narrative above is the why and the flow. This section is the what-to-actually-type.
Headers (required on every server-side request)
Authorization: Bearer <oauth_access_token>
revision: 2026-07-15
Accept: application/json
Content-Type: application/json
Pin the revision header to a specific date when you ship. Check the API versioning guide for the current latest. Without it you'll get a 400.
Pull segment membership (snapshot)
Page through members; follow the cursor until links.next is null. Diff against yesterday's snapshot.
GET /api/segments/{id}/profiles?page[size]=100
→ response.links.next contains the full next-page URL
→ loop until links.next is null
Client-side engagement event (anonymous session)
From your widget, with Klaviyo's onsite JS loaded.
klaviyo.track("Recommendation Clicked", {
"Widget ID": "home_rail_1",
"Placement": "homepage",
"Product ID": "prod_881",
"Recommendation Type": "similar_items",
"Position": 2
});
Server-side purchase event with revenue
For a recommended-product purchase your backend can attribute to a known order. Include $value and the widget context.
POST /api/events/
{
"data": {
"type": "event",
"attributes": {
"properties": {
"Product ID": "prod_881",
"Order ID": "order_98765",
"Widget ID": "home_rail_1",
"Recommendation Type": "similar_items",
"$value": 64.00
},
"time": "2026-06-17T14:22:11Z",
"unique_id": "order_98765-prod_881",
"metric": {
"data": {
"type": "metric",
"attributes": { "name": "Purchased Recommended Product" }
}
},
"profile": {
"data": {
"type": "profile",
"attributes": { "email": "[email protected]" }
}
}
}
}
}
Include time (when the event occurred, ISO 8601) and unique_id (a stable identifier for the event, such as the order ID plus the product ID) on every server-side event. Klaviyo uses unique_id to deduplicate.
Retries
- 429: respect the
Retry-Afterheader. Otherwise exponential backoff starting at 1s, cap at 60s, max 5 retries. - 5xx: same backoff.
- 4xx (other than 429): don't retry. Log and surface to the merchant.
Rate limits
Per-account, not per-app. Recommendation Shown fires on every widget render, so onsite personalization can generate very high event volume. Prefer the client-side path for anonymous engagement, batch server-side writes with Bulk Create Events (POST /api/event-bulk-create-jobs/), and consider sampling high-frequency impression events. Daily segment pulls sit well under limits. Request per-account increases through Klaviyo Support and CSM before launch if a merchant is at unusual scale.
Glossary
- Klaviyo profile: customer record. Keyed by email, phone, or external ID.
- Klaviyo metric: event type. "Recommendation Clicked," "Purchased Recommended Product," etc. Created automatically on first event ingest.
- Klaviyo segment / list: dynamic vs. static audience. The merchant mirrors these onsite to personalize what a known shopper sees.
- Onsite JavaScript: Klaviyo's in-browser library, used to track client-side events, check segment membership in real time, and resolve anonymous identity via the
__kla_idcookie. - Exchange ID: an encrypted identifier in the
__kla_idcookie that ties an anonymous browser session to a Klaviyo profile once identity resolves. - Recommendation type: the algorithm behind a widget (similar items, frequently bought together, and so on). Carried on events so revenue attributes to the right strategy.
- Public API key: the six-character site ID used to authenticate client-side calls from the browser. Safe to expose; never use a private key client-side.
Resources
- Klaviyo Developer Portal. Start here for everything.
- Create a public OAuth app
- Klaviyo JavaScript API / Create Client Event / Create Client Profile
- Get Segments / Get Profiles for Segment / Get Profiles
- Create Event / Bulk Create Events / Update Profile
- Integrate a search and merchandising platform (the sibling category for site search and discovery)
- Klaviyo App Marketplace, Personalization category. The existing set of onsite personalization integrations.
- App Marketplace Review: [email protected]
Updated about 21 hours ago