StackMap.aiIntegration Hub
Back to integrations
E-Commerce & Marketing#WooCommerce#Klaviyo#E-Commerce#Marketing Automation#Automated Sync

How to Connect WooCommerce to Klaviyo Setup Blueprint

Verified Blueprint

Real-time synchronization of WooCommerce customer, order, and product data to Klaviyo for targeted marketing automation and personalized customer journeys.

WooCommerce
Klaviyo
Alternative Flow

Need an alternative to manual coding? Connect these apps in minutes via Make.com.

Try Make.com

How to Connect WooCommerce to Klaviyo (Automated Data Sync)

📊 Integration Overview This blueprint outlines a robust, real-time integration pipeline designed to connect your WooCommerce store with Klaviyo, empowering sophisticated marketing automation. The core mechanism involves leveraging WooCommerce's webhook system to capture key events—such as new customer registrations, placed orders, and updated order statuses—as they occur. These events are then securely transmitted to a custom integration endpoint, where the incoming data payload is validated, transformed, and mapped to Klaviyo's API schema. Finally, the processed data is despatched to Klaviyo, creating or updating customer profiles, tracking custom events (e.g., "Placed Order," "Started Checkout"), and facilitating dynamic segmentation for highly personalized email and SMS campaigns. This ensures that your marketing efforts are always based on the most current customer behavior and transactional data, enhancing engagement and driving conversions.

Available integrations in directory: ["shopify-to-freshbooks","shopify-to-hubspot","shopify-to-klaviyo","shopify-to-mailchimp","shopify-to-netsuite","shopify-to-quickbooks","shopify-to-salesforce","shopify-to-waveaccounting","shopify-to-xero","shopify-to-zohocrm","stripe-to-hubspot","woocommerce-to-hubspot","woocommerce-to-quickbooks","woocommerce-to-salesforce","woocommerce-to-waveaccounting","woocommerce-to-xero","woocommerce-to-zohocrm"]. For similar E-Commerce integrations, consider Shopify to Klaviyo. If you're looking to connect WooCommerce to other business systems, explore options like WooCommerce to HubSpot or WooCommerce to QuickBooks.

🛠️ Core Connection Requirements Primary Key: customer_email (for Klaviyo profiles), order_id (for transactional events) Trigger Event: order.created, order.updated, customer.created, customer.updated Action Event: track (for events), identify (for profiles), subscribe (for lists)

đź“‹ The 5-Step Execution Blueprint

Step 1: Authentication & Scope Configuration To establish a secure connection, you'll need API credentials for both WooCommerce and Klaviyo.

WooCommerce API Keys: Generate a Consumer Key and Consumer Secret with "Read/Write" permissions for Customers and Orders. Path: WooCommerce -> Settings -> Advanced -> REST API -> Add key. The key will be used by your integration endpoint to make any potential back-calls (though webhooks primarily push data).

Klaviyo Private API Key: Obtain a Private API Key from your Klaviyo account. This key grants programmatic access to manage profiles, events, and lists. Path: Klaviyo -> Account -> Settings -> API Keys. Ensure the key has necessary permissions, primarily for Profiles Write, Events Write, and Lists Write.

Secure Environment Variable Setup: Store your API keys securely as environment variables in your integration environment.

// .env-example
WOOCOMMERCE_CONSUMER_KEY="ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
WOOCOMMERCE_CONSUMER_SECRET="cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
WOOCOMMERCE_WEBHOOK_SECRET="your_secure_webhook_signing_secret" # Used for verifying WooCommerce webhook signatures
KLAVIYO_PRIVATE_API_KEY="pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Step 2: Webhook Trigger Setup WooCommerce will push data to your integration via webhooks. You must register specific webhook events and provide a secure endpoint URL. WooCommerce also provides a shared secret for cryptographic signature validation to ensure the authenticity and integrity of incoming payloads.

  1. Register Webhooks in WooCommerce:

    • Navigate to: WooCommerce -> Settings -> Advanced -> Webhooks.
    • Add new webhooks for the following events, pointing to your integration's public endpoint URL:
      • order.created
      • order.updated (for status changes, refunds, etc.)
      • customer.created
      • customer.updated
    • Set the "Secret" field for each webhook to a strong, unique value (e.g., WOOCOMMERCE_WEBHOOK_SECRET from your .env).
  2. Webhook Endpoint Verification (Node.js/TypeScript Example): Your integration endpoint must listen for POST requests and validate the incoming signature.

