GTM integration
How to load @usesophi/sophi-web-object (the storefront event-tracking SDK) through Google Tag Manager, including recommended split and all-in-GTM configurations.
Use this page when you load @usesophi/sophi-web-object (the browser data-layer / analytics SDK) through Google Tag Manager. It is not the chat widget: for @usesophi/sophi-web-sdk (SophiWidget), see SDK GTM integration.
Prerequisites
- Google Tag Manager is installed on your site.
- Tags that load Sophi fire only when your privacy / consent rules allow (for example Google Consent Mode analytics_storage granted, or an equivalent you use).
window.sophi_object.config.apiKeyis available beforesophi.min.jsruns, unless you use the all-in-GTM variant below.
Recommended split (apps and SPAs)
For most modern storefronts, keep data and API keys in your application and use GTM only to inject the script:
| Responsibility | Where |
|---|---|
window.sophi_object — config (and optionally userId, debug, …), page, product, basket, listing, transaction, user | Your site / SPA, updated when consent allows |
Loading sophi.min.js from jsDelivr | GTM (Custom HTML tag, consent-gated) |
This avoids duplicating commerce payloads in GTM, supports multi-brand API keys in code, and matches the pattern described in our integration patterns.
GTM variable (easy upgrades)
Create a Constant variable in GTM, for example:
| Variable name | Type | Value |
|---|---|---|
Sophi Web Object script URL | Constant | https://cdn.jsdelivr.net/npm/@usesophi/sophi-web-object@x.y.z/dist/sophi.min.js |
Replace x.y.z with a pinned semver for production. When you upgrade the SDK, change this one variable and publish the container—no need to edit multiple tags.
@latest is convenient for development. In production, pin a version so a new npm release cannot change behaviour until you deliberately update the Constant.
Two triggers, one tag
Visitors may already have granted analytics consent when the page loads, or they may accept cookies during the session. Attach the same “load Sophi script” tag to both cases:
- Consent on first paint — For example a Consent Initialization trigger (or your CMP’s equivalent) that fires when analytics consent is already granted for this page view.
- Consent granted mid-session — For example a Custom Event trigger when your banner pushes a consent update to
dataLayer, withanalytics === true(names depend on your implementation).
Both triggers should run the identical Custom HTML (below) so sophi.min.js loads exactly once when consent becomes true, whether that was before or after load.
Example: Consent Mode + dataLayer (illustrative)
If you mirror Google Consent Mode and push cookie_consent_updated when the user saves preferences:
- Variable: Data Layer Variable reading
cookie_consent.analytics(or your field name). - Trigger A: Consent Initialization — All Pages, with condition analytics_storage granted (or your CMP’s mapping).
- Trigger B: Custom Event
cookie_consent_updated, with condition DLV equalstrue.
Adapt names and conditions to your CMP; the important part is covering both initial and delayed consent.
Custom HTML tag (script only)
When your application already sets window.sophi_object.config (and other keys) before or when the tag fires:
<script src="{{Sophi Web Object script URL}}" async></script>Use the exact variable name you defined in GTM (the {{...}} placeholder must match).
If the script might fire more than once during navigation tests, you can guard with a small check (optional):
<script>
if (!window.__sophiWebObjectLoaded) {
window.__sophiWebObjectLoaded = true;
var s = document.createElement('script');
s.src = '{{Sophi Web Object script URL}}';
s.async = true;
document.head.appendChild(s);
}
</script>The SDK itself waits for DOMContentLoaded before bootstrapping; async on the script tag is supported.
All-in-GTM variant (simple sites)
For static sites you can set minimal config in the same tag that loads the bundle. Prefer Option A (separate script src); Option B inlines the bundle and increases container size.
Option A — load from jsDelivr
- Create a Custom HTML tag.
- Ensure
window.sophi_objectexists with at leastconfig.apiKey, then load the script:
<script>
window.sophi_object = window.sophi_object || {};
window.sophi_object.config = Object.assign({}, window.sophi_object.config, {
apiKey: 'YOUR_API_KEY'
});
</script>
<script src="https://cdn.jsdelivr.net/npm/@usesophi/sophi-web-object@x.y.z/dist/sophi.min.js" async></script>- Fire the tag only when analytics consent is granted (same consent principles as above). Pin
x.y.zin production.
Option B — inline sophi.min.js
- Paste the full contents of
sophi.min.jsfrom the published package after the smallwindow.sophi_objectconfig block. - Use the same triggers as Option A.
Inlining removes one CDN round-trip at the cost of a large GTM payload.
If window.sophi_object is defined in an earlier tag, define it there and keep this tag’s HTML to only the script src line (recommended pattern in Recommended split).
For consent-sensitive fields (UserObject, PII), see Configuration and Types reference.
QA checklist
- With consent denied, confirm no Sophi tracking requests (or script load, depending on your triggers).
- After consent granted, confirm
sophi.min.jsloads from your pinned URL. - Confirm
window.sophi_object.confighas a validapiKeybefore or when the script runs (unless you rely on the SDK’s post-start updates—see SophiTracker). - Navigate the site and verify events align with default mappings (for example
page→page_view,product→product_view).
Related
- Integration guide — choose GTM vs script vs npm
- Configuration
- Window object layer
- Integration patterns
- Event types