Skip to content

Klaviyo Subscription

The Klaviyo Subscription extension adds what the official Klaviyo extension leaves out for a Venta store: SMS marketing consent, region-aware phone validation for it, a merge or replace choice when an abandoned-cart link arrives at a cart that already has items, and cookie-consent gating on Klaviyo's onsite JavaScript.

It is a layer on top of klaviyo/magento2-extension, not a replacement. Every feature reads its API keys and its consent-at-checkout settings from the official extension's configuration, and the module cannot run without it.

Documentation

  • Benefits covers what the extension adds for a store already running Klaviyo.

Installation

Installation Command:

bash
composer require magebitcom/module-klaviyo-subscription

Composer pulls in klaviyo/magento2-extension 4.4.* as a dependency.

Post-Installation Steps:

bash
bin/magento module:enable Klaviyo_Reclaim Magebit_KlaviyoSubscription
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

setup:di:compile is required here because ViewModel/Telephone type-hints a Hyvä class in its constructor.

Configuration Access: Navigate to Stores > Configuration > Magebit > Klaviyo for this module's own settings, and Stores > Configuration > Klaviyo for the API keys and the consent-at-checkout settings it reads.

Requirements

RequirementVersion
PHP8.1 or higher
Magento2.4.x
Klaviyo extensionklaviyo/magento2-extension 4.4.*
Hyvä theme moduleany current release
Hyvä Checkoutrequired for the checkout consent checkboxes
Magewirerequired by the checkout component
Venta Themerequired by the registration form template
Magebit GDPRoptional. Without it the cookie gate is inert and Klaviyo loads unconditionally

Only the first three of those are enforced by Composer. Everything below them is used by the code and either understated or absent from composer.json:

DependencyHow composer.json treats itWhat actually needs it
Hyvä theme modulesuggestViewModel/Telephone type-hints the Hyvä SvgIcons class in its constructor, so setup:di:compile fails without it. All six storefront templates need the Hyvä view model registry, and the module uses seven Hyvä view models in total.
Magewirenot declaredThe checkout component extends Magewirephp\Magewire\Component.
Hyvä Checkoutnot declaredThe hyva_checkout_components layout handle, and five Magewire address events the component listens on.
Magebit_VentaThemenot declaredThe registration template calls Magebit\VentaTheme\ViewModel\Customer\Registration to render agreements, on every Create Account page load.
Magebit GDPRnot declaredThe cookie gate reads window.cookie_consent_config and window.cookie_consent_groups and listens for user-allowed-save-cookie, all published by the GDPR module. window.COOKIE_CONFIG comes from Hyvä core, so the gate needs both.
Magento core modulesnone declaredCustomer, Quote, Newsletter, Checkout, Store, Ui, Directory, Config, Sales, Backend. module.xml sequences only Klaviyo_Reclaim.

In practice this is a Venta module rather than a portable Magento extension. Installing it on a Hyvä store without Venta Theme and the GDPR module leaves the registration form and the cookie gate broken.

Extension Configuration

This module's own section holds two fields, both under Stores > Configuration > Magebit > Klaviyo.

SMS phone validation

Regions where a telephone number is accepted for Klaviyo SMS subscribe flows. Align these with Klaviyo's own SMS availability.

FieldDefaultDescription
Sms subscription enablednone stored, reads as NoMaster switch for every SMS flow this module adds.
Allowed countriesUS, CAISO country codes used when validating phone numbers for SMS subscription at checkout, on the account page, and in the newsletter form.

The 22 selectable countries are US, CA, GB, AU, NZ, AT, BE, DK, FI, FR, DE, HU, IE, IT, LU, NL, NO, PL, PT, ES, SE, CH.

Klaviyo SMS phone validation configuration, with only US and Canada selected

Only United States and Canada are highlighted in the screenshot above. That is the shipped default, and every other country in the list is inactive until it is selected.

Two defaults to set before testing

Sms subscription enabled has no stored default. The dropdown renders showing Yes while the effective value is still false, so open the section, set it explicitly, and save before testing.

Allowed countries defaults to US, CA only. Until it is changed, every European phone number fails validation, which hides the SMS checkbox at checkout and on the account pages and makes the order-placement subscribe skip. All of it happens silently, with no message anywhere.

Clearing Allowed countries does not turn validation off. An empty list makes phone normalisation return nothing, which disables SMS subscription completely. The field also has no dependency on the master switch, so it stays visible and editable while SMS is off.

Settings read from the official extension

These are not in this module's section, but SMS will not work without them.

