n8n Klaviyo Node: Sync Profiles, Trigger Flows, and Automate E-Commerce Email Marketing [Free Workflow JSON]
Klaviyo is the email and SMS platform built for e-commerce — tight Shopify integration, revenue-attributed flows, and deep segmentation. The n8n Klaviyo node lets you create and update profiles, manage list membership, trigger events, and sync order data without leaving your automation layer. This guide covers every operation, the gotchas, and three workflow patterns ready to import.
What the Klaviyo Node Does
The n8n Klaviyo node exposes four core resources:
| Resource | Operations |
|---|---|
| Profile | Create, Delete, Get, Get All, Update |
| List | Add (subscribe), Get All, Remove (unsubscribe) |
| Event | Create (track) |
| Trigger | Send Campaign |
Authentication uses a Klaviyo Private API Key (server-side) — never a public key.
Setting Up the Credential
- Log into Klaviyo → Settings → API Keys
- Click Create Private API Key — give it a descriptive name like
n8n-operator - Scope: Full Access (or narrow to Profiles + Lists + Events for principle of least privilege)
- Copy the key — it begins with
pk_ - In n8n, add a Klaviyo API credential and paste the key
Note: Klaviyo also has public API keys (beginning
pk_pub_) used only in client-side JavaScript. Never use these in n8n — they have no write access and are not intended for server-side calls.
Core Operations
Profile Resource
Create — adds a new subscriber profile. Required fields: at minimum one identifier (email, phone_number, or external_id). Klaviyo automatically deduplicates on email address.
Update — modifies properties on an existing profile. Requires the Klaviyo profile ID (not the email). Retrieve IDs via Get All with a filter.
Get / Get All — fetch one profile by ID or list profiles with optional filter expressions (e.g., equals(email,"user@example.com")).
Delete — permanently removes a profile and all associated data. Irreversible.
List Resource
Add — subscribes one or more profiles to a list. Profiles must already exist; the node will not create them on the fly — use Profile → Create first if needed, or chain both nodes.
Remove — unsubscribes profiles from a list. Does not delete the profile.
Get All — returns all lists in the account.
Event Resource
Create — tracks a custom event for a profile. Used to trigger Klaviyo Flows. Required: event (event name), profile object (must include email or phone), and optionally properties (arbitrary JSON — e.g., order total, product ID, coupon code).
This is the most powerful operation in the node — it's how you fire Klaviyo automations from n8n.
Trigger Resource
Send Campaign — manually triggers an existing campaign to send. Primarily used for testing or scheduled batch sends outside Klaviyo's own scheduler.
Six Gotchas
1. Profile deduplication is email-based, but updates are ID-based.
Creating a profile with a duplicate email silently upserts instead of creating a duplicate. But the Update operation requires the Klaviyo-assigned profile ID, not the email. Pattern: Get the profile first to retrieve the ID, then Update it.
2. List.Add requires profiles to exist first.
Unlike Mailchimp, the Klaviyo node's List → Add operation does not create profiles — it only subscribes existing ones. If you're adding a brand-new email, run Profile → Create before List → Add (connect both nodes in sequence).
3. Klaviyo has aggressive rate limits on the v3 API.
The REST API is limited to 75 requests per second (burst) and varies by operation. For batch imports of >100 profiles, use Klaviyo's Bulk Import API (available via HTTP Request node, not the built-in node). The built-in node sends one API call per item — 1,000 profiles = 1,000 calls.
4. Event properties must be serializable JSON.
The properties field in Event → Create accepts a JSON object. If you're passing n8n expressions that evaluate to non-serializable types (undefined, circular refs), the event will silently fail or send empty properties. Always validate the expression output before wiring.
5. Phone numbers must be in E.164 format.
If you're using phone_number as the identifier or for SMS flows, the value must be E.164 (e.g., +12025551234). Raw formats like (202) 555-1234 will be rejected. Use a Code node to normalize before sending to Klaviyo.
6. Consent fields are separate from profile properties.
Email/SMS subscription consent (email_marketing.consent, sms_marketing.consent) is managed through Klaviyo's consent system, not as arbitrary profile properties. Setting subscribed: true as a custom property has no effect on marketing consent. Use the List → Add operation (which sets email_marketing consent to subscribed for that list) rather than trying to set consent via profile properties directly.
Three Workflow Patterns
Pattern 1: Shopify Order → Klaviyo "Placed Order" Event (Revenue Attribution)
Trigger: Shopify webhook on orders/paid
Goal: Track every completed purchase as a Klaviyo event so revenue-attributed flows (abandoned cart, post-purchase series) fire correctly.
Shopify Webhook Trigger
→ Klaviyo: Event → Create
profile: { email: {{ $json.email }} }
event: "Placed Order"
properties:
order_id: {{ $json.id }}
total: {{ $json.total_price }}
items: {{ $json.line_items.map(i => ({name: i.title, sku: i.sku, quantity: i.quantity})) }}
currency: {{ $json.currency }}
Why it matters: Klaviyo's revenue reporting requires events in this exact format. Once tracking, you can build flows triggered by "Placed Order", "Ordered Product", or "Refunded Order" natively inside Klaviyo without any custom code on the storefront.
Pattern 2: Typeform Lead Capture → Klaviyo Profile + List Subscription
Trigger: Typeform webhook on form submit
Goal: Create a Klaviyo profile for every new lead, tag them with lead source, and subscribe them to the welcome list.
Typeform Webhook
→ Klaviyo: Profile → Create
email: {{ $json.form_response.answers[0].email }}
first_name: {{ $json.form_response.answers[1].text }}
properties: { lead_source: "typeform", funnel: "top" }
→ Klaviyo: List → Add
list_id: <your welcome list ID>
profiles: [{ email: {{ $json.form_response.answers[0].email }} }]
Why it matters: Klaviyo profiles created via API are not automatically subscribed to any list — you need both steps. Skipping List → Add means the profile exists but never enters any flows.
Pattern 3: Churn Prevention — Stripe Subscription Cancelled → Klaviyo Win-Back Event
Trigger: Stripe webhook on customer.subscription.deleted
Goal: Fire a Klaviyo event when a subscription cancels so a win-back flow starts automatically.
Stripe Webhook Trigger
→ (filter: event.type = customer.subscription.deleted)
→ Stripe: Customer → Get (to retrieve email from customer ID)
→ Klaviyo: Event → Create
profile: { email: {{ $json.email }} }
event: "Subscription Cancelled"
properties:
plan: {{ $('Stripe Webhook').item.json.data.object.plan.nickname }}
cancelled_at: {{ $('Stripe Webhook').item.json.data.object.canceled_at }}
mrr_lost: {{ $('Stripe Webhook').item.json.data.object.plan.amount / 100 }}
Why it matters: Win-back flows are among the highest-ROI Klaviyo automations — but only work if cancellation events are tracked. Stripe doesn't push to Klaviyo natively; this webhook bridge closes the gap.
Klaviyo Node vs. HTTP Request for Klaviyo
| Use case | Klaviyo node | HTTP Request node |
|---|---|---|
| Single profile create/update | ✅ Simple | Overkill |
| Bulk import (>100 profiles) | ❌ Too slow (1 call/item) | ✅ Use Bulk Import API |
| Track custom events | ✅ Easiest | Doable |
| Advanced filtering / segmentation API | ❌ Not exposed | ✅ Required |
| Klaviyo Flow triggers | ✅ Via Event → Create | Doable |
For bulk operations or advanced API v2/v3 endpoints not exposed in the n8n node, use an HTTP Request node with Authorization: Klaviyo-API-Key <your_key> and revision: 2024-02-15 headers.
Free Workflow JSON
Import the Shopify → Klaviyo "Placed Order" event tracker directly into n8n:
{
"name": "Shopify Order → Klaviyo Placed Order Event",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "shopify-order-paid",
"responseMode": "responseNode"
},
"name": "Shopify Webhook",
"type": "n8n-nodes-base.webhook",
"position": [240, 300]
},
{
"parameters": {
"resource": "event",
"operation": "create",
"profile": {
"email": "={{ $json.email }}"
},
"eventName": "Placed Order",
"properties": "={{ JSON.stringify({ order_id: $json.id, total: $json.total_price, currency: $json.currency, items: $json.line_items.map(i => ({name: i.title, sku: i.sku, quantity: i.quantity})) }) }}"
},
"name": "Klaviyo Track Order",
"type": "n8n-nodes-base.klaviyo",
"position": [460, 300]
}
],
"connections": {
"Shopify Webhook": {
"main": [[{ "node": "Klaviyo Track Order", "type": "main", "index": 0 }]]
}
}
}
What to Read Next
- n8n Shopify Node — trigger on orders, customers, and inventory events at the source
- n8n Stripe Node — bridge payment events into Klaviyo win-back and upsell flows
- n8n Mailchimp Node — if you're on Mailchimp instead of Klaviyo, the patterns are similar
Want this workflow built and configured for your store? The n8n Workflow Starter Pack includes 10 pre-built workflows covering the most common e-commerce automation patterns — import and run in minutes.
Need a custom workflow for your Klaviyo + Shopify setup? Done-for-you n8n workflow builds start at $99.
Top comments (3)
Are you using the Klaviyo node to sync Shopify order events, build lead capture flows from Typeform, or trigger win-back campaigns from Stripe cancellations? Drop your use case in the comments — would love to see how people are bridging Klaviyo and n8n.
Are you using the n8n Klaviyo node to sync e-commerce profiles, trigger abandoned cart flows, or automate post-purchase email sequences? Drop your use case in the comments — curious what integrations people are building with it.
Are you using the n8n Klaviyo node to sync profiles, trigger flows, or manage e-commerce email marketing? Drop your use case in the comments — would love to see what automations people are building with Klaviyo and n8n.