Futureman Labs
Platform Integration

n8n + Klaviyo: Build Email Automations Klaviyo Can't Do Alone

Go beyond Klaviyo's native flows with n8n. Build advanced email automations using external triggers, cross-platform data, and smart segmentation.

David YuMarch 23, 202617 min read

Klaviyo is excellent at what it does. You connect it to Shopify, it pulls in purchase history, and you build flows triggered by placed orders, abandoned carts, and browse activity. The drag-and-drop flow builder handles 80% of ecommerce email marketing perfectly well.

But then you hit the other 20%.

You want to send a restock notification triggered by your warehouse management system -- not by Klaviyo's native back-in-stock feature, which only works for products tracked in Shopify. You want to move a customer into a VIP segment the moment their lifetime value crosses $500, calculated from data that lives in your ERP, not Shopify. You want to trigger a win-back flow when a support ticket gets resolved, because that is the moment the customer is most receptive -- but Klaviyo has no idea your helpdesk exists.

These are the automations that separate stores doing competent email marketing from stores doing genuinely sophisticated lifecycle marketing. And they all require something Klaviyo cannot do on its own: react to events from outside its ecosystem.

That is where n8n comes in. By using n8n as an orchestration layer between your external systems and Klaviyo's API, you can build email marketing automations that would be impossible with Klaviyo alone -- without writing a custom application or paying a developer $15,000 for a one-off integration.

Here is how to do it, step by step.

Why Klaviyo's Native Flows Hit a Ceiling

Before building anything, you need to understand exactly where Klaviyo's flow system stops being useful. This is not about Klaviyo being a bad product -- it is about understanding its architectural boundaries so you can extend them intelligently.

Limited Trigger Types

Klaviyo flows can be triggered by exactly five things: a list addition, a segment change, a metric (event), a price drop, or a date property. That is it. There is no "webhook received" trigger, no "API call from an external system" trigger, no "file appeared in an S3 bucket" trigger.

If you want a flow triggered by something outside of Klaviyo's world, your only option is to push a custom event into Klaviyo via the API and trigger a metric-based flow off of that event. This works -- and it is the core pattern this entire guide is built around -- but Klaviyo cannot do the pushing. Something else has to.

No Cross-Platform Logic

Klaviyo's conditional splits can only evaluate data that already exists inside Klaviyo -- profile properties, event history, list membership, and segment membership. You cannot build a conditional split that says "if this customer's open support ticket count in Zendesk is greater than zero, skip this email." Klaviyo simply does not have access to that data in real time.

To make decisions based on external data, you need to either sync that data into Klaviyo profile properties ahead of time (so Klaviyo can reference it) or handle the logic outside of Klaviyo entirely and only push the final "send this email" event.

Segment Re-Entry Restrictions

Segment-triggered flows in Klaviyo have a significant limitation: a profile can only enter a segment-triggered flow once. If a customer leaves a segment and later re-qualifies, they will not re-trigger the flow. This makes segment-triggered flows unsuitable for recurring use cases like monthly loyalty tier notifications or periodic restock reminders.

Timing Constraints on Event Ingestion

If there is a delay of more than six hours between when an event actually occurred and when Klaviyo receives it, the event will not trigger a metric-based flow. This means batch-synced data from systems that only push updates every few hours can silently fail to trigger the flows you built around them.

The Architecture: n8n as the Orchestration Layer

The pattern is straightforward. n8n sits between your external data sources and Klaviyo, doing three things:

  1. Listening for events from external systems (webhooks, scheduled polls, database queries)
  2. Transforming that data into the format Klaviyo expects
  3. Pushing events and profile updates into Klaviyo via the API, which then trigger native Klaviyo flows
┌─────────────────┐     ┌──────────┐     ┌──────────────┐
│  External System │────▶│   n8n    │────▶│   Klaviyo    │
│  (WMS, Helpdesk, │     │ Workflow │     │   API v3     │
│   ERP, CRM...)   │     │          │     │              │
└─────────────────┘     └──────────┘     └──────┬───────┘
                                                 │
                                                 ▼
                                          ┌──────────────┐
                                          │  Klaviyo Flow │
                                          │  (triggered   │
                                          │   by metric)  │
                                          └──────────────┘

