Installing the Pixel
Copy and paste the following Liquid Code into your layouts/theme.liquid file before any JavaScript that utilizes the Layers API. Replace {{ PUT YOUR TRACKING API KEY HERE}} with the Tracking API Key found under Settings > API Access.
{% comment %} Start layers click tracking {% endcomment %}
< script id = "layers-config" type = "application/json" >
{
"apiToken": " {{ PUT YOUR TRACKING API KEY HERE }} "
}
</ script >
{% comment %} theme-check-disable {% endcomment %}
< script id = "layers-session-context" type = "application/json" >
{
"productsInCart": [
{%- assign first_item = true - %}
{%- for item in cart . items - %}
{%- if item . product_id and item . variant_id - %}
{%- unless first_item - %} , {%- endunless -%}
{
"title": {{ item . product . title | json }} ,
"price": {{ item . final_line_price | divided_by: item . quantity | divided_by: 100.0 | json }} ,
"type": {{ item . product . type | json }} ,
"productId": {{ item . product_id | json }} ,
"variantId": {{ item . variant_id | json }} ,
"options": {
{%- if item . product . options_with_values . size > 0 - %}
{%- for option in item . product . options_with_values - %}
{%- assign option_index = forloop . index0 - %}
{%- assign option_value = item . variant . options [option_index] - %}
{{ option . name | json }} : {{ option_value | json }}
{%- unless forloop . last - %} , {%- endunless -%}
{%- endfor -%}
{%- endif -%}
}
}
{%- assign first_item = false - %}
{%- endif -%}
{%- endfor -%}
],
"productsPurchased": [
{%- assign sorted_orders = customer . orders | sort: "created_at" - %}
{%- assign first_purchased = true - %}
{%- for order in sorted_orders - %}
{%- for line_item in order . line_items - %}
{%- if line_item . product_id and line_item . variant_id - %}
{%- unless first_purchased - %} , {%- endunless -%}
{
"title": {{ line_item . title | json }} ,
"price": {{ line_item . final_line_price | divided_by: line_item . quantity | divided_by: 100.0 | json }} ,
"type": {{ line_item . product . type | json }} ,
"productId": {{ line_item . product_id | json }} ,
"variantId": {{ line_item . variant_id | json }} ,
"options": {
{%- if line_item . product . options_with_values . size > 0 - %}
{%- for option in line_item . product . options_with_values - %}
{%- assign option_index = forloop . index0 - %}
{%- assign option_value = line_item . variant . options [option_index] - %}
{{ option . name | json }} : {{ option_value | json }}
{%- unless forloop . last - %} , {%- endunless -%}
{%- endfor -%}
{%- endif -%}
}
}
{%- assign first_purchased = false - %}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
],
"customer": {
"signedIn": {%- if customer - %} true {%- else -%} false {%- endif -%} ,
"returning": {%- if customer . orders_count > 0 - %} true {%- else -%} false {%- endif -%} ,
"numberOfOrders": {{ customer . orders_count | default: 0 | json }} ,
"averageOrderValue": {%- if customer . orders_count > 0 - %}
{{ customer . total_spent | divided_by: customer . orders_count | divided_by: 100.0 | json }}
{%- else -%} 0 {%- endif -%} ,
"daysBetweenOrders": {%- assign sorted_orders = customer . orders | sort: "created_at" - %}
{%- assign prev_date = nil - %}
{%- assign total_diff = 0 - %}
{%- assign count = 0 - %}
{%- for order in sorted_orders - %}
{%- if prev_date - %}
{%- assign diff = order . created_at | date: "%s" | minus: prev_date | abs - %}
{%- assign total_diff = total_diff | plus: diff - %}
{%- assign count = count | plus: 1 - %}
{%- endif -%}
{%- assign prev_date = order . created_at | date: "%s" - %}
{%- endfor -%}
{%- if count > 0 - %}{{ total_diff | divided_by: count | divided_by: 86400 | json }}{%- else -%} null {%- endif -%} ,
"daysSinceLastOrder": {%- if customer . last_order - %}
{%- assign now = 'now' | date: '%s' - %}
{%- assign last = customer . last_order . created_at | date: '%s' - %}
{{ now | minus: last | divided_by: 86400 | json }}
{%- else -%} null {%- endif -%} ,
"daysSinceOldestOrder": {%- if sorted_orders . size > 0 - %}
{%- assign now = 'now' | date: '%s' - %}
{%- assign oldest = sorted_orders . first . created_at | date: '%s' - %}
{{ now | minus: oldest | divided_by: 86400 | json }}
{%- else -%} null {%- endif -%} ,
"totalSpent": {{ customer . total_spent | divided_by: 100.0 | json }}
}
}
</ script >
< link rel = "dns-prefetch" href = "https://cl.uselayers.com" >
{% comment %} theme-check-enable {% endcomment %}
< script src = "https://cdn.uselayers.com/pixel/layers-tracking-pixel.js" type = "module" ></ script >
{% comment %} End layers click tracking {% endcomment %}
Please
contact support if you have any questions or could use some assistance installing the Storefront Pixel.
Events Captured by Pixel
Collection View
Product Click
Product View
Product Add to Cart
For information on forwarding these events to third-party analytics services like Microsoft Clarity and Blotout.io, see Third-Party Integrations .
Line Item Properties
A Line Item Property with the key _layers_attribution is appended to some add to cart forms. The value corresponds to the identifier of the request made using the Search or Browse API where the customer last saw the product before adding it to their cart. This property is only added if the customer clicked on products from the Search or Browse APIs.
Order Attributes
Layers reads the following order-level note attributes to associate purchase events with browsing sessions:
Attribute Description _em_session_idThe Edgemesh session ID. When present, this is used as the primary session identifier for purchase attribution. _em_device_idThe Edgemesh device ID. Stored for attribution context. _em_nav_idThe Edgemesh navigation ID. Stored for attribution context. _layers_session_idThe Layers session ID. Used as a fallback when Edgemesh attributes are not present.
When both _em_session_id and _layers_session_id are present on an order, _em_session_id takes priority.
If you have the Edgemesh integration enabled, the Edgemesh attributes are automatically appended to orders. No additional configuration is required.
The Storefront Pixel includes a built-in debug panel called the Search Inspector that helps developers and QA teams verify tracking behavior, inspect API requests, and submit search quality feedback — all without leaving the storefront.
Add the _layers_debug_menu=true query parameter to any page URL on your storefront:
https://your-store.myshopify.com?_layers_debug_menu=true
Once activated, the debug mode persists for the entire browser session (using sessionStorage). To deactivate it, use _layers_debug_menu=false.
Panel Tabs
The Search Inspector has four tabs:
Searches — Displays all API requests intercepted by the pixel (search, browse, similar, blocks). Each request shows the URL, request type, timestamp, and can be expanded to reveal the full request/response bodies, workflow steps (like spelling corrections, query expansions, and applied rules), metadata, and search IDs.
Activity — Shows all tracking events captured by the pixel (product clicks, views, add-to-carts, etc.) with their status (queued or sent) and full event payloads.
Feedback — A form for submitting search quality feedback directly to Layers. The search reference ID is automatically populated from the most recent search. Includes a rating (good/poor results) and optional text feedback.
Rules — Displays the current session state including experiment info, active search query, collection context, result counts, and attribution tokens. Also shows any merchandising rules that were applied to recent requests.
Panel Features
Draggable and resizable — The panel can be moved anywhere on screen and resized. Position is persisted across page navigations within the session.
Dockable — Collapses to a small handle on the left or right edge of the viewport. Click the handle to expand.
Shadow DOM isolation — The panel renders inside a closed Shadow DOM, so it does not interfere with the storefront’s styles or layout.
The Search Inspector is dynamically loaded only when debug mode is active. It adds no overhead to the storefront when not in use.
Misc
Browser Specs Supported
Back/Forward Cache.
Speculation Rules.
SPA Navigation.