Conversion Tracking & Custom Scripts
Two isolated injection surfaces for merchant scripts: site-wide Liquid layouts and order-confirmation React route. CSP nonce auto-injected. Multi-script snippets (async loader + inline config) both execute.
Two Surfaces
- Site-wide (
/admin/settings→ Custom Scripts):analytics_config.custom_head_script/custom_body_script. Fires on every Liquid storefront page via{{ shop.custom_head_script }}inlayouts/theme.liquid. - Order Confirmation (
/admin/preferences→ Checkout Scripts):analytics_config.order_status_head_script/order_status_body_script. Fires exclusively on the Reactstorefront.checkout.successroute, gated by(!error && order).
Storage
JSONB column shops.analytics_config. Site-wide and order-status keys are disjoint — they no longer collide (previous bug: last save won).
CSP Nonce
injectScriptNonce() in frontend/liquid-service.mjs patches every <script> tag in the merchant HTML with the per-request CSP nonce. Merchants do not add nonces manually.
Multi-Script Support
executeMerchantHTML (React) clones every <script> node via document.createElement('script') — the HTML-spec path for reliable execution of dynamically-inserted scripts. Paste a Google Ads snippet with two script tags and both execute.
Platform Governance
PATCH /platform/analytics — super-admin enables/disables custom scripts globally. Merchant editor shows a hint when disabled.
Theme Integration
Add to layouts/theme.liquid:
{{ shop.custom_head_script }}
</head>
<body>
{{ shop.custom_body_script }}Boilerplate and Minimal already include these. Clarity/Linen/Mono follow in v1.23.