To integrate Klaviyo with Lovable, create a Supabase Edge Function that proxies Klaviyo API calls using your Private API Key stored in Cloud Secrets. Use your Public API Key for client-side event tracking. This lets you manage Klaviyo profiles, track custom events, sync subscribers to lists, and trigger email and SMS automation flows from your Lovable app.
Add Klaviyo E-commerce Email Automation to Your Lovable App
Klaviyo is the email and SMS marketing platform of choice for serious e-commerce businesses, known for its deep integration with purchase data and revenue attribution. Unlike general-purpose email tools, Klaviyo is built around behavioral triggers — abandoned cart emails, post-purchase sequences, browse abandonment, and win-back campaigns — all driven by the event data you send from your store.
Integrating Klaviyo with Lovable gives your app access to the full Klaviyo automation stack: track custom events when users take important actions (viewed a product, added to cart, started checkout), manage subscriber profiles with custom properties, add users to segmented lists, and trigger Klaviyo flows that send perfectly timed email and SMS sequences. Klaviyo's revenue attribution then connects your email sends back to actual purchases, showing you exactly how much revenue each campaign generates.
Klaviyo uses two types of API keys: a Public API Key (also called Site ID) that is safe to include in client-side JavaScript for event tracking, and a Private API Key that must stay server-side for profile management, list operations, and sensitive data access. This guide covers both correctly — client-side event tracking with the Public Key and server-side profile management through Edge Functions with the Private Key.
Integration method
Klaviyo integration in Lovable uses two API keys with different security requirements. The Private API Key (used for profile management, list subscriptions, and flow triggering) is stored in Cloud Secrets and accessed only from Edge Functions via Deno.env.get(). The Public API Key (safe for client-side use) is used for event tracking directly in React components using Klaviyo's JavaScript SDK or a lightweight fetch call. This split architecture matches Klaviyo's own recommended integration pattern.
Prerequisites
- A Klaviyo account at klaviyo.com — free tier available with up to 500 email contacts
- At least one Klaviyo list created for subscriber management (or note the list ID of an existing list)
- A Lovable project with Lovable Cloud enabled
- Basic familiarity with Klaviyo's interface for creating flows and reviewing profile data
- For full automation: Klaviyo flows set up in advance so tracked events trigger the correct email sequences
Step-by-step guide
Find your Klaviyo API keys
Find your Klaviyo API keys
Log in to your Klaviyo account and navigate to Settings → API Keys (found under the account name dropdown in the bottom left of the sidebar, or via Settings → Account → API Keys). You will see two types of keys on this page. The Public API Key (labeled 'Public API Key' or 'Site ID') is a short alphanumeric string — this key is designed to be used in client-side JavaScript and can safely appear in your React component code. It is used for event tracking with Klaviyo's identify and track calls. The Private API Keys section lets you generate server-side keys — click 'Create Private API Key'. Give it a name like 'Lovable Integration' and select the access scopes your integration needs: for list subscription management select Lists - Read Access and Profiles - Write Access; for event tracking you need Events - Write Access; for full profile management select all of the above. Click 'Create'. The Private API Key is shown once — copy it immediately. If you plan to use Klaviyo for SMS in addition to email, note that SMS subscription management uses the same API endpoints but requires Klaviyo SMS to be enabled on your account.
Pro tip: Klaviyo's Private API Keys now use a newer format starting with pk_ (as of 2024). Older keys starting with a different prefix still work but the new format supports scope-restricted keys for better security.
Expected result: You have your Klaviyo Public API Key (short Site ID) and a scoped Private API Key copied and ready to configure.
Configure Klaviyo API keys in Lovable
Configure Klaviyo API keys in Lovable
In your Lovable project, open the Cloud tab by clicking '+' next to Preview, then go to the Secrets section. Add one secret: KLAVIYO_PRIVATE_KEY with your Private API Key value. This key must stay server-side — it has access to read and write customer profiles, which is sensitive data. For the Public API Key, you can add it as a Lovable environment variable (which is safe for browser exposure since it is a public key by design) or hardcode it in your React component — either is acceptable. Add VITE_KLAVIYO_PUBLIC_KEY as an environment variable in your project settings (not in Cloud Secrets) with your Public API Key. The VITE_ prefix makes it available in React components as import.meta.env.VITE_KLAVIYO_PUBLIC_KEY. Alternatively, add it directly to the Klaviyo tracking component since it is intentionally public. Lovable's security system correctly identifies KLAVIYO_PRIVATE_KEY as a sensitive credential and stores it with encryption — approximately 1,200 API keys per day are prevented from being hardcoded in application code by Lovable's security layer.
Pro tip: The Public API Key is safe to use in client-side code — Klaviyo designed it this way. Only the Private API Key needs to be in Cloud Secrets.
Expected result: KLAVIYO_PRIVATE_KEY is stored in Cloud Secrets. VITE_KLAVIYO_PUBLIC_KEY is configured as an environment variable.
Create the Klaviyo private API proxy Edge Function
Create the Klaviyo private API proxy Edge Function
Ask Lovable to create a Supabase Edge Function for Klaviyo operations that require the Private API Key — specifically, profile creation and updates, list subscription management, and event tracking with server-side context. Klaviyo's current API (v3/beta as of 2024) uses JSON:API format at https://a.klaviyo.com/api/. The Authorization header should be 'Klaviyo-API-Key YOUR_PRIVATE_KEY'. Key endpoints include /api/profiles/ for creating or updating profiles, /api/lists/{list_id}/relationships/profiles/ for subscribing profiles to lists, and /api/events/ for server-side event tracking. The Edge Function should accept an 'operation' parameter to route between these endpoints: subscribe (add email to list), update_profile (set custom properties), and track_event (server-side event). Build the appropriate JSON:API request body for each operation and POST to the correct Klaviyo endpoint. Include proper CORS headers and error handling for Klaviyo's error response format.
Create a Supabase Edge Function called klaviyo-api that handles three Klaviyo operations. For 'subscribe': POST to /api/profiles/ to create/update a profile, then POST to /api/lists/{listId}/relationships/profiles/ to add them to a list. For 'track_event': POST to /api/events/ with event name and properties. Read KLAVIYO_PRIVATE_KEY from Deno.env.get() and use it in the header: Klaviyo-API-Key {key}. Accept operation, email, properties, listId, eventName in the request body.
Paste this in Lovable chat
1import { serve } from "https://deno.land/std@0.168.0/http/server.ts";23const corsHeaders = {4 "Access-Control-Allow-Origin": "*",5 "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",6};78const KLAVIYO_API = "https://a.klaviyo.com/api";910serve(async (req) => {11 if (req.method === "OPTIONS") {12 return new Response("ok", { headers: corsHeaders });13 }1415 try {16 const apiKey = Deno.env.get("KLAVIYO_PRIVATE_KEY")!;17 const headers = {18 "Authorization": `Klaviyo-API-Key ${apiKey}`,19 "Content-Type": "application/json",20 "revision": "2024-10-15",21 };2223 const { operation, email, firstName, lastName, properties, listId, eventName } =24 await req.json();2526 if (operation === "subscribe") {27 // Create or update profile28 const profileRes = await fetch(`${KLAVIYO_API}/profiles/`, {29 method: "POST",30 headers,31 body: JSON.stringify({32 data: {33 type: "profile",34 attributes: {35 email,36 first_name: firstName || "",37 last_name: lastName || "",38 properties: properties || {},39 },40 },41 }),42 });43 const profileData = await profileRes.json();44 const profileId = profileData.data?.id;4546 if (listId && profileId) {47 await fetch(`${KLAVIYO_API}/lists/${listId}/relationships/profiles/`, {48 method: "POST",49 headers,50 body: JSON.stringify({51 data: [{ type: "profile", id: profileId }],52 }),53 });54 }5556 return new Response(JSON.stringify({ success: true, profileId }), {57 headers: { ...corsHeaders, "Content-Type": "application/json" },58 });59 }6061 if (operation === "track_event") {62 const eventRes = await fetch(`${KLAVIYO_API}/events/`, {63 method: "POST",64 headers,65 body: JSON.stringify({66 data: {67 type: "event",68 attributes: {69 metric: { data: { type: "metric", attributes: { name: eventName } } },70 profile: { data: { type: "profile", attributes: { email } } },71 properties: properties || {},72 },73 },74 }),75 });76 const ok = eventRes.status === 202;77 return new Response(JSON.stringify({ success: ok }), {78 headers: { ...corsHeaders, "Content-Type": "application/json" },79 });80 }8182 return new Response(JSON.stringify({ error: "Unknown operation" }), {83 status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" },84 });85 } catch (error) {86 return new Response(87 JSON.stringify({ error: error.message }),88 { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }89 );90 }91});Pro tip: Klaviyo's API requires a 'revision' header with the API version date. Use the latest stable revision date from Klaviyo's changelog to access current API features.
Expected result: The klaviyo-api Edge Function is deployed. Test by subscribing a test email through the function and checking it appears in your Klaviyo lists.
Build a Klaviyo email signup form component
Build a Klaviyo email signup form component
Ask Lovable to create a reusable EmailSignup React component that captures name and email, calls the klaviyo-api Edge Function to subscribe the user to your Klaviyo list, and shows appropriate success and error states. The component should use Lovable's built-in shadcn/ui Input and Button components for consistent styling. Add client-side validation to ensure the email is properly formatted before submitting. After successful subscription, show a success message explaining that Klaviyo will send a confirmation email if double opt-in is enabled (which is the default and required in many countries). You will need your Klaviyo List ID — find this in Klaviyo by going to Lists → click your list → the list ID appears in the URL and on the list settings page. The List ID is a string like 'abc123' and should be passed as listId in the Edge Function request body. For GDPR compliance, include a clear consent checkbox explaining what the subscriber is signing up for before allowing form submission.
Create an EmailSignup React component with firstName, lastName, and email fields plus a consent checkbox. When submitted, call my klaviyo-api Edge Function with operation=subscribe, the user's details, and listId='YOUR_LIST_ID'. Show a loading spinner during submission, a success message on completion, and an error message if it fails. Include form validation for email format and require the consent checkbox.
Paste this in Lovable chat
Pro tip: Replace 'YOUR_LIST_ID' with your actual Klaviyo list ID. You can find it by going to Klaviyo → Lists → your list → the ID appears in the page URL.
Expected result: Submitting the signup form adds the subscriber to your Klaviyo list, visible immediately in Klaviyo's Profiles section.
Implement client-side Klaviyo event tracking
Implement client-side Klaviyo event tracking
For tracking behavioral events like product views, add-to-cart, and checkout starts, use Klaviyo's client-side track API directly from your React components — this is one of the rare cases where calling an external API directly from the frontend is the correct approach, because Klaviyo's Public API Key is designed for this use. Klaviyo's track endpoint is https://a.klaviyo.com/api/track (legacy v1) or the newer identify and track pattern. For client-side tracking, send a POST to the track endpoint with your Public API Key and event data. Identify the user first by calling the identify endpoint with their email when they log in or submit a form, then subsequent track calls will be attributed to that profile. For the most reliable tracking, identify the user as early as possible (login, signup, email form submit) and then track behavioral events on key pages. Ask Lovable to create a useKlaviyo custom React hook that wraps the identify and track calls with your Public API Key, making it easy to add tracking to any component with one line of code.
Create a useKlaviyo React hook that exposes identify(email, properties) and track(eventName, properties) functions. Use VITE_KLAVIYO_PUBLIC_KEY from import.meta.env. The identify function should POST to https://a.klaviyo.com/api/identify with the profile data. The track function should POST to https://a.klaviyo.com/api/track with the event name and properties. Both should use the encoded base64 format Klaviyo expects.
Paste this in Lovable chat
Pro tip: Klaviyo's legacy track endpoint expects the data as a base64-encoded JSON string in the 'data' query parameter. The newer API v3 accepts JSON directly with the Authorization header.
Expected result: Behavioral events appear in Klaviyo's Activity feed for test profiles, confirming event tracking is working.
Common use cases
Email list signup form with Klaviyo list subscription
Add a newsletter signup form to your Lovable app that subscribes new users to a Klaviyo list with their email, name, and any custom properties. The Edge Function calls Klaviyo's Subscribe API with double opt-in support for GDPR compliance.
Create an email signup form component that collects name and email. When submitted, call an Edge Function that subscribes the user to my Klaviyo list using the Private API Key. Add them to list ID 'abc123' with their name as a custom property. Show a success message with 'Check your email to confirm' for double opt-in.
Copy this prompt to try it in Lovable
E-commerce event tracking for automated flows
Track Klaviyo events when users view products, add to cart, or complete purchases. These events power Klaviyo's automated flow triggers — sending abandoned cart emails 1 hour after Add to Cart, or post-purchase review request emails 7 days after an order.
Add Klaviyo event tracking to my product pages. When a user views a product, track a 'Viewed Product' event with product ID, name, price, and category. When they add to cart, track 'Added to Cart' with the same data. Use my Klaviyo Public API Key to send these events directly from the React component to Klaviyo's track API at https://a.klaviyo.com/api/track.
Copy this prompt to try it in Lovable
Post-purchase customer profile enrichment
After a customer completes a Stripe payment in your Lovable app, send their purchase data to Klaviyo to update their profile and trigger post-purchase automation flows. The Edge Function creates or updates the Klaviyo profile with purchase history and triggers the Placed Order event.
After a successful Stripe payment, call an Edge Function that creates or updates the customer's Klaviyo profile using the Private API Key, adds the order value and product names as profile properties, and tracks a 'Placed Order' event with the order details. This should trigger my Klaviyo post-purchase flow.
Copy this prompt to try it in Lovable
Troubleshooting
Edge Function returns 401 Unauthorized from Klaviyo API
Cause: The KLAVIYO_PRIVATE_KEY secret is missing, incorrectly named, or the key has been revoked. Klaviyo's v3 API requires the header format 'Klaviyo-API-Key {key}' not 'Bearer {key}'.
Solution: Verify the secret name is exactly KLAVIYO_PRIVATE_KEY in Cloud Secrets. Check the Authorization header format in your Edge Function — it must be Klaviyo-API-Key {yourKey}. Confirm the Private API Key is active in Klaviyo under Settings → API Keys and has the required scopes (Profiles - Write, Lists - Full Access).
1"Authorization": `Klaviyo-API-Key ${apiKey}`,Profile is created but not added to the list — list subscription silently fails
Cause: The List ID passed to the Edge Function is incorrect, or the Klaviyo account's double opt-in settings require the subscriber to confirm via email before they appear as subscribed in the list.
Solution: Verify the List ID by navigating to Klaviyo → Lists → your list — the ID appears in the URL. For double opt-in (recommended and GDPR-required), the subscriber will only appear in the list after clicking the confirmation email. Check Klaviyo's Profiles section — the profile should exist immediately even if the list subscription is pending confirmation.
Client-side event tracking works but events are not triggering Klaviyo flows
Cause: Klaviyo flows are triggered by specific metric names — if the event name in your React component does not exactly match the trigger configured in the Klaviyo flow, the flow will not fire.
Solution: In Klaviyo, go to Flows → your flow → click the trigger → check the metric name. Ensure your track() call uses the exact same metric name string (case-sensitive). Common names like 'Added to Cart' and 'Placed Order' are Klaviyo standard events with special handling — use these exact strings for e-commerce flows.
Klaviyo API returns a 409 Conflict error when creating a profile
Cause: A profile with this email address already exists in Klaviyo. The /api/profiles/ POST endpoint returns 409 when the email is already registered.
Solution: Use Klaviyo's upsert endpoint instead: PATCH to /api/profiles/{profile_id} or use the create-or-update endpoint. First attempt a GET to find the existing profile by email, then PATCH to update it. Alternatively, catch the 409 response in your Edge Function and treat it as a success — the profile already exists, so subscription to a list can proceed with the profile ID from the 409 response body.
1if (profileRes.status === 409) {2 const errorData = await profileRes.json();3 // Extract existing profile ID from error response4 const profileId = errorData.errors?.[0]?.meta?.duplicate_profile_id;5}Best practices
- Always keep KLAVIYO_PRIVATE_KEY in Cloud Secrets — the Public API Key is safe for client-side use, but the Private Key has full profile read access and must never appear in frontend code
- Include the 'revision' header with Klaviyo's current API version date to ensure you are using the latest API behavior and avoid deprecation-related breakages
- Use Klaviyo's standard event names for e-commerce actions ('Placed Order', 'Added to Cart', 'Viewed Product') to take advantage of Klaviyo's pre-built revenue attribution and flow templates
- Implement double opt-in for email subscriptions to maintain list health, improve deliverability, and comply with GDPR and CAN-SPAM regulations
- Track events with rich property data — the more context Klaviyo has (product name, price, category, order value), the more precisely you can segment and target subscribers
- Call Klaviyo's identify function when a user logs in to link anonymous behavioral events to a known profile, enabling accurate attribution even for multi-session journeys
- Test Klaviyo flows in Klaviyo's Preview mode before enabling them for production traffic — triggered flows fire based on event properties and can be difficult to reverse once active
Alternatives
Mailchimp is a general-purpose email platform with a free tier suitable for beginners, whereas Klaviyo is purpose-built for e-commerce with revenue attribution and more powerful behavioral automation.
ConvertKit is designed for content creators and bloggers with simpler pricing, whereas Klaviyo is built for online stores that need product-level revenue tracking and abandoned cart automation.
SendGrid is a transactional email delivery service with high volume sending infrastructure, while Klaviyo is a complete marketing automation platform with built-in behavioral triggers and customer journey flows.
Frequently asked questions
Can I use Klaviyo's free plan with this Lovable integration?
Yes. Klaviyo's free plan supports up to 500 email contacts and 150 SMS credits per month. The API features used in this guide — profile management, list subscriptions, and event tracking — are all available on the free plan. The integration works identically on free and paid plans. As your list grows past 500 contacts, Klaviyo's pricing scales by contact count.
What is the difference between Klaviyo's Public API Key and Private API Key?
The Public API Key (Site ID) is intentionally designed for client-side JavaScript use — it can only submit events and identify calls, never read customer data. The Private API Key has full read and write access to profiles, lists, segments, campaigns, and flows. Always keep the Private Key server-side in Cloud Secrets. Using the Public Key in React component code is correct and safe.
How do I connect Klaviyo to my Shopify store in Lovable?
Lovable's native Shopify connector handles the Shopify integration. For Klaviyo, the recommended approach is to install Klaviyo's official Shopify app directly in your Shopify store — this handles all e-commerce event tracking and order syncing between Shopify and Klaviyo automatically. Your Lovable app can then use the Klaviyo API integration from this guide for any custom events or subscription forms outside of the Shopify storefront.
Can Klaviyo send SMS messages from this integration?
Yes, if Klaviyo SMS is enabled on your account (requires US/Canada phone number and SMS plan). The Edge Function can subscribe users to SMS lists by including the phone_number field in the profile attributes alongside email. Klaviyo handles SMS compliance and opt-in confirmation automatically when you use the standard subscription API.
How do I trigger a specific Klaviyo flow from my Lovable app?
Klaviyo flows are triggered by metric events, not called directly. To trigger a flow, track the event it is configured to listen for. For example, if your 'Welcome Series' flow triggers on the 'Subscribed to List' event, adding someone to the list via the API automatically starts the flow for them. For custom trigger events, use the track_event operation in the Edge Function with the exact event name configured as the flow trigger.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation