Installing the app, how consent is handled, headless storefronts, and stores that check out on their own system. The headless and checkout sections are written for a developer.
The native Shopiens app is live on the Shopify App Store. Install it from apps.shopify.com/evarist, then open it in your admin: opening it sets Shopiens up on your store and draws your Live Store from your catalog, and while it does, the page asks you to turn on the Shopiens app embed in your theme editor. No code, and Shopify already knows your store, so there's no domain to type. By using the app you accept our Terms and Privacy policy.
The app turns on tracking through a theme app embed and a web pixel. If you already track this site with the snippet or a tag manager, remove it once the app is connected: the app replaces it. Orders are deduplicated by order ID across every source, so your revenue stays correct either way; but while both are running, page events and any goals you set up on the old tracking can be counted twice, so don't leave them side by side longer than the switchover.
The pixel also sends the product id with each product view, so that data is collected on a Shopify store with nothing to wire. Asking about individual products on top of it is still being finished. On a storefront you built yourself, see product ids.
With the app there is nothing to wire: the Shopiens app embed checks your store's Customer Privacy settings before it loads the tracker. That check needs your store's cookie banner to use Shopify's Customer Privacy API; without it, the tracker loads at page load. If you track a Shopify store with the snippet instead, switch on consent mode and Shopiens follows the same signal. A headless storefront carries it only if it loads Shopify's customer-privacy runtime; otherwise wire your consent tool's callbacks as on any other site.
Running Shopify behind a custom frontend instead of the Online Store (Hydrogen, or your own React/Next.js site)? A theme app embed can't reach those pages, so set up tracking manually with the two steps below. This works today, independent of the app. One exception: a Shopify-hosted customer or subscription portal (native Shopify customer accounts, or an app like Recharge's own portal) is still a Liquid Online Store page, so the app's theme app embed reaches it automatically even while your main storefront is headless, with no manual setup needed there.
Paste the tracking snippet into your storefront's root layout or template, on every page, not just one.
The common case, even with a custom frontend. Whenever you build or update the cart, give it a Shopify cart custom attribute named _shopiens holding the value of the visitor's _shopiens cookie, via the Storefront API's cartAttributesUpdate mutation (cartCreate takes the same list). That mutation replaces the cart's whole list of attributes, so send every attribute the cart should keep, yours included, and add _shopiens only while the cookie exists. Leaving it out removes it from the cart; an empty value would stay on the cart as an empty attribute.
mutation cartAttributesUpdate($cartId: ID!, $attributes: [AttributeInput!]!) {
cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {
cart { id }
userErrors { field message }
}
}
# variables: the cart's other attributes, then _shopiens while the cookie exists
{
"cartId": "YOUR_CART_ID",
"attributes": [
{ "key": "gift_note", "value": "AN_ATTRIBUTE_OF_YOUR_OWN" },
{ "key": "_shopiens", "value": "VALUE_OF_THE_SHOPIENS_COOKIE" }
]
}
To build that list in the browser, read the cookie itself, never session storage, where consent mode keeps the visitor id while it has no consent. Pass this the attributes the cart should keep, the cart's current ones for example: it drops any earlier _shopiens, and an _evarist left by an older version of this code, then adds the cookie's value back only if the cookie is still there.
function withShopiens(attributes) {
var kept = attributes.filter(function (a) { return a.key !== '_shopiens' && a.key !== '_evarist'; });
var cookie = document.cookie.match(/(?:^|;\s*)_shopiens=([^;]+)/);
return cookie ? kept.concat([{ key: '_shopiens', value: cookie[1] }]) : kept;
}
Set this up before? Your code reads the _evarist cookie and writes an _evarist attribute. The visitor id now lives in the _shopiens cookie, and _evarist is deleted, so switch both names to _shopiens: until you do, your orders reach Shopiens without the visitor id. Orders that already carry _evarist are still read.
It rides through to the order, so Shopiens attributes the purchase to the right visitor, no matter where checkout renders. This only carries the anonymous visitor id, never anything about the customer. If you run subscriptions (through Recharge or another subscription app on top of Shopify), setting this attribute is required, not just helpful: in most subscription setups it is carried forward from the first order onto future rebills, which is what lets Shopiens credit each rebill to the channel that originally acquired the subscriber instead of reporting it as unattributed revenue. How much of that carries through depends on the subscription app, so expect good coverage rather than every single rebill.
One timing note: the snippet loads asynchronously, so on a brand-new visit the _shopiens cookie may not exist yet when you first create the cart. Read the cookie fresh at every cart mutation rather than caching it at page load, and have the handler that sends the shopper to checkout write the attributes one last time, so a cart created before the snippet finished loading still picks the value up, and a cart whose cookie has since gone loses it. The value present at checkout is the one that rides through; a cart without it simply shows as an unattributed order, nothing breaks.
Consent. With consent mode, the cookie carries the visitor's choice: Shopiens sets no _shopiens cookie until you signal that the visitor consented, and deletes it when you signal a withdrawal. So nothing reaches the cart before consent, and the last write before checkout removes a value written before a withdrawal. Use consent mode if your storefront must set no identifying cookie before consent. Without it, the snippet sets its cookie as soon as it loads, so load the snippet only after the visitor accepts analytics; a withdrawal then leaves the cookie in place until you delete it.
If checkout isn't Shopify at all, install the snippet and tag your order-confirmation page as a goal, the same no-code flow as any other outcome: Track what matters.
If the amount varies per order, fire it from code with one JS call.