This architecture keeps Klaviyo doing what it does best -- rendering emails, managing deliverability, handling unsubscribes, and tracking engagement -- while n8n handles the complex orchestration logic that Klaviyo was never designed for.

Setting Up: Klaviyo API Credentials in n8n

Before building workflows, you need to connect n8n to Klaviyo's API. Klaviyo uses a private API key for server-side operations.

Step 1: Generate a Klaviyo Private API Key

In your Klaviyo account, navigate to Settings > API Keys and create a new private API key. Give it a descriptive name like "n8n Integration" and grant it the following scopes:

  • Events: Read and Write (for pushing custom events)
  • Profiles: Read and Write (for updating profile properties)
  • Lists: Read and Write (for managing list membership)
  • Segments: Read (for checking segment membership)

Step 2: Configure the HTTP Request Node in n8n

n8n connects to Klaviyo through the HTTP Request node using generic header authentication. In n8n, create a new credential:

  1. Go to Credentials > New Credential > Header Auth
  2. Set the header name to Authorization
  3. Set the header value to Klaviyo-API-Key your-private-api-key
  4. Also add a second header: revision with value 2024-10-15 (or the latest API revision)

Every HTTP Request node in your Klaviyo workflows will use this credential.

Use Case 1: Inventory-Based Email Triggers From Your WMS

This is the most common reason stores need n8n alongside Klaviyo. Your warehouse management system knows when products are back in stock, but Klaviyo's native back-in-stock feature only monitors Shopify inventory levels. If you manage inventory in a WMS like ShipHero, ShipBob, or a custom system, Klaviyo never sees the restock event.

The n8n Workflow

Trigger: Webhook node receiving a restock event from your WMS (or a scheduled poll to your WMS API checking inventory levels).

Step 1 -- Validate the restock event:

// Function node: Filter for meaningful restocks
const items = $input.all();
const restocked = items.filter(item => {
  const previousQty = item.json.previous_quantity || 0;
  const currentQty = item.json.current_quantity || 0;
  // Only trigger if item went from 0 to 10+ units
  return previousQty === 0 && currentQty >= 10;
});
return restocked;

Step 2 -- Push a custom event to Klaviyo:

Use an HTTP Request node to POST to https://a.klaviyo.com/api/events:

{
  "data": {
    "type": "event",
    "attributes": {
      "metric": {
        "data": {
          "type": "metric",
          "attributes": {
            "name": "Back in Stock (WMS)"
          }
        }
      },
      "properties": {
        "ProductName": "{{ $json.product_name }}",
        "ProductID": "{{ $json.product_id }}",
        "SKU": "{{ $json.sku }}",
        "AvailableQuantity": {{ $json.current_quantity }},
        "ProductURL": "https://yourstore.com/products/{{ $json.handle }}",
        "ImageURL": "{{ $json.image_url }}"
      },
      "profile": {
        "data": {
          "type": "profile",
          "attributes": {
            "email": "{{ $json.customer_email }}"
          }
        }
      }
    }
  }
}

Step 3 -- In Klaviyo: Create a metric-triggered flow using the "Back in Stock (WMS)" metric. Now you have a back-in-stock flow that fires based on real warehouse data, not Shopify inventory counts.

Handling the "Who Gets Notified" Problem

The example above sends the event for a specific customer. But what if you want to notify everyone who has expressed interest in a product? You need a waitlist.

Build a second n8n workflow that captures back-in-stock signup requests (from a form on your site) and stores them in a database or Airtable. When the restock webhook fires, your n8n workflow queries the waitlist, loops through every signed-up email, and pushes a "Back in Stock (WMS)" event for each one.

Restock Webhook ──▶ Query Waitlist DB ──▶ Loop ──▶ Push Event to Klaviyo
                     (Airtable/Postgres)    │         (for each email)
                                            │
                                            └──▶ Clear Waitlist for SKU

