# Klaviyo for GoCommerce — Order and Cart Events Module

> Send a GoCommerce store’s orders and abandoned carts to Klaviyo as events, under the metric names Klaviyo’s flows know. The key, the delays, the limits.

- Canonical: https://kitcommerce.store/integrations/klaviyo/
- Last updated: 2026-09-25

---

Marketing

## Klaviyo events from GoCommerce

A Go package that tells Klaviyo what happens in the store, so its flows — abandoned cart, post-purchase, win-back — have something to run on. Placed, fulfilled, cancelled and refunded orders, each product ordered, and abandoned carts become events on the shopper’s Klaviyo profile. One key is required.

- **Marketing** module
- **5** settings
- **2** tests
- **1** API operation
- **ext/klaviyo**

### What it does

The package sends orders and abandoned carts “under the metric names Klaviyo’s own Shopify integration uses … so a flow built against those names works unchanged.” In the code that is order.created as Placed Order, with one Ordered Product per line; order.shipped as Fulfilled Order; order.cancelled as Cancelled Order; order.refunded as Refunded Order; and cart.abandoned as Started Checkout.

Each event carries the order number, status, payment status, currency, the lines with SKU, variant, quantity and prices, the tracking number where there is one, and a value in major units — the refunded amount, for a refund. The shopper’s profile is keyed on their email, with their name and phone when the order has them.

It posts to Klaviyo’s events API over Go’s standard library, one POST per event at API revision 2024-10-15. Delivery is best effort on purpose: a call that fails twice is logged and counted, never returned to the engine — a failed subscriber would make the engine re-run the whole event, re-issuing invoices and re-sending notifications for one marketing ping.

### Configuration

One setting is required: a private API key. Set it in Config — the reference binary’s -klaviyo flag reads KLAVIYO_PRIVATE_KEY — or on the Plugins screen, which wins.

*Klaviyo module settings — 5 settings, 1 required*

| Setting | Environment variable | Required | What it does |
| --- | --- | --- | --- |
| `PrivateKey` Private API key | `KLAVIYO_PRIVATE_KEY` | Yes | A pk\_… key with events:write and profiles:write. With it in Config the plugin starts switched on. |
| `PublicKey` Public API key | `KLAVIYO_PUBLIC_KEY` | No | The six-character key Klaviyo’s onsite tracking and signup forms use. Only the panel’s value reaches the storefront, through GET /api/plugins; Config.PublicKey is not read in this version. |
| `track_carts` Send abandoned carts as Started Checkout | — | No | On by default. Panel only; there is no Config field for it. |
| `BaseURL` | — | No | Overrides https://a.klaviyo.com, for tests. Go only. |
| `Client` | — | No | Replaces the HTTP client, which otherwise times out after 8 seconds. Go only. |

The module reads its Config struct, not the environment. The variable names are the ones the package’s own example or the reference binary uses; in your own `main()` you choose where each value comes from. Where a setting has a panel label, the admin’s settings drawer can hold it too, and a value typed there wins over Config.

### Setting it up

1. **Create a private key** — In Klaviyo, a private API key with events:write and profiles:write. Note the six-character public key too, if the storefront will run Klaviyo’s tracking.
2. **Install the module** — Pass klaviyo.New to gocommerce.New, as below, or start the reference binary with -klaviyo and KLAVIYO_PRIVATE_KEY set.
3. **Switch it on** — A private key in Config switches it on. Otherwise enable Klaviyo on the Plugins screen and paste the key there — and the public key, if the storefront needs it.
4. **Build flows on the metrics** — The six metrics arrive as orders and carts do. GET /api/admin/x/klaviyo/status shows whether it is on, how many events were sent and failed, and the last error.

main.go

```
import (
	"os"

	"github.com/itswadesh/gocommerce/core"
	"github.com/itswadesh/gocommerce/ext/klaviyo"
)

app, err := gocommerce.New(cfg, klaviyo.New(klaviyo.Config{
	PrivateKey: os.Getenv("KLAVIYO_PRIVATE_KEY"),
}))
```

The package doc has no example of its own; this is the reference binary’s, without the public key, which Config does not publish — type that on the Plugins screen. cfg is your gocommerce.Config. Import path `github.com/itswadesh/gocommerce/ext/klaviyo`.

