Google Tag Manager
If you use GTM, your dataLayer is usually already populated to some degree, so setting up GTM answers two questions at once: how to load the tag, and which tracking mode to use.
Decision Matrix
| dataLayer empty / unreliable | dataLayer complete | dataLayer present but incomplete | |
|---|---|---|---|
| Can write Custom HTML | 4.1 native | 4.2 datalayer mode | 4.3 hybrid mode |
| Sandboxed template only | 4.4, no mode line | 4.4 + trackingMode: 'datalayer' | 4.4 + trackingMode: 'hybrid' |
If you also need custom events, window.b2mConfig is required regardless of mode — see Custom Events.
4.1 Custom HTML — Native
Your dataLayer isn't used for analytics (GTM is only for tag management here). Let the SDK collect everything itself:
<script
src="https://edge.b2metric.com/b2m-web-sdk.js"
data-api-key="YOUR_API_KEY"></script>
4.2 Custom HTML — dataLayer Only
<script
src="https://edge.b2metric.com/b2m-web-sdk.js"
data-api-key="YOUR_API_KEY"
data-tracking-mode="datalayer"
data-event-groups="core,ecommerce"></script>
4.3 Custom HTML — Hybrid
<script
src="https://edge.b2metric.com/b2m-web-sdk.js"
data-api-key="YOUR_API_KEY"
data-tracking-mode="hybrid"
data-event-groups="core,ecommerce,search"></script>
4.4 Sandboxed Custom Template
GTM's sandboxed custom template can't render a script tag with data-* attributes. Use a config object instead — including the mode:
<script>
window.b2mConfig = {
apiKey: 'API_KEY',
trackingMode: 'hybrid',
// 'datalayer' | 'hybrid' — omit this line entirely for native
eventGroups: {
core: { enabled: true },
ecommerce: { enabled: true },
search: { enabled: true }
}
};
</script>
<script src="https://edge.b2metric.com/b2m-web-sdk.js"></script>
Attribute-to-config mapping
If you need to translate an existing script-tag setup to a b2mConfig object:
| Script-tag attribute | b2mConfig key |
|---|---|
data-api-key | apiKey |
data-tracking-mode | trackingMode |
data-event-groups="core,ecommerce" | eventGroups: { core: {enabled:true}, ecommerce: {enabled:true} } |
data-require-consent="true" | requireConsent: true |
data-ab-mode="true" | abMode: true |
data-cookie-domain | cookieDomain |
data-app-identifier | appIdentifier |
data-chat-integration-id | chatIntegrationId |
data-session-replay="true" | enableSessionReplay: true |
4.5 GTM + Custom Events (+ Mode + Chat) — Full Example
<script>
window.b2mConfig = {
apiKey: 'API_KEY',
trackingMode: 'hybrid',
requireConsent: true,
eventGroups: {
core: { enabled: true },
ecommerce: { enabled: true },
my_events: {
enabled: true,
events: ['quote_started', 'quote_completed', 'demo_requested'],
autoTrack: []
}
},
chatIntegrationId: 'INTEGRATION_ID',
chatApiKey: 'CHAT_API_KEY',
chatTenant: 'TENANT'
};
</script>
<script src="https://edge.b2metric.com/b2m-web-sdk.js"></script>
4.6 Trigger Selection
| Trigger | When to use it |
|---|---|
| All Pages (Page View) | Default choice — correct for most setups. |
| Initialization — All Pages | When the SDK needs to run as early as possible (e.g. A/B testing anti-flicker — see A/B Testing). |
| Consent Initialization | In a CMP-based setup where the SDK must load only after consent is resolved (see Consent Management). |
Attach the trigger to a single tag firing once per page — attaching the same SDK tag to more than one trigger loads it twice.
4.7 Ordering Rule
window.b2mConfig must be defined before the SDK script runs. Keeping the config block above the SDK tag inside the same Custom HTML tag (as in every example above) guarantees this. Don't split them across two separate GTM tags and rely on tag priority — the SDK reads config immediately, so a config tag that fires later is simply ignored.
4.8 Common Conflicts to Check For
- If the page already has a hardcoded tag with
data-api-key, awindow.b2mConfigblock from GTM is never read. Pick one integration path, not both. - If two tags on the page both carry
data-api-key, only the first one found is used — remove the duplicate rather than relying on load order. data-apiKey(wrong case) never starts the SDK — the attribute selector only looks fordata-api-key.
4.9 Verifying in GTM Preview
await window.b2mReady; // true
window.b2mWebSDK.config.trackingMode;
// 'native' | 'datalayer' | 'hybrid' — is this what you expected?
window.b2m.getEnabledEvents(); // are your event names listed?
Then trigger a dataLayer push and check the Network tab: the resulting event should reach the collector exactly once. If it appears twice, the mode is probably still set to native.