import { createHmac } from 'crypto';
import express from 'express';
import bodyParser from 'body-parser';

const app = express();
const WOOCOMMERCE_WEBHOOK_SECRET = process.env.WOOCOMMERCE_WEBHOOK_SECRET!;

// Use raw body parser for webhook processing to allow signature verification
app.use(bodyParser.json({
  verify: (req: any, res, buf) => {
    req.rawBody = buf;
  }
}));

app.post('/webhook/woocommerce', (req, res) => {
  const hmacHeader = req.headers['x-wc-webhook-signature'];
  const topicHeader = req.headers['x-wc-webhook-topic']; // e.g., 'order.created'
  const payload = req.rawBody.toString('utf8');

  if (!hmacHeader || !topicHeader || !payload) {
    console.error('Missing WooCommerce webhook headers or payload.');
    return res.status(400).send('Bad Request: Missing webhook data.');
  }

  // Calculate HMAC-SHA256 signature
  const hmac = createHmac('sha256', WOOCOMMERCE_WEBHOOK_SECRET)
    .update(payload)
    .digest('base64');

  // Compare calculated signature with the one from the header
  if (hmac !== hmacHeader) {
    console.warn(`Webhook signature mismatch for topic: ${topicHeader}`);
    return res.status(401).send('Unauthorized: Invalid signature.');
  }

  console.log(`Received valid WooCommerce webhook for topic: ${topicHeader}`);
  
  // Process the payload based on the topic
  switch (topicHeader) {
    case 'order.created':
      // Handle new order data
      console.log('Order created:', req.body.id);
      break;
    case 'order.updated':
      // Handle order update data
      console.log('Order updated:', req.body.id);
      break;
    case 'customer.created':
      // Handle new customer data
      console.log('Customer created:', req.body.id);
      break;
    case 'customer.updated':
      // Handle customer update data
      console.log('Customer updated:', req.body.id);
      break;
    default:
      console.log(`Unhandled webhook topic: ${topicHeader}`);
  }

  res.status(200).send('Webhook received and processed.');
});

// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Webhook listener running on port ${PORT}`);
});

Step 3: Payload Transformation & Mapping Once a webhook payload is validated, it needs to be transformed into a format consumable by Klaviyo's APIs. We'll focus on mapping a WooCommerce order.created event to a Klaviyo track event (e.g., "Placed Order") and updating the associated customer identify profile.

Sample WooCommerce order.created Input (abbreviated):

{
  "id": 12345,
  "parent_id": 0,
  "status": "processing",
  "currency": "USD",
  "total": "99.99",
  "customer_id": 1,
  "billing": {
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com",
    "phone": "555-123-4567"
  },
  "shipping": { /* ... */ },
  "line_items": [
    {
      "id": 1,
      "name": "Product A",
      "product_id": 101,
      "quantity": 1,
      "total": "49.99"
    },
    {
      "id": 2,
      "name": "Product B",
      "product_id": 102,
      "quantity": 2,
      "total": "50.00"
    }
  ],
  "date_created": "2023-10-26T10:00:00Z"
}

Transformed Klaviyo identify Profile Update Output: This payload updates or creates a customer profile in Klaviyo with relevant attributes.

{
  "token": "YOUR_KLAVIYO_PUBLIC_API_KEY",
  "event": "$identify",
  "properties": {
    "$email": "john.doe@example.com",
    "$first_name": "John",
    "$last_name": "Doe",
    "$phone_number": "555-123-4567",
    "WooCommerceCustomerID": 1,
    "LastOrderDate": "2023-10-26T10:00:00Z",
    "TotalOrders": 1,
    "LifetimeValue": 99.99
  }
}

Transformed Klaviyo track Event Output (e.g., "Placed Order"): This payload records a specific event, linking it to the customer profile.

