> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lemrock.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversion tracking on Shopify

> Install the Lemrock Pixel as a Shopify custom pixel, with no theme changes.

The Lemrock Pixel shows which Lemrock ads lead to sales in your store, so Lemrock can report your results and deliver more toward buyers. On Shopify, you install it as a custom pixel: one snippet pasted in your Shopify admin, with no theme changes.

You need your **pixel ID**. It looks like `lr_px_` followed by 22 characters. Your Lemrock contact gives it to you.

## 1. Add the pixel

1. In Shopify, go to **Settings > Customer events > Add custom pixel**. Name it `Lemrock`.
2. Under **Customer privacy**, set **Permission** to **Required** and tick **Marketing**. The pixel then only runs for visitors who accept marketing cookies.
3. Paste the snippet below in **Code** and replace `lr_px_...` with your pixel ID.
4. Click **Save**, then **Connect**.

```js theme={null}
const PIXEL_ID = "lr_px_...";
const VALIDATE_ONLY = false; // true while testing: events are checked, not recorded

const ENDPOINT = "https://api.lemrock.com/v1/browser/events";
const COOKIE = "lemrock_click";
const LRCLID = /^lr_clk_[A-Za-z0-9_-]{22}$/;

const cents = (money) => {
  if (!money || money.amount == null) return undefined;
  return Math.round(Number(money.amount) * 100);
};

const item = (variant, quantity) => ({
  id: String(variant?.product?.id ?? ""),
  name: variant?.product?.title,
  quantity,
  amount: cents(variant?.price),
  currency: variant?.price?.currencyCode,
});

const checkoutData = (checkout) => ({
  amount: cents(checkout.subtotalPrice),
  currency: checkout.currencyCode,
  contents: checkout.lineItems.map((line) => item(line.variant, line.quantity)),
});

async function sha256(text) {
  const bytes = new TextEncoder().encode(text);
  const hash = await crypto.subtle.digest("SHA-256", bytes);
  return Array.from(new Uint8Array(hash), (b) =>
    b.toString(16).padStart(2, "0"),
  ).join("");
}

async function send(eventType, eventId, event, data, user) {
  const lrclid = await browser.cookie.get(COOKIE);
  if (!lrclid && !user) return;

  fetch(ENDPOINT, {
    method: "POST",
    headers: { "content-type": "application/json" },
    keepalive: true,
    body: JSON.stringify({
      event_type: eventType,
      event_id: String(eventId),
      event_time_ms: Date.parse(event.timestamp) || Date.now(),
      lrclid: lrclid || undefined,
      user,
      source_url: event.context.document.location.href,
      pixel_id: PIXEL_ID,
      pixel_version: "shopify-1.0.0",
      data: { type: "contents", ...data },
      validate_only: VALIDATE_ONLY,
    }),
  });
}

analytics.subscribe("page_viewed", async (event) => {
  const url = new URL(event.context.document.location.href);
  const token = (url.searchParams.get("lrclid") || "").trim();
  if (LRCLID.test(token)) {
    await browser.cookie.set(
      `${COOKIE}=${token}; path=/; max-age=${90 * 86400}; SameSite=Lax; Secure`,
    );
  }
});

analytics.subscribe("product_viewed", (event) => {
  const variant = event.data.productVariant;
  send("contents_viewed", event.id, event, { contents: [item(variant, 1)] });
});

analytics.subscribe("product_added_to_cart", (event) => {
  const line = event.data.cartLine;
  send("items_added", event.id, event, {
    amount: cents(line.cost.totalAmount),
    currency: line.cost.totalAmount.currencyCode,
    contents: [item(line.merchandise, line.quantity)],
  });
});

analytics.subscribe("checkout_started", (event) => {
  send("checkout_started", event.id, event, checkoutData(event.data.checkout));
});

analytics.subscribe("checkout_completed", async (event) => {
  const checkout = event.data.checkout;
  const email = checkout.email?.trim().toLowerCase();
  const user = email ? { email_sha256: await sha256(email) } : undefined;
  send(
    "order_created",
    checkout.order?.id ?? event.id,
    event,
    checkoutData(checkout),
    user,
  );
});
```

* **Product IDs must match your catalog feed.** The snippet sends the Shopify product ID. If your feed uses variant IDs or SKUs, replace `variant?.product?.id` with `variant?.id` or `variant?.sku`.
* **The snippet sends the customer's email hashed, never in clear.** It's hashed in the browser before sending, so Lemrock never receives the address itself. Nothing to set up.

## 2. Check your setup

1. **Turn on test mode.** Set `VALIDATE_ONLY = true` and save.
2. **Simulate an ad click.** Open your store with `?lrclid=lr_clk_0000000000000000000000` added to the URL, and accept the cookie banner.
3. **Walk the funnel.** View a product, add it to the cart, and place a test order.
4. **Open your browser's developer tools**, tab **Network**, and filter on `browser/events`. Each step shows one request with status `202`.
5. **Turn test mode off.** Set `VALIDATE_ONLY = false` and save.

If something is wrong:

* **No request:** check the pixel is connected and the cookie banner was accepted. [Shopify Pixel Helper](https://help.shopify.com/en/manual/promoting-marketing/pixels/custom-pixels/testing) shows whether the pixel runs.
* **Status** `400`**:** the response names the field Lemrock refused.
* **A change doesn't show up at checkout:** a checkout keeps the pixel version it started with. Start a new checkout after saving.
* **Make sure your redirects keep** `lrclid` in the URL.

Your Lemrock contact can confirm events are arriving. Send them your pixel ID and the time of your test.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.