Skip to main content

Web Pixel Extensions

Web Pixels listen for customer-events (page_viewed, product_viewed, product_added_to_cart, checkout_started, checkout_completed). They are how analytics and marketing apps observe customer behavior without direct DOM access to the store theme.

Runtime sandbox

Pixels run in a sandboxed runtime with no access to the host page — depending on where they run:
  • Storefront — the pixel runs in a dedicated Web Worker (created from a Blob via new Worker(url)). A Worker has no DOM, no cookies and no document at all; the pixel script is loaded with importScripts.
  • React checkout / cart / account — the pixel runs in an srcdoc iframe loaded with sandbox="allow-scripts" (no allow-same-origin).
Either way the pixel cannot:
  • Read or write cookies on the parent page.
  • Read or write localStorage / sessionStorage on the parent.
  • Make same-origin requests against the store.
  • Read the parent DOM.
It can make cross-origin requests to your analytics service. Event delivery is via postMessage from the host to the pixel runtime — your pixel subscribes to a stable event API documented below.

Manifest

Declare Web Pixels under extensions.webPixels[] in your app’s app.json (same manifest file as every other extension type):
*One of scriptSrc or inlineScript is required.

Pixel runtime API

The sandbox exposes two globals: register and analytics. Both work identically on both runtimes (storefront Worker and checkout iframe). register hands your callback an object with the event bus and the merchant’s saved settings for this pixel:
Semantics:
  • The callback runs synchronously, before the host delivers any event — subscriptions made inside it never miss an event.
  • If the callback throws, the error is caught and the sandbox keeps running. On the iframe runtime the host also receives an LMS_PIXEL_ERROR message with reason: 'register-callback-threw'.
  • Calling register with a non-function is a safe no-op.
  • Calling register more than once is allowed; each callback runs once.

analytics.subscribe(eventName, cb) — top level

Subscribing at the top level of your script also works, and remains fully supported. It has no access to configuration:
There is no default export, no positional settings/init argument and no browser proxy — the sandbox is a Web Worker (storefront) or a same-origin-blocked iframe (checkout), so no host-page storage exists.

Event catalogue

Payloads use the stable customer-event shapes documented above, so a pixel can subscribe to event names and read the listed payload fields without further translation.

Installation

The pixel JS + manifest are deployed by the install pipeline (POST /api/apps/install-extensions), a server-to-server endpoint gated by the platform’s internal API key — it is not called directly from the browser with a merchant token (the only browser-accepted path is a fromCatalog: true catalog copy). The storefront’s pixel loader picks the pixel up on the next page load. Uninstall removes the pixel directory and the storefront stops sending events to it on the next render.

Best practices

  • Prefer register. It is the only way to read the merchant’s settings from inside the sandbox. Reach for top-level analytics.subscribe only when your pixel needs no configuration.
  • Don’t bake merchant config into scriptSrc. One script is served to every store that installs your app; per-store values belong in settings and arrive as configuration.
  • Use navigator.sendBeacon over fetch. The pixel runtime may be torn down during navigation — sendBeacon survives.
  • Don’t expect cookies to persist between visits. The pixel runs in a Worker (storefront) or a sandboxed iframe (checkout) with no host-page storage.