Anonymous visitors are not lost
Most people browse before they ever type an email address. The SDK keeps that history:- A visitor browses anonymously. Their events are held in their browser. The
SDK still pings the endpoint so the dashboard’s
lastUsedAtshows the snippet is alive, but nothing is stored server-side for an anonymous visitor - the server answersqueued: false. - The visitor signs in or reaches checkout. Your backend mints a short-lived
identity token, and your site calls
sequenzy.identify(email, token). - The held events are replayed against that contact at their original timestamps.
Step 1: Create a tracking key
In the dashboard, go to Settings → Integrations → Website tracking and create a key. Or from the terminal:Origin header. Identified events therefore also require a signed,
short-lived identity token minted by your backend.
A bare domain is read as
https. https://*.example.com covers subdomains at
any depth but not the apex, so list https://example.com separately if you
need both. Add your development origin (for example http://localhost:3000)
while you are wiring things up.Step 2: Install the snippet
Paste the snippet from the dashboard or CLI into every page. Its first script creates lightweight method stubs synchronously, so calls made while the SDK is still downloading are queued rather than lost:Install from npm
If your site has a JavaScript build, install the side-effect-free package and create the client explicitly:Step 3: Identify your visitors
Callidentify as early as your backend has authenticated someone - on sign-in,
and again at checkout. First mint a token from your backend using a secret API
key with commerce:write, automations:trigger, and subscribers:write (the
last one because minting can create the contact). Pass the same publishable
key that is in your snippet:
ttlHours accepts up to 720). Mint a fresh
one on each sign-in and at checkout rather than reaching for a long lifetime -
the token is a bearer proof, and a short expiry is what limits a leaked one.
Minting also establishes the email as a contact if it is not one yet, so
identified events always have a profile to land on. The contact is created
active with no list memberships and no automations triggered - enroll it
through your normal signup flows when you want more than event attribution.
Return only identityToken to that signed-in browser, then pass it with the
same normalized email:
reset() on sign-out so the next person using that browser starts clean:
Step 4: Track events
Each event has a convenience method:providerProductId is your own product id. Use the same value you push to the product catalog so recommendations and product blocks in emails resolve to the right item.
Cart abandonment needs the cart contents, so include
quantity on every cart
event. Without it, a recovery email cannot say what was left behind.When a cart disappears without telling us
The tracked cart is only as current as the events your site sends. Plenty of sites empty a cart without ever firing a removal: a session-scoped cart timing out, a reservation or inventory hold being released, the shopper finishing checkout on another device, or the snippet simply not loading on a page. So a tracked cart expires. AfterexpireAfterHours (default 72) with no
activity, the cart is dropped instead of being emailed about, and a later add
starts a fresh cart rather than merging into the old items. That is what stops
a recovery email from listing things the shopper no longer has.
Sites using the browser SDK currently always use the default expiry.
sequenzy shopify settings update --cart-expire-after-hours applies per
connected Shopify store only - it has no effect on SDK-tracked carts.
The cleanest fix is still to tell us directly - call
sequenzy.viewedCart({ ... }) with the current contents whenever your site
knows them, or fire removedFromCart when the cart empties. An explicit cart
view replaces the whole snapshot, so it corrects any drift in one call -
including sequenzy.viewedCart({ lineItems: [] }), which clears the tracked
cart so no abandonment email goes out for items the shopper no longer has.
Configuration
Extra attributes on the script tag:
The stored identity only applies while its identity token is also unexpired, so with the default 24-hour token the browser stays identified for at most a day after the last
identify call regardless of this setting. data-sequenzy-identity-ttl-days caps the window from the other side.
Lower data-sequenzy-identity-ttl-days on any site where one device is routinely shared between buyers rather than belonging to one of them - shared workstations, kiosks, in-store terminals, or any flow where people commonly buy on someone else’s behalf. A stored identity means “this browser was last used by this person”, not “this browser belongs to this person”, and a long window on a shared machine can attribute one person’s browsing to another.
Setting data-sequenzy-storage="off" disables the anonymous buffer as well, so visitors who identify later arrive with no prior history. Use it only where a consent policy requires it.
Server-side alternative
If your visitors are signed in, you do not need the browser at all. Post the same events from your backend with your secret API key:Managing keys
list_web_tracking_keys, get_web_tracking_key, create_web_tracking_key, update_web_tracking_key, and delete_web_tracking_key. See the MCP reference.
Revoking a key stops its events within about a minute while keeping the key value visible, so you can still find the matching snippet on your site. Delete it once the snippet is gone.
Troubleshooting
No events arriving. Check the key’slastUsedAt. If it is null, no event has successfully authenticated yet: the snippet may be missing or not loading, the page may not have fired an instrumented event, or the origin allowlist may be rejecting the request. Open your site’s network tab and look for a POST to /customer-events and its response status.
Events rejected with 403. Either the page’s origin is not on the key’s
allowlist, or an identified event has a missing, expired, or mismatched identity
token. Note that https://example.com and https://www.example.com are
different origins, as are http and https.
Anonymous history not appearing. Confirm token minting succeeds and
sequenzy.identify(email, identityToken) runs at sign-in and checkout. Without
a valid proof, events stay anonymous and are never attached to a contact.
Nothing works in an ad-blocked browser. Some blockers drop third-party tracking scripts. Those visitors are covered by the server-side approach above if they sign in.