Klaviyo
Grow your lists with Klaviyo signup forms and keep visitor tracking under consent. By default, Klaviyo.js waits for marketing and measurement.
Inth keeps the consent record of each choice, with the visitor’s country and the policy that applied.
pnpm add @c15t/integrationsAllow marketing only. Nothing loads from Klaviyo, and the Application tab shows no __kla_id cookie.
Before you start
You need an Inth project that connects to your app and c15t in that app. You also need the six character public API key from Settings > Account > API keys in Klaviyo.
Never put a private key (pk_...) in browser code. If you pass one, the helper logs an error, and Klaviyo does not load.
Open the quickstart for your frameworkHow consent works with Klaviyo
One script, Klaviyo.js, serves signup forms and Active on Site tracking. Klaviyo has no setting that loads one without the other.
So by default, the c15t klaviyo helper waits for marketing and measurement. With one category or none, c15t requests nothing from Klaviyo, and Klaviyo stores nothing.
Once the second category has permission, Klaviyo.js loads once without a page reload. On withdrawal, c15t removes the loader and reloads the page.
The helper sets the vendor slug klaviyo. So a visitor can allow both categories and still switch Klaviyo off.
Installation
The helper has two modes. Pick forms with tracking, or forms alone.
Forms only is not a cookieless mode. Klaviyo.js still writes an anonymous __kla_id cookie, and form views still reach Klaviyo form analytics.
Setup steps
Install the integration package
Add the helpers next to c15t. An import alone does not start Klaviyo.js.
Add your public API key
The public API key, also called the site ID, appears on every page that loads Klaviyo. So it is safe in browser code.
src/consent-scripts.ts Pass your own category condition if your legal review classes Klaviyo in another way.
Send your own events only with consent
The helper never calls identify or track. The klaviyo object exists only after consent on this page, so optional chaining drops calls made without it.
src/add-to-cart.ts This check needs the default reload on revocation. With reloadOnConsentRevoked: false, check the categories before each call.
Register it with your existing setup
Add scripts to the c15t configuration that you have now. Keep your Inth endpoint, mode, policy, styles and consent UI.
Add scripts to c15t.config.ts, next to next.config.ts. Keep the rest of your config, such as mode, in the same call. App Router, Pages Router and static export read the same file.
c15t.config.ts Pass scripts to the ConsentRoot in your root route. Import helpers in the route module, not in a server function: script configurations carry callbacks.
src/routes/__root.tsx Add scripts to the options of your ConsentProvider, next to mode. Keep the banner, dialog and preferences link inside the provider.
src/consent.tsx Register scripts under the c15t key in app.config.ts. Keep them out of nuxt.config.ts, which reaches the browser as JSON and drops the helper callbacks.
app/app.config.ts Pass scripts to the c15tVue plugin call you have now. The plugin starts one script loader when the app mounts.
src/main.ts Add scripts to the client entrypoint, which the integration finds on its own. Keep helpers out of astro.config.mjs: its options are serialized into the page.
src/c15t.client.ts Pass scripts as a prop to the ConsentProvider you have now. The provider owns the loader and disposes it on unmount.
src/App.svelte Add scripts to the ConsentRoot in the root layout. Import helpers in the layout component, not in +layout.server.ts: a server load cannot send functions to the browser.
src/routes/+layout.svelte Paste the vendor’s snippet behind consent
The helpers need a bundler. On a page with the c15t script tag, paste the vendor’s own snippet instead and keep it inert until visitors allow its category. Helper options, such as loadMode, do not apply.
index.html Pass scripts to init() from @c15t/browser, next to your mode. With createConsentRuntime, pass scripts to it instead.
src/consent.ts
Remove the Klaviyo snippet first. On Shopify, BigCommerce, WooCommerce and other platforms where Klaviyo adds Klaviyo.js for you, turn that off.
Verify your setup
Filter DevTools Network by klaviyo. Then test the three states.
Before a choice
Allow marketing only. Nothing loads from Klaviyo, and the Application tab shows no __kla_id cookie.
After you allow both
Allow measurement too. klaviyo.js loads from static.klaviyo.com/onsite/js/ with your key, followed by its modules.
After you withdraw consent
c15t removes the loader and reloads the page. The new page loads nothing from Klaviyo.
Cookie consent is not subscription consent. Your Klaviyo forms still need their own email and SMS consent, in the words that your channels need.
Open the full Klaviyo guide