|
| 1 | +# Shopify Integration |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Instrument your Shopify store with Datadog Real User Monitoring using the Datadog RUM Shopify bundle. One bundle covers both surfaces of a Shopify store: |
| 6 | + |
| 7 | +- **Storefront pages** (`/`, `/products/*`, `/collections/*`, etc.) — added via a Theme Liquid snippet. Full RUM feature set: views, resources, long tasks, user interactions, errors, and Session Replay. |
| 8 | +- **Checkout pages** (`/checkouts/*`, `/checkout`) — added via a Custom Pixel. Shopify deprecated `checkout.liquid` in August 2024, so checkout pages cannot be reached by theme edits at all; a [Web Pixel][5] running in a sandboxed iframe is the only mechanism that can observe them. |
| 9 | + |
| 10 | +Use both deployment paths together for full-funnel coverage. |
| 11 | + |
| 12 | +## Setup |
| 13 | + |
| 14 | +### Prerequisites |
| 15 | + |
| 16 | +Before you begin, gather the following Datadog RUM values: |
| 17 | + |
| 18 | +- A Datadog RUM Application ID |
| 19 | +- A Datadog RUM Client Token |
| 20 | +- A Datadog site, such as `datadoghq.com` |
| 21 | + |
| 22 | +You can get those values in Datadog under **Digital Experience > Real User Monitoring > Manage Applications > Set Up Manually**. |
| 23 | + |
| 24 | +You'll also need: |
| 25 | + |
| 26 | +- Admin access to your Shopify store (**Settings** and **Online Store > Themes**). |
| 27 | +- For the Custom Pixel path: access to **Settings > Customer events** in Shopify Admin. |
| 28 | + |
| 29 | +### Installation and Configuration |
| 30 | + |
| 31 | +#### Theme Liquid Setup |
| 32 | + |
| 33 | +Use this path to cover storefront pages (product, collection, cart, home). |
| 34 | + |
| 35 | +##### Steps |
| 36 | + |
| 37 | +1. In Shopify Admin, go to **Online Store > Themes**. |
| 38 | +2. On your live theme, click the **⋮** menu, then **Edit code**. |
| 39 | +3. Open `layout/theme.liquid`. |
| 40 | +4. Paste the following snippet right before the closing `</head>` tag, replacing the placeholder values with your Datadog RUM configuration: |
| 41 | + |
| 42 | + ```html |
| 43 | + <script> |
| 44 | + (function (h, o, u, n, d) { |
| 45 | + h = h[d] = h[d] || { q: [], onReady: function (c) { h.q.push(c) } } |
| 46 | + d = o.createElement(u); d.async = 1; d.src = n |
| 47 | + d.crossOrigin = 'anonymous' |
| 48 | + n = o.getElementsByTagName(u)[0]; n.parentNode.insertBefore(d, n) |
| 49 | + })( |
| 50 | + window, |
| 51 | + document, |
| 52 | + 'script', |
| 53 | + 'https://www.datadoghq-browser-agent.com/{{< region-param key="dd_datacenter_lowercase" code="true" >}}/v7/datadog-rum-shopify.js', |
| 54 | + 'DD_RUM' |
| 55 | + ); |
| 56 | +
|
| 57 | + DD_RUM.onReady(function () { |
| 58 | + DD_RUM.init({ |
| 59 | + applicationId: '<YOUR_DATADOG_APPLICATION_ID>', |
| 60 | + clientToken: '<YOUR_DATADOG_CLIENT_TOKEN>', |
| 61 | + site: '{{< region-param key="dd_site" code="true" >}}', |
| 62 | + service: '<YOUR_SERVICE_NAME>', |
| 63 | + env: '<YOUR_ENV_NAME>', |
| 64 | + version: '1.0.0', |
| 65 | + sessionSampleRate: 100, |
| 66 | + sessionReplaySampleRate: 100, |
| 67 | + trackUserInteractions: true, |
| 68 | + trackResources: true, |
| 69 | + trackLongTasks: true, |
| 70 | + defaultPrivacyLevel: 'mask-user-input', |
| 71 | + }) |
| 72 | + DD_RUM.startSessionReplayRecording() |
| 73 | + }) |
| 74 | + </script> |
| 75 | + ``` |
| 76 | + |
| 77 | +5. Save the file. |
| 78 | + |
| 79 | +##### Out-of-the-box functionality |
| 80 | + |
| 81 | +`DD_RUM.init()` here behaves exactly like the regular [`@datadog/browser-rum`][6] package. You get: |
| 82 | + |
| 83 | +- Automatic view tracking as visitors navigate storefront pages. |
| 84 | +- Web Vitals, resource timing, long tasks, and automatic click tracking. |
| 85 | +- Session Replay recording. |
| 86 | +- Runtime error tracking (`window.onerror`, `unhandledrejection`). |
| 87 | + |
| 88 | +##### Limitations |
| 89 | + |
| 90 | +- **No checkout coverage.** Checkout, Thank You / Order Status, and Customer Account pages are fully controlled by Shopify and cannot be reached by any Liquid edit. Use the [Custom Pixel Setup](#custom-pixel-setup) below for that funnel. |
| 91 | +- Theme code changes require re-editing `theme.liquid` on every theme update or theme switch — there's no install-once mechanism on this path. |
| 92 | + |
| 93 | +#### Custom Pixel Setup |
| 94 | + |
| 95 | +Use this path to cover checkout pages (`/checkouts/*`, `/checkout`). It runs inside a Shopify **Custom Pixel**, a sandboxed `<iframe sandbox="allow-scripts allow-forms">` that Shopify injects to observe checkout events — the only place JavaScript can run on checkout pages at all. |
| 96 | + |
| 97 | +##### Steps |
| 98 | + |
| 99 | +1. In Shopify Admin, go to **Settings > Customer events**. |
| 100 | +2. Click **Add custom pixel**, give it a name, and open its code editor. |
| 101 | +3. Paste the following snippet, replacing the placeholder values with your Datadog RUM configuration: |
| 102 | + |
| 103 | + ```javascript |
| 104 | + (function (h, o, u, n, d) { |
| 105 | + h = h[d] = h[d] || { q: [], onReady: function (c) { h.q.push(c) } } |
| 106 | + d = o.createElement(u); d.src = n |
| 107 | + d.crossOrigin = 'anonymous' |
| 108 | + n = o.getElementsByTagName(u)[0]; n.parentNode.insertBefore(d, n) |
| 109 | + })( |
| 110 | + window, |
| 111 | + document, |
| 112 | + 'script', |
| 113 | + 'https://www.datadoghq-browser-agent.com/{{< region-param key="dd_datacenter_lowercase" code="true" >}}/v7/datadog-rum-shopify.js', |
| 114 | + 'DD_RUM' |
| 115 | + ) |
| 116 | + |
| 117 | + DD_RUM.onReady(function () { |
| 118 | + DD_RUM.init({ |
| 119 | + applicationId: '<YOUR_DATADOG_APPLICATION_ID>', |
| 120 | + clientToken: '<YOUR_DATADOG_CLIENT_TOKEN>', |
| 121 | + site: '{{< region-param key="dd_site" code="true" >}}', |
| 122 | + service: '<YOUR_SERVICE_NAME>', |
| 123 | + env: '<YOUR_ENV_NAME>', |
| 124 | + version: '1.0.0', |
| 125 | + sessionSampleRate: 100, |
| 126 | + shopifyAnalytics: analytics, // the Custom Pixel's `analytics` global — see note below |
| 127 | + }) |
| 128 | + }) |
| 129 | + ``` |
| 130 | + |
| 131 | +4. Save the pixel, then set its required consent category under **Settings** for the pixel (e.g. Analytics) to match your store's privacy configuration — the bundle does not add its own consent gate; it defers entirely to whatever the merchant declares in Shopify's Pixel Manager. |
| 132 | + |
| 133 | +**Note on `shopifyAnalytics`:** `analytics` is a bare global that only exists inside a Custom Pixel's code editor scope — pass it straight through as shown. |
| 134 | + |
| 135 | +##### Out-of-the-box functionality |
| 136 | + |
| 137 | +Once `shopifyAnalytics` is set, the bundle automatically: |
| 138 | + |
| 139 | +- Starts a RUM view on each checkout step (bound to Shopify's `page_viewed` standard event). |
| 140 | +- Converts Shopify's `clicked` DOM event into a RUM click action, with correct position data. |
| 141 | +- Converts Shopify's `ui_extension_errored` event (a checkout UI extension crashing) into a RUM error, tagged with the failing extension's name, target, and type. |
| 142 | +- Continues the storefront session: the sandbox shares the top frame's cookie jar, so if a visitor already has a `_dd_s` session cookie from the Theme Liquid snippet, checkout events land in that same session. |
| 143 | +- Is a no-op in effect on storefront pages: Shopify fires the pixel's `page_viewed` event on every page, not just checkout, but the bundle only calls `startView` for checkout-path URLs — so no duplicate session or duplicate view is created alongside the Theme Liquid instance. |
| 144 | + |
| 145 | +##### Instrumenting extra Shopify events |
| 146 | + |
| 147 | +The snippet above only wires up the three events the bundle binds automatically. Shopify's [standard events][7] cover the full checkout funnel — `checkout_started`, `checkout_contact_info_submitted`, `checkout_shipping_info_submitted`, `payment_info_submitted`, `checkout_completed`, `alert_displayed` and more. Subscribe to any of them yourself, using `DD_RUM.onReady()` to queue calls made before the SDK has finished loading: |
| 148 | + |
| 149 | +```javascript |
| 150 | +analytics.subscribe('checkout_completed', (event) => { |
| 151 | + const checkout = event.data.checkout |
| 152 | + DD_RUM.onReady(() => |
| 153 | + DD_RUM.addAction('checkout_completed', { |
| 154 | + orderId: checkout?.order?.id, |
| 155 | + totalPrice: checkout?.totalPrice, |
| 156 | + }) |
| 157 | + ) |
| 158 | +}) |
| 159 | + |
| 160 | +analytics.subscribe('checkout_contact_info_submitted', (event) => { |
| 161 | + const checkout = event.data.checkout |
| 162 | + DD_RUM.onReady(() => { |
| 163 | + if (checkout?.email) { |
| 164 | + DD_RUM.setUser({ email: checkout.email }) // capture the guest email here |
| 165 | + } |
| 166 | + DD_RUM.addAction('checkout_contact_info_submitted', { checkoutToken: checkout?.token }) |
| 167 | + }) |
| 168 | +}) |
| 169 | +``` |
| 170 | +
|
| 171 | +You can also emit and subscribe to [custom events][8] the same way. |
| 172 | +
|
| 173 | +##### Limitations |
| 174 | +
|
| 175 | +- **No Session Replay or Profiling.** The sandbox iframe has no real checkout DOM — recording or profiling it would capture nothing meaningful. Both are force-disabled regardless of what you pass to `init()`. |
| 176 | +- **No Web Vitals, resource timing, or runtime JS errors.** `PerformanceObserver`, `fetch`/`XMLHttpRequest` instrumentation, and `window.onerror`/`unhandledrejection` all observe the sandbox iframe itself, not the checkout page's main thread — that boundary can't be crossed from a Custom Pixel. |
| 177 | +- **Click actions are partial.** Only Shopify's basic `clicked` DOM event is available (no automatic DOM click listener, since there's no real DOM to listen on): |
| 178 | + - Emitted for inputs, links, and buttons — not for empty space or plain text. |
| 179 | + - Not emitted for payment card fields (card number, expiration, CVC, name on card) or the "Sign in" link. |
| 180 | + - Not emitted for a second click on a field that's already focused. |
| 181 | +- **Advanced DOM Events are unavailable.** Shopify restricts that API to apps approved for it in the Partner Dashboard — a bar that doesn't apply to (and can't be met by) a Custom Pixel. |
| 182 | +- **Checkout-path detection is regex-based**, matching `/checkouts?/` with an optional two-letter locale prefix (e.g. `/en/checkout`). A store with a non-standard checkout URL structure won't currently have an override flag to adjust it. |
| 183 | +
|
| 184 | +### Validate the Installation |
| 185 | +
|
| 186 | +#### Storefront (Theme Liquid) |
| 187 | +
|
| 188 | +1. Open your storefront in a new browser session with developer tools open. |
| 189 | +2. Confirm `datadog-rum-shopify.js` loads successfully (Network tab) and `window.DD_RUM` is defined (Console tab). |
| 190 | +3. Navigate between a few storefront pages (home, a product, the cart). |
| 191 | +4. In Datadog, open **Digital Experience > RUM Explorer**, filter by your configured `service` and `env`. |
| 192 | +5. Confirm view events appear for each page you visited, and that a Session Replay recording is available for the session. |
| 193 | +
|
| 194 | +#### Checkout (Custom Pixel) |
| 195 | +
|
| 196 | +1. Place a test order (or go far enough into checkout to trigger `checkout_started`) on a storefront that has the Custom Pixel configured. |
| 197 | +2. In the RUM Explorer, filter by the same `service`/`env` and look for views whose URL is under `/checkouts/`. |
| 198 | +3. Confirm the view URL matches the real checkout URL (not a sandbox/iframe address) — this validates the `page_viewed`-driven `startView` binding is working. |
| 199 | +4. Click a few checkout fields/buttons during the test run, then confirm corresponding click actions appear on the view. |
| 200 | +5. If you added extra event subscriptions (see [Instrumenting extra Shopify events](#instrumenting-extra-shopify-events)), confirm their custom actions or user attributes (e.g. `checkout_completed`, the identified email from `setUser`) show up on the same view/session. |
| 201 | +6. If nothing appears: check the pixel's consent category under **Settings > Customer events** — in opt-in (GDPR-style) regions, Shopify won't load the sandbox at all until the visitor consents, so no events fire until then. |
| 202 | + |
| 203 | +## Troubleshooting |
| 204 | + |
| 205 | +Need help? Contact [Datadog Support][3]. |
| 206 | + |
| 207 | +[1]: https://shopify.dev/docs/api/web-pixels-api |
| 208 | +[2]: https://docs.datadoghq.com/help/ |
| 209 | +[3]: https://docs.datadoghq.com/help/ |
| 210 | +[4]: https://docs.datadoghq.com/getting_started/site/#access-the-datadog-site |
| 211 | +[5]: https://shopify.dev/docs/api/web-pixels-api |
| 212 | +[6]: https://github.com/DataDog/browser-sdk/blob/main/packages/rum/README.md |
| 213 | +[7]: https://shopify.dev/docs/api/web-pixels-api/standard-events |
| 214 | +[8]: https://shopify.dev/docs/api/web-pixels-api/emitting-data |
0 commit comments