{
  "token": "YOUR_KLAVIYO_PUBLIC_API_KEY",
  "event": "Placed Order",
  "customer_properties": {
    "$email": "john.doe@example.com",
    "$first_name": "John",
    "$last_name": "Doe"
  },
  "properties": {
    "$event_id": "WC_ORDER_12345_20231026100000", // Unique event identifier
    "$value": 99.99,
    "OrderID": 12345,
    "OrderNumber": 12345,
    "OrderTotal": 99.99,
    "Currency": "USD",
    "Products": [
      {
        "ID": 101,
        "Name": "Product A",
        "Quantity": 1,
        "Price": 49.99
      },
      {
        "ID": 102,
        "Name": "Product B",
        "Quantity": 2,
        "Price": 25.00 // Assuming per unit price for clarity
      }
    ],
    "ItemNames": ["Product A", "Product B"],
    "Categories": ["Category1", "Category2"], // Derive from product data if available
    "DiscountCode": null,
    "Status": "processing"
  },
  "time": 1698391200 // Unix timestamp of event in seconds
}

Note: The token in Klaviyo identify and track payloads is typically your Public API Key (Site ID), not the Private API Key used for server-side management. However, when making server-side API requests using the v2/track or v2/identify endpoints, you'll use the Private API Key in the Authorization header, and the token field is then often omitted or handled differently depending on the specific endpoint version. For newer Klaviyo APIs (v3/v2.5), using the private API key in the Authorization header is standard, and the token field is not required in the body.

Step 4: Endpoint Despatch & Error Guarding After transformation, the data is sent to Klaviyo's API. This step is critical for reliability, requiring robust error handling.

Klaviyo API Request (Node.js/TypeScript using axios):

import axios from 'axios';

const KLAVIYO_PRIVATE_API_KEY = process.env.KLAVIYO_PRIVATE_API_KEY!;
const KLAVIYO_API_URL = 'https://a.klaviyo.com/api'; // Or v3 API: https://a.klaviyo.com/api/v2.5 (for events) or v3 for profiles

async function sendToKlaviyo(endpoint: string, payload: any) {
  try {
    const headers = {
      'Authorization': `Klaviyo-API-Key ${KLAVIYO_PRIVATE_API_KEY}`,
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    };
    
    // For V3 APIs, specific endpoints for profiles and events.
    // Example for V3 Profile Update:
    if (endpoint.includes('/profiles/')) {
      const response = await axios.patch(`${KLAVIYO_API_URL}${endpoint}`, payload, { headers });
      return response.data;
    }
    // Example for V3 Event Track:
    else if (endpoint.includes('/events/')) {
      const response = await axios.post(`${KLAVIYO_API_URL}${endpoint}`, payload, { headers });
      return response.data;
    }
    // Fallback or older V2 track/identify (less common for new integrations)
    else {
      // Old V2 track/identify uses GET with base64 encoded data, or POST with specific JSON.
      // This example focuses on newer patterns.
      console.warn("Using potentially deprecated Klaviyo endpoint pattern. Consider V2.5/V3.");
      // This example for v2/track requires a different structure:
      // const trackPayload = { token: KLAVIYO_PUBLIC_API_KEY, event: payload.event, customer_properties: payload.customer_properties, properties: payload.properties };
      // const response = await axios.post(`${KLAVIYO_API_URL}/api/track`, trackPayload, { headers });
      // For new integrations, prefer V3.
      throw new Error("Unsupported Klaviyo API endpoint for direct payload despatch.");
    }

  } catch (error: any) {
    if (axios.isAxiosError(error)) {
      console.error(`Klaviyo API Error: ${error.response?.status} - ${JSON.stringify(error.response?.data)}`);
      throw new Error(`Klaviyo API request failed: ${error.response?.status} ${error.response?.data?.message || error.message}`);
    }
    throw error;
  }
}

// Example usage:
// await sendToKlaviyo('/api/v2.5/track', klaviyoTrackPayload); // For V2.5 events
// await sendToKlaviyo('/api/profiles/', klaviyoIdentifyPayload); // For V3 profiles (PATCH)