Use Case 2: Dynamic Segmentation From External Data

Klaviyo's segments are powerful, but they can only evaluate data that lives in Klaviyo. If your loyalty program data is in a separate system, your support ticket history is in Zendesk, or your wholesale account status is in your ERP, Klaviyo has no way to segment on that information -- unless you sync it.

Syncing External Data to Klaviyo Profile Properties

Build an n8n workflow that runs on a schedule (every hour, every 6 hours, or daily depending on how fresh the data needs to be) and updates Klaviyo profile properties with external data.

Example: Syncing loyalty tier data from your CRM

Trigger: Schedule node (runs every 4 hours)

Step 1 -- Pull loyalty data: HTTP Request node to your CRM or loyalty platform API to fetch all customers with their current tier and points balance.

Step 2 -- Update Klaviyo profiles: For each customer, use an HTTP Request node to PATCH https://a.klaviyo.com/api/profiles/{profile_id}:

{
  "data": {
    "type": "profile",
    "id": "KLAVIYO_PROFILE_ID",
    "attributes": {
      "properties": {
        "Loyalty_Tier": "Gold",
        "Loyalty_Points": 2450,
        "Tier_Expiry_Date": "2026-06-30",
        "Lifetime_Value_External": 3200.00,
        "Open_Support_Tickets": 0,
        "Last_Support_Interaction": "2026-03-15"
      }
    }
  }
}

Step 3 -- Build segments in Klaviyo using these synced properties. Create segments like "Gold Tier Members," "Customers With Open Support Tickets," or "LTV Over $1000 (External)." These segments update automatically as n8n keeps the profile properties current.

The Profile ID Lookup Pattern

Klaviyo's update profile endpoint requires the Klaviyo profile ID, not just the email address. You will need a lookup step. Use a GET request to https://a.klaviyo.com/api/profiles?filter=equals(email,"customer@example.com") to retrieve the profile ID before updating.

In practice, build this as a reusable sub-workflow in n8n:

Email Address ──▶ Lookup Profile ID ──▶ If exists: Update
                                        If not: Create Profile ──▶ Update

This "upsert" pattern ensures you never fail silently when a profile does not exist yet in Klaviyo.

Use Case 3: Triggered Flows From Non-Shopify Events

This is where the n8n + Klaviyo combination becomes genuinely powerful. Here are real-world triggers that Klaviyo cannot detect natively:

Support Ticket Resolved Flow

When a customer's support ticket gets resolved in Zendesk, Freshdesk, or Intercom, they are in a uniquely receptive state. They just got helped. This is the perfect moment for a "How did we do?" email followed by a review request 3 days later.

n8n Workflow:

  1. Webhook trigger from your helpdesk (Zendesk sends webhooks on ticket status changes)
  2. Filter node to only process tickets that moved to "Resolved" status
  3. Function node to extract customer email and ticket details
  4. HTTP Request node to push a "Support Ticket Resolved" event to Klaviyo with properties like TicketSubject, ResolutionTime, and AgentName

In Klaviyo, build a flow triggered by the "Support Ticket Resolved" metric. Add a time delay of 2 hours, then send a CSAT survey email. Add another delay of 3 days, then send a review request -- but only if the profile property Open_Support_Tickets (synced by your profile enrichment workflow) equals zero.

Subscription Renewal Approaching

If you run a subscription program through Recharge, Bold, or a custom system, you can trigger a renewal reminder flow that is far more sophisticated than what these platforms offer natively.

n8n Workflow:

  1. Schedule trigger (runs daily)
  2. HTTP Request to your subscription platform API to fetch subscriptions renewing in the next 7 days
  3. Enrichment step to pull in each customer's recent order history, loyalty points, and support history
  4. Decision logic in n8n:
    • If customer has had a support issue in the last 30 days: push a "Subscription Renewal - At Risk" event
    • If customer's order frequency is declining: push a "Subscription Renewal - Winback" event
    • Otherwise: push a "Subscription Renewal - Standard" event