SettingLocationWhy it matters
EnableKlaviyo > GeneralMaster switch. Everything in this module checks it.
Public API KeyKlaviyo > GeneralGates the onsite JavaScript block.
Private API KeyKlaviyo > GeneralEvery consent read and write uses it. Without it, consent reads fail and the store treats every customer as unsubscribed.
SMS consent is activeKlaviyo > Consent at CheckoutHides the checkout SMS box and makes the registration and account flows do nothing when off.
SMS list IDKlaviyo > Consent at CheckoutRequired. An unset list ID sends an empty list to Klaviyo and the subscribe job fails.
SMS consent textKlaviyo > Consent at CheckoutSupplies the checkbox label text on the storefront.
Email consent is activeKlaviyo > Consent at CheckoutGates the newsletter checkbox at checkout.

When a subscribe call to Klaviyo fails, for a missing list ID or any other reason, the error is written to the Klaviyo log and the storefront still reports success. Verify a real signup lands in Klaviyo rather than trusting the confirmation on screen.

Once the three switches above are on, an SMS opt-in appears at four touchpoints.

Hyvä Checkout

A Magewire component renders up to two checkboxes, each shown only when the matching consent-at-checkout setting is active and the customer is not already subscribed:

  • A newsletter checkbox labelled "I want to receive newsletter to stay up to date".
  • An SMS checkbox labelled with the consent text from the Klaviyo configuration.

The SMS box is shown based on the billing telephone, falling back to the shipping telephone. If no phone has been entered yet the box is shown anyway, so a shopper can tick it and then enter a number that fails validation, in which case the subscribe silently skips at order placement.

Ticking a box saves the flag onto the quote immediately, not at order placement. The call to Klaviyo happens when the order is submitted. A shopper who ticks the box and abandons leaves the flag on the quote with nothing sent.

The component registers itself into the Hyvä Checkout component registry. Where it appears in the checkout depends on the project's Hyvä Checkout configuration, since the module registers the block but does not place it.

Create Account page

An SMS checkbox labelled with the Klaviyo consent text. Ticking it reveals a required Telephone field.

The phone field is a plain text input. The module builds and passes a filtered country list to it, but the template ignores it, so there is no country or flag selector on this page despite the machinery being loaded for one.

My Account, Newsletter Subscriptions

A card titled "Subscription option" with a General Subscription checkbox and, behind the same gates, the SMS checkbox.

Viewing these pages changes subscription state

Rendering the My Account newsletter page and opening a customer in the admin both call Klaviyo live and then write Magento's newsletter subscription to match what Klaviyo reports. Loading the page is not a read-only operation.

Admin customer page

The stock Newsletter tab is hidden and a Newsletter Subscription toggle is added to the Account Information fieldset instead. Opening a customer calls Klaviyo to read their current consent, and saving pushes newsletter state and SMS consent back.

Saving the customer from this form also writes their SMS consent, and it writes it as off. On a store with an active SMS list, avoid editing customers in the admin, or confirm the form carries an SMS field before rolling this out.

Phone validation

Numbers are stripped to digits and normalised to an E.164 value with a leading +, then checked against a pattern for each enabled country. Eight countries also accept a local format; the rest accept the international form only.

CountriesAccepted input
US, CAA 10-digit national number, normalised to +1, or an 11-digit number already starting with 1
GB, AU, NZ, FR, NLA local number with a leading 0, rewritten to the country code, or the international form
ESThe +34 form only
AT, BE, DK, DE, FI, HU, IE, IT, LU, NO, PL, PT, SE, CHThe international form only: country code followed by the digit count that country uses

A number that matches none of the enabled countries is rejected, which hides the SMS opt-in rather than reporting an error. The country list is resolved at store scope, so it can differ per store view.

Abandoned cart merge or replace

Klaviyo's abandoned-cart emails link back to a saved quote. The official extension merges that quote into the visitor's current cart without asking. This module replaces that behaviour.

When the visitor's cart already has items, they land on the cart page with a modal titled "The shopping cart isn't empty" offering Merge, Replace, and Cancel. When the cart is empty the merge happens straight away, as before.

It also adds an eligibility check the official code does not have: a quote that is inactive or already has a reserved order ID is rejected, so a link from an old email cannot resurrect a cart belonging to a placed order.

/magebitReclaim/checkout/mergeCarts changes the cart on a plain GET with no form key, and Replace empties it. The link is built root-relative, so verify the merge prompt on a store that uses store codes in URLs or a subdirectory install.

From 1.0.9 the module replaces Klaviyo's onsite initialisation templates. The window.klaviyo queue stub still loads immediately, so calls made early are not lost, but the klaviyo.js script tag is held back until the visitor has consented to the cookie group containing __kla_id. Customer identification runs off Magento's private content load.

This reads the cookie consent configuration published by the Magebit GDPR module. That dependency is not declared in composer.json.

The gate has two failure modes:

  • Fails open - If Magento's cookie restriction mode is off, or the GDPR module is absent, Klaviyo loads immediately with no consent check.
  • Fails closed - If no consent group lists __kla_id, the script never loads and all onsite tracking and Klaviyo forms stop working with no error. Check that a cookie group actually declares __kla_id.