Error Guarding Strategies:

  • 401 (Unauthorized):

    • Cause: Invalid or expired API key.
    • Handling: Log the error, send an alert to the administrator. This typically requires manual intervention to refresh or update the KLAVIYO_PRIVATE_API_KEY. Do not retry automatically unless you have an automated key rotation mechanism.
  • 400 (Bad Request):

    • Cause: Data validation errors (e.g., missing required fields, incorrect data types).
    • Handling:
      1. Log Details: Capture the specific error message from Klaviyo's response, which usually indicates the problematic field.
      2. Dead-Letter Queue (DLQ): Move the failed payload to a DLQ for manual inspection and correction.
      3. Alerting: Notify developers to investigate the data mapping logic.
      4. No Retry: Retrying a 400 error without correcting the payload is futile.
  • 429 (Rate Limiting):

    • Cause: Exceeding Klaviyo's API request limits (e.g., too many requests per second).
    • Handling:
      1. Asynchronous Queueing: Implement a message queue (e.g., Redis with BullMQ, Kafka) to buffer outgoing Klaviyo requests. Your webhook receiver should quickly acknowledge the request and push the processing to this queue.
      2. Exponential Backoff with Jitter: When a 429 is received, wait for an increasing duration before retrying. Introduce a small random jitter to avoid thundering herd issues.
      3. Retry Headers: Klaviyo often includes Retry-After headers. Respect these if present.
      4. Circuit Breaker Pattern: Temporarily halt requests if rate limits are hit repeatedly, allowing the system to recover.
  • 5xx (Server Errors - e.g., 500, 502, 503):

    • Cause: Temporary issues on Klaviyo's server side.
    • Handling:
      1. Retry with Exponential Backoff: Implement a retry mechanism with increasing delays. Start with short delays (e.g., 1s, 5s, 15s, 60s) for a limited number of attempts.
      2. Circuit Breaker: If multiple 5xx errors occur, activate a circuit breaker to prevent flooding a potentially overloaded Klaviyo server, then gracefully degrade or switch to a fallback if possible.
      3. Alerting: Log the errors and trigger alerts if persistent 5xx errors occur, indicating a broader issue with Klaviyo's service.
      4. Monitoring: Monitor API uptime and response times.

Step 5: Live Loop Validation Thorough testing in a sandbox or staging environment is crucial before deploying to production.

  1. Environment Setup:

    • Set up a development/staging WooCommerce instance.
    • Create a dedicated Klaviyo sandbox account or a separate list/segment in your live account to quarantine test data.
  2. Test Case Execution:

    • New Customer Registration: Create a new customer account in WooCommerce. Verify that a new profile (or an updated one if email exists) appears in Klaviyo, with accurate first_name, last_name, email, and custom WooCommerce attributes.
    • Order Placement: Place a test order in WooCommerce (ensure it progresses to "processing" or "completed" status).
      • Verify a "Placed Order" event (or similar) is tracked in Klaviyo, containing correct $value, OrderID, Products array, and ItemNames.
      • Check that the customer profile associated with the order has updated metrics like TotalOrders and LifetimeValue.
    • Order Update: Change the status of a test order (e.g., from "processing" to "completed"). Verify if a relevant event (e.g., "Order Fulfilled") or profile update occurs in Klaviyo.
    • Customer Update: Edit customer details (e.g., phone number) in WooCommerce. Confirm the Klaviyo profile is updated.
  3. Data Integrity Checks:

    • No Truncation: Ensure all expected fields from WooCommerce are correctly mapped and transmitted to Klaviyo without data loss or shortening.
    • No Duplication: Verify that customer profiles are not duplicated based on email. Klaviyo's identify call inherently handles merging based on email. For events, ensure your $event_id is unique per event instance to prevent Klaviyo from recording duplicate events if a webhook is re-sent.
    • Correct Data Types: Confirm that numerical values are numbers, dates are in correct formats, etc.
    • Segmentation Validation: Create a test segment in Klaviyo based on the data sent (e.g., "Customers who placed an order over $50"). Verify that your test customers appear in these segments as expected.
  4. Monitoring: Implement logging and monitoring for your integration service to track successful requests, errors, and queue lengths. Use tools like Prometheus/Grafana or cloud-native monitoring solutions (e.g., AWS CloudWatch, Azure Monitor) to track the health of your webhook endpoint and Klaviyo API calls.