Each event type triggers a different Klaviyo flow with different messaging. The "At Risk" flow might include a discount code. The "Winback" flow might highlight new products. The "Standard" flow is a simple reminder. None of this segmentation logic is possible inside Klaviyo alone because it requires cross-referencing data from multiple external systems.

Warehouse Shipment Delay Alert

When your 3PL or warehouse system detects a shipment delay, you can proactively notify customers before they notice -- turning a negative experience into a trust-building moment.

// n8n Function node: Determine delay severity
const hoursDelayed = $json.estimated_delay_hours;
let eventName;

if (hoursDelayed >= 72) {
  eventName = "Shipment Delay - Major";
} else if (hoursDelayed >= 24) {
  eventName = "Shipment Delay - Moderate";
} else {
  // Minor delays: don't email, just track
  eventName = "Shipment Delay - Minor";
}

return [{
  json: {
    event_name: eventName,
    customer_email: $json.customer_email,
    order_number: $json.order_id,
    original_eta: $json.original_eta,
    new_eta: $json.revised_eta,
    delay_hours: hoursDelayed
  }
}];

Build three separate Klaviyo flows: "Major" delays get an apologetic email with a discount code. "Moderate" delays get a proactive heads-up. "Minor" delays get logged as an event on the profile but do not trigger an email -- giving you data for later analysis without over-emailing.

Use Case 4: A/B Testing Automation With n8n

Klaviyo has built-in A/B testing for campaigns, but it is limited to subject lines and send times within a single campaign. If you want to test fundamentally different email strategies -- different flows, different timing sequences, different content approaches -- you need to handle the split outside of Klaviyo.

The Pattern

  1. n8n Webhook or Schedule trigger captures the event (new customer, new purchase, etc.)
  2. Function node assigns each profile to a test group:
// Deterministic A/B split based on email hash
const crypto = require('crypto');
const email = $json.email.toLowerCase().trim();
const hash = crypto.createHash('md5').update(email).digest('hex');
const hashInt = parseInt(hash.substring(0, 8), 16);
const group = hashInt % 100; // 0-99

let testGroup;
if (group < 50) {
  testGroup = "flow_variant_a";
} else {
  testGroup = "flow_variant_b";
}

return [{
  json: {
    ...$json,
    test_group: testGroup
  }
}];
  1. HTTP Request nodes push different events to Klaviyo based on the test group. Variant A profiles get a "Welcome - Variant A" event (triggering a 3-email welcome series). Variant B profiles get a "Welcome - Variant B" event (triggering a 5-email series with different timing).

The deterministic hash approach ensures the same email always lands in the same group, which prevents contamination if the workflow runs multiple times. It also means you do not need to store group assignments anywhere -- the assignment is derived from the email itself.

Tracking Results

Push a profile property like Welcome_Test_Group: "variant_a" alongside the event. In Klaviyo, you can then build segments for each test group and compare engagement metrics (open rates, click rates, conversion rates) across groups using Klaviyo's native analytics.

Use Case 5: Automated List Hygiene Based on Engagement Decay

Klaviyo lets you build segments based on engagement, but it does not automatically take action based on engagement decay over time. With n8n, you can build a workflow that progressively manages disengaged profiles.

Schedule trigger: Runs weekly.

Step 1 -- Query Klaviyo for profiles in your "Engaged" segment:

GET https://a.klaviyo.com/api/segments/{segment_id}/profiles

Step 2 -- For each profile, check engagement history:

GET https://a.klaviyo.com/api/events?filter=equals(profile_id,"{id}"),equals(metric_id,"{opened_email_metric_id}")&sort=-datetime

Step 3 -- Apply decay logic:

const lastOpenDate = new Date($json.last_open_date);
const daysSinceOpen = (Date.now() - lastOpenDate) / (1000 * 60 * 60 * 24);

let engagementAction;
if (daysSinceOpen > 120) {
  engagementAction = "suppress"; // Remove from all sends
} else if (daysSinceOpen > 90) {
  engagementAction = "sunset_flow"; // Trigger final re-engagement
} else if (daysSinceOpen > 60) {
  engagementAction = "reduce_frequency"; // Move to monthly-only list
} else {
  engagementAction = "none";
}