Limits to check before going live

  • Editing a customer in the admin turns their SMS consent off - The save pushes an unsubscribe to Klaviyo, so avoid admin customer edits on a store with an active SMS list.
  • The SMS master switch has no stored default - It reads as off while the dropdown displays Yes, so it has to be set and saved explicitly.
  • Allowed countries ships as US and CA - Every other country fails phone validation, which hides the opt-in and skips the subscribe, silently.
  • Failed subscribe calls are invisible to the shopper - They are written to the Klaviyo log while the storefront reports success.
  • Every consent read is a synchronous API call - There is no queue and no cache, and the calls happen on admin pages and at order placement.
  • The cart merge endpoint changes the cart on a GET request - It takes no form key, so anything that follows the link, a prefetching browser or a link scanner included, can merge or empty the shopper's cart.

Developer notes

What it changes in the official extension

Five classes are replaced by preference, each subclassing the original rather than rewriting it:

ReplacedPurpose of the override
KlaviyoV3Sdk\KlaviyoV3ApiAdds SMS subscribe and unsubscribe, and requests subscription state on profile lookup
Helper\DataAdds the SMS subscribe, unsubscribe, and consent-read helpers
Observer\SaveOrderMarketingConsentPerforms the subscribe at order submission
Controller\Checkout\CartRedirects to the cart page with the merge prompt instead of merging silently
Magento\Ui\Component\Layout\TabsHides the admin Newsletter tab

The bundled KlaviyoV3Sdk/ directory is not a vendored copy of Klaviyo's SDK. It is one subclass of the official API class. The load-bearing change is that profile lookups request the subscriptions field, which the official version does not, and every consent read in the module depends on it.

The Klaviyo API revision the calls carry comes from the official extension's own constant and is not pinned here, so a 4.4.x patch can change it.

Data

Two nullable boolean columns are added to the quote table, general_subscription and sms_subscription, both defaulting to false and exposed as cart extension attributes. No new tables are created.

An is_sms_subscribed extension attribute is declared on the customer, but nothing stores it: there is no column, no EAV attribute, and no data patch. The only source of truth for a customer's SMS consent is a live Klaviyo API call, so do not treat it as a queryable or reportable customer field.

Performance

Every consent read and write is a synchronous HTTPS call inside the request, retried up to three times with a pause between attempts. There is no cron job, no queue, and no cache. These calls happen on admin customer form load, admin customer save, My Account newsletter render, registration submit, newsletter form submit, and order placement.

CSP

The analytics initialisation template is CSP-safe. The SMS subscription, cart merge, and registration templates are not, so those pages fail under a strict Content Security Policy.

Routes

URLMethodAuth
/magebitReclaim/checkout/mergeCartsGETnone, no form key
/reclaim/checkout/cartGETnone, served by the preference on the official controller

Api/SmsPhoneValidationInterface is an internal service contract. There is no webapi.xml, so it is not exposed over REST or GraphQL.

Troubleshooting

The SMS checkbox never appears

Work through the gates in order:

  1. Stores > Configuration > Magebit > Klaviyo and set Sms subscription enabled to Yes, then save. It has no stored default.
  2. Add the shopper's country to Allowed countries. The default is US and CA only.
  3. Stores > Configuration > Klaviyo > General and confirm Enable is Yes and both API keys are set.
  4. Stores > Configuration > Klaviyo > Consent at Checkout and confirm SMS consent is active and has a list ID.
  5. Confirm the customer is not already subscribed, since the box hides for subscribers.

Signups report success but nothing arrives in Klaviyo

Check the Klaviyo log. Failed subscribe calls are logged and swallowed, and the storefront reports success either way. A missing SMS list ID is the most common cause.

Every customer shows as unsubscribed

Consent state is read live using the private API key. If that key is missing or wrong, the read fails, the UI reports unsubscribed, and a save re-subscribes them. Confirm the private key first.

An admin customer save pushes an unsubscribe to Klaviyo, so avoid editing customers in the admin on a store with an active SMS list.

Klaviyo tracking stopped after upgrading to 1.0.9

The onsite script now waits for cookie consent. Confirm a cookie consent group declares the __kla_id cookie. If none does, the script never loads.

SMS, cart merge or registration pages fail under a strict Content Security Policy

Those three templates are not CSP-safe, so a restrictive policy blocks their scripts and the pages fail with no visible error. Check the browser console for CSP violations.

The merge prompt does not work on this store

The merge link is built root-relative, so confirm it resolves on a store that uses store codes in URLs or is installed under a subdirectory.

The checkout checkboxes do not render

The block is registered into the Hyvä Checkout component registry but not placed by this module. Confirm the project's Hyvä Checkout configuration renders subscription-checkboxes, and that Hyvä Checkout and Magewire are installed, since neither is declared in composer.json.