Developer docs
Page, track, identify
The snippet boots a global executen. Auto-track sends Page Viewed. You add identity after login, commerce events when they happen, and consent when the banner says so.
The client
executen.page(name?);
executen.track(event, properties?);
executen.identify(userId, traits?);
executen.decide(page?);
executen.consent.update({ analytics, personalization, marketing });
executen.init({ writeKey, ingestionUrl?, edgeUrl?, autoTrack?, country?, device? });
page
Sends the canonical Page Viewed event. The snippet already calls this on load. Call it again on SPA route changes, then decide() so experiences can follow the new path.
executen.page(); // uses document.title
executen.page("Summer oak table"); // optional name
executen.decide(location.pathname); // ask the edge what to show
identify
After login or checkout, pass a stable user id. Anonymous id lives in localStorage and a first-party cookie (executen_anonymous_id). Identify merges that anonymous profile onto the known customer. Strong identifiers only — we do not pretend “same browser, same person.”
executen.identify("user_123", { name: "Ada" });
track
Custom names must match [A-Za-z][A-Za-z0-9 _./:-]{0,63}. Prefer the canonical shop names below so Tracking Health and funnels light up without aliases.
executen.track("Order Completed", {
value: 154,
currency: "USD",
sku: "oak-table",
quantity: 1
});
Canonical events
The SDK emits the first six on its own. Commerce events you send — or Shopify / Woo map from paid orders.
| Event | Who sends it | Funnel / job |
|---|---|---|
| Page Viewed | SDK on load, or executen.page() | Visitors. Funnel step 1. |
| Identify | executen.identify() | Merge anonymous → person. |
| Element Clicked | SDK heatmap (consent) | Editor overlay. Empty until clicks exist. |
| Scroll Depth | SDK at 25 / 50 / 75 / 100% | Depth buckets, once each. |
| Experience Exposed | SDK after decide() applies a change | |
| Experiment Assigned | SDK for control and treatment | |
| Product Viewed | You, or a theme hook | |
| Product Added | You, on add-to-cart | |
| Checkout Started | You, when checkout begins | |
| Order Completed | You, or Shopify/Woo paid webhook |
Funnel aliases
If you already speak Segment or GA4, we recognise these names. We never invent a missing stage.
| Stage | Canonical | Also accepted |
|---|---|---|
| Page view | Page Viewed | Page View, page_viewed, page_view, page |
| Product view | Product Viewed | Product View, product_viewed, view_item |
| Add to cart | Product Added | Add to Cart, add_to_cart, cart_add |
| Checkout | Checkout Started | checkout_started, begin_checkout |
| Purchase | Order Completed | Purchase, order_completed, purchase |
Allowed properties
Browser properties are allow-listed. Unknown keys are dropped. utm_* is allowed. Amounts from the snippet should use value (and currency). Shopify paid orders arrive with total. Analytics will read value, total, revenue, amount, or order_total if they made it through.
| Key | Use it for |
|---|---|
| name, title | Page or product name |
| value, currency | Money from the snippet |
| sku, product_id, variant_id, category, quantity | Catalog |
| selector, x, y, path, depth, url, page | Heatmap / context |
| userId | Identify only |
| experience_id, experience_version | Set by the SDK |
| experiment_id, experiment_arm, experiment_version | Set by the SDK |
| utm_* | Campaign |
A shop in four calls
executen.track("Product Viewed", {
sku: "oak-table",
category: "Furniture",
value: 154,
currency: "USD"
});
executen.track("Product Added", {
sku: "oak-table",
quantity: 1,
value: 154,
currency: "USD"
});
executen.track("Checkout Started", {
value: 154,
currency: "USD"
});
executen.identify("user_123", { name: "Ada" });
executen.track("Order Completed", {
value: 154,
currency: "USD",
sku: "oak-table"
});
SPA / client-side routing
function onRoute(path) {
executen.page(document.title);
executen.decide(path);
}
window.addEventListener("popstate", () => onRoute(location.pathname));
// Call onRoute() from your router after each navigation.
Apps — same contract, no native SDK
There is no iOS or Android SDK to install. POST the same shape the browser sends. Keep a stable anonymousId per install; call identify after login.
{
"writeKey": "pk_live_…",
"event": "Order Completed",
"anonymousId": "anon_device_…",
"userId": "user_123",
"sessionId": "ses_…",
"timestamp": "2026-10-04T00:12:00.000Z",
"properties": { "value": 154, "currency": "USD", "sku": "oak-table" },
"context": {
"page": { "path": "/checkout/thanks" },
"locale": "en-US",
"device": { "type": "mobile" }
}
}
Consent
Default after boot: analytics true, personalization true, marketing false. track() no-ops when analytics is false. decide() no-ops when personalization is false and still marks the page ready so markers do not stay hidden.
executen.consent.update({ analytics: false, personalization: false });
// later, after the banner:
executen.consent.update({ analytics: true, personalization: true });
executen.page();
executen.decide();
What never goes live from the client
- Publish, approve, pause, rollback, SQL.
- Workspace ids as auth.
- Arbitrary JavaScript on the merchant theme.
- Preview traffic into live analytics (previewToken path is display-only).