âť“ Integration Frequently Asked Questions

Q: How does this pipeline handle duplicate data entries? A: This integration pipeline is designed with idempotency in mind for Klaviyo, leveraging its inherent behavior and best practices for event tracking.

  1. Customer Profiles: When using Klaviyo's identify endpoint, Klaviyo uses the $email property as the primary key. If a profile with that email already exists, Klaviyo updates the existing profile with any new or changed properties rather than creating a duplicate. If no profile exists, a new one is created. This prevents duplicate customer entries.
  2. Event Tracking: For track events (e.g., "Placed Order"), Klaviyo allows for an optional $event_id property. It is crucial to generate a unique and deterministic $event_id for each distinct occurrence of an event. For example, for a WooCommerce order creation, combining the WooCommerce order_id with a timestamp (e.g., WC_ORDER_12345_20231026100000) creates a highly unique identifier. If Klaviyo receives a track request with an $event_id that it has previously processed, it will typically deduplicate that event, preventing multiple records of the exact same transactional event. This ensures that even if a WooCommerce webhook is re-sent or processed multiple times due to network issues, the event is only recorded once in Klaviyo.

Q: What happens if the API rate limit is exceeded during high volume? A: Exceeding API rate limits is a common challenge in high-volume data synchronization. Our blueprint addresses this through a multi-pronged approach:

  1. Asynchronous Message Queue: The webhook receiver acts as a lean ingress point, quickly validating the incoming WooCommerce payload and then pushing it onto an asynchronous message queue (e.g., a Redis-backed queue like BullMQ or a cloud-managed service like AWS SQS/Azure Service Bus). This decouples the webhook receipt from the Klaviyo API despatch, allowing the webhook to respond quickly to WooCommerce, preventing timeouts, and ensuring no data is lost.
  2. Worker Processes: Dedicated worker processes consume messages from this queue. These workers are responsible for payload transformation and making the actual API calls to Klaviyo.
  3. Exponential Backoff and Jitter: If a Klaviyo API request returns a 429 Too Many Requests status, the worker process implements an exponential backoff strategy. It waits for an increasingly longer period (e.g., 1s, 2s, 4s, 8s) before retrying the request. To prevent all workers from retrying simultaneously and causing another rate limit breach, a random "jitter" (a small, random delay) is added to the backoff interval.
  4. Retry Headers: Klaviyo's API often includes a Retry-After HTTP header in its 429 responses, specifying how long to wait before retrying. Workers are configured to respect this header if present.
  5. Circuit Breaker Pattern: A circuit breaker is implemented to monitor the success/failure rate of Klaviyo API calls. If failures (especially 429s) exceed a predefined threshold within a certain period, the circuit "opens," temporarily stopping further requests to Klaviyo from that worker or even globally, allowing Klaviyo's systems to recover. After a configured "cool-down" period, the circuit enters a "half-open" state, allowing a few test requests to determine if the service has recovered before fully closing.
  6. Prioritization (Optional): For extremely high-volume scenarios with different event criticality, the message queue can be configured with multiple queues or message priorities, ensuring critical events (e.g., "Placed Order") are processed before less critical ones.
Developer Infrastructure

Deploy custom integration scripts safely.

Get $200 free server credits on DigitalOcean to host webhook brokers, queues, and database engines.

Get $200 Free Credits

Integration Core Specs

Source Platform

WooCommerce

Destination Platform

Klaviyo

Primary Key Identifieremail
Pipeline SpeedSub-second Realtime

Production Guardrails

  • Automatic signature checks for HMAC SHA256 payloads.
  • Redis queue throttle buffers to prevent Intuit/HubSpot API caps.
  • Fallbacks for missing SKU or contact mappings.
  • Idempotent validation gates before REST ledger entry creation.