### How it works

- **Subscribed, not polled**

  The module subscribes to order.\* and cart.abandoned on the engine’s event bus and sends as events are dispatched. Order events it has no metric for — edits, returns, reversals — are ignored.

- **De-duplicated by Klaviyo**

  Each event’s unique_id is the engine’s event id, plus the SKU for Ordered Product, so when the engine redelivers an event Klaviyo treats it as the one it already has.

- **Two tries, then a count**

  A failed POST is tried once more after a second. A second failure is logged, counted on the status route and dropped — never returned to the engine.

- **Values in major units**

  The engine holds minor units and Klaviyo wants 19.99, not 1999. The module converts with the currency’s own decimals — none for yen, three for dinar.

- **An email or nothing**

  An order or cart without an email is skipped, because the profile is keyed on it. Emails are lower-cased, and a name is split at its last space into first and last.

- **The public key, for the storefront**

  The panel’s public key is marked public, so a storefront can read it from GET /api/plugins and load Klaviyo’s onsite tracking and signup forms.

### What it does not do

Read these before an order depends on it. No store is known to run GoCommerce in production yet, so these come from the code, not from anyone’s experience.

- **Abandoned carts arrive late** — The engine marks a cart abandoned when it expires — 30 days after it was last changed, by default (Config.CartTTL). Started Checkout waits for that, so a timely abandoned-cart flow needs a shorter CartTTL.
- **Placed means created** — Placed Order fires when the order is created, before it is paid — cash-on-delivery orders included. Paid, delivered, edited and returned orders send no event.
- **Best effort** — An event that fails twice is dropped, not queued for later. The sent and failed counts live in memory and reset on restart.
- **No history, no consent** — Only events from the moment it is switched on; nothing is backfilled. It posts events and does not subscribe anyone to email or SMS marketing.
- **The cart token leaves the store** — Started Checkout carries the cart’s token as CartToken, for a recovery link. The engine treats that token as a credential for the basket, and it now sits in Klaviyo too.
- **Config.PublicKey is not read** — Only a public key typed on the Plugins screen reaches the storefront. The reference binary reads KLAVIYO_PUBLIC_KEY into Config, where nothing uses it.

FAQ

### Questions about the Klaviyo module

**Which Klaviyo metrics does it send?**

Placed Order when an order is created, with one Ordered Product per line; Fulfilled Order when it ships; Cancelled Order; Refunded Order, valued at the amount refunded; and Started Checkout when a cart is abandoned, if cart tracking is on.

**Why has my abandoned-cart flow not fired?**

A cart counts as abandoned only when it expires, which by default is 30 days after it was last changed, and only a cart with an email address is sent. Shorten the engine’s CartTTL if the flow should start sooner.

**Does it manage lists or consent?**

No. It creates and updates profiles only as part of events — email, name, phone. Lists, segments and marketing consent stay in Klaviyo and on the storefront.

**What happens if Klaviyo is unreachable?**

Each event is tried twice, a second apart. Then it is dropped, logged and counted, and the status route shows the last error. The order itself is unaffected.

**Is this a Klaviyo partnership?**

No. The module calls Klaviyo’s public API with a key you supply. Klaviyo does not endorse GoCommerce, and no store is known to run this module in production yet.

### Source

Everything on this page is read from [`ext/klaviyo`](https://github.com/itswadesh/gocommerce/tree/main/ext/klaviyo) in the GoCommerce repository, MIT licensed. When this page and the code disagree, the code is right and this page is out of date.Klaviyo is a trademark of its owner; this module talks to its public API and implies no endorsement. See [trademarks](https://kitcommerce.store/about/#trademarks).

- [ext/klaviyo on GitHub](https://github.com/itswadesh/gocommerce/tree/main/ext/klaviyo)
- [Klaviyo](https://www.klaviyo.com)
- [All GoCommerce modules](https://kitcommerce.store/integrations/)

### Try it against a store of your own

The one-command stack gives you GoCommerce’s API and admin on your own machine in minutes. Add this module to it and try it on test orders before a real one depends on it.

[Deploy in minutes](https://kitcommerce.store/#one-command) · [Read the module](https://github.com/itswadesh/gocommerce/tree/main/ext/klaviyo) · [All integrations](https://kitcommerce.store/integrations/)