return [{ json: { ...$json, engagement_action: engagementAction } }];

Step 4 -- Execute actions: Based on the engagementAction, the workflow either updates a profile property (which changes their Klaviyo segment membership), adds them to a sunset list (triggering a re-engagement flow), or suppresses them via the API.

This kind of progressive engagement management protects your sender reputation automatically, without anyone on your team needing to remember to run a manual list clean every quarter.

Production Considerations

Rate Limits

Klaviyo's API enforces rate limits that you need to respect. The general limit for most endpoints is 75 requests per second for the Events API and 10 requests per second for profile updates. In n8n, handle this by:

  • Adding a Wait node (1 second) inside loops that process large batches
  • Using n8n's built-in retry logic on HTTP Request nodes (set to retry on 429 status codes with exponential backoff)
  • Breaking large profile syncs into batches of 100 and spacing them out

Error Handling

Every n8n workflow that pushes data to Klaviyo should have an error branch. At minimum:

  1. Log failures to a Google Sheet, Slack channel, or database so you can audit what failed
  2. Retry transient failures (network timeouts, 5xx errors) automatically
  3. Alert on persistent failures (invalid API key, malformed data) via Slack or email notification

In n8n, attach an Error Trigger workflow that catches failures from your Klaviyo workflows and routes them to the appropriate notification channel.

Idempotency

If your n8n workflow pushes the same event to Klaviyo twice (because of a retry or a duplicate webhook), you could trigger a flow twice. Protect against this by including a unique_id in your event payload:

{
  "data": {
    "type": "event",
    "attributes": {
      "unique_id": "restock-SKU123-2026-03-23",
      "metric": {
        "data": {
          "type": "metric",
          "attributes": {
            "name": "Back in Stock (WMS)"
          }
        }
      }
    }
  }
}

Klaviyo deduplicates events based on unique_id, so even if your workflow fires twice, only one event gets recorded and only one flow gets triggered.

Data Freshness vs. API Cost

Not every profile property needs real-time sync. Loyalty tier data that changes once a month does not need hourly updates. Map out your data freshness requirements:

Data TypeFreshness NeededSync Frequency
Loyalty tierDailyOnce per day
Open support ticketsNear real-timeWebhook-driven
Lifetime valueDailyOnce per day
Subscription statusNear real-timeWebhook-driven
NPS scoreWeeklyWeekly batch

This prevents you from burning through API quota on unnecessary updates.

Putting It All Together: Your First Workflow

If you are starting from scratch, here is the recommended order of implementation:

  1. Profile enrichment workflow first. Get external data flowing into Klaviyo profile properties on a schedule. This immediately makes your existing Klaviyo segments and flows smarter, without building any new flows.

  2. One high-value event trigger. Pick the single external event that would have the biggest impact on revenue -- usually back-in-stock notifications or post-support review requests -- and build that workflow end to end.

  3. List hygiene automation. Set up the engagement decay workflow to protect your sender reputation from day one.

  4. Advanced orchestration. Once you are comfortable with the pattern, build out the multi-signal workflows like subscription renewal segmentation and A/B test routing.

Each workflow follows the same core pattern: listen for an external event, transform the data, push it to Klaviyo. Once you have built one, the second takes half the time, and the third takes a quarter.

The result is an email marketing program that reacts to your entire business -- not just the slice of it that Klaviyo can see natively. Your emails become more relevant because they are triggered by the right moments. Your segments become more accurate because they reflect data from every system. And your team spends less time on manual workarounds because the orchestration layer handles the complexity automatically.

Email is just one channel where automation compounds. Take the free Growth Bottleneck Audit to see where else you can eliminate manual work across your operation.

Want to Talk Through Your Automation Needs?

Book a 30-minute call. We'll map out which automations would save you the most time — no obligation.

Want to Talk Through Your Automation Needs?

Book a 30-minute call. We'll map out which automations would save you the most time — no obligation.