What GTM Changes — and What It Doesn't
If your team already routes every tag through Google Tag Manager, ClickStream fits that workflow without giving up its core property: the pixel still loads from your own domain. GTM is just the delivery mechanism for a tiny script tag. The script's src points at https://t.yourdomain.com/sdk.js — a subdomain you control, CNAME'd to ClickStream — so the SDK bundle, the event traffic, and the visitor cookie all stay first-party even though the tag itself was published from a GTM container.
That distinction matters. A typical GTM-loaded analytics pixel is a third-party script from the vendor's domain. This google tag manager analytics install is different: GTM injects a first-party loader. The rest of this guide walks through the whole setup — the DNS step, the Custom HTML tag, triggers, consent, and verification.
Before You Start
- A ClickStream account at einstein.clickstream.com with at least one site created. The free Hobby tier works — see plans for what each tier includes.
- An API key (
cs_live_…orcs_test_…) from the dashboard. The key is domain-gated, so pasting it into a public GTM container is safe by design — here's why a stolen analytics key is useless. - A GTM container with publish rights on the site you're instrumenting.
- DNS access for your domain, for the one-time CNAME step below.
Step 1: Point a CNAME at ClickStream
Every ClickStream install runs through a first-party tracking domain — there is no vendor-hosted fallback. Add this record in your DNS provider:
| Field | Value |
|---|---|
| Type | CNAME |
| Name | t (or analytics, data — your choice) |
| Target | feynman.clickstream.com (copy the dashboard value if it differs) |
| TTL | Auto or 3600 |
| Proxy (Cloudflare) | DNS-only — gray cloud, not orange |
Then register the hostname in the dashboard under Sites → Your Site → Tracking Domain. The control plane polls DNS every 10 seconds for up to 5 minutes; once the CNAME resolves, SSL provisioning starts automatically and typically completes within 60 seconds. When the hostname shows Active, you're ready for the GTM side.
Honest caveat: CNAME propagation across resolvers can take anywhere from 1 to 60 minutes depending on your DNS provider. Everything after this step is fast; this step is the one you can't rush.
Step 2: Create the Custom HTML Tag
In Google Tag Manager: Tags → New → Tag Configuration → Custom HTML. Name it something findable — "ClickStream — First-Party Pixel".
Important — GTM needs a different snippet than a hand-pasted tag. The standard loader finds its own element with document.currentScript, which is null for a script that a tag manager injects at runtime — so the plain script tag pasted into a Custom HTML tag will silently do nothing. Under GTM, set the configuration on window and load the bundle directly:
<script>
window.ClickstreamConfig = {
key: "cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
endpoint: "https://t.example.com"
};
</script>
<script async src="https://t.example.com/sdk/bundle.js"></script>
Replace t.example.com (both places) with the tracking domain you verified in Step 1, and the key with your site's API key from the dashboard. Two GTM-specific notes:
endpointis required here. Thewindow.ClickstreamConfigpath can't auto-derive it from the script origin the way the normal tag does — leave it out and events quietly fall back to the shared collector, which costs you the first-party install you just set up DNS for.- Leave "Support document.write" unchecked. The bundle doesn't use it, and
asynccarries through — the tag never blocks rendering.
What loads is deliberately small: a 344-byte loader that pulls the ~56.5 KB gzipped tracker bundle from your own subdomain. The full anatomy is in The 344-Byte Pixel.
Step 3: Pick a Trigger (One Is Enough)
Attach the built-in All Pages page-view trigger. If you want the pixel to fire as early as GTM allows, use the Initialization — All Pages trigger instead; either works.
If your site is a single-page app, resist the reflex to add a History Change trigger. The ClickStream SDK handles SPA route changes internally — one tag, fired once per real page load, captures every client-side navigation after it. Duplicate triggers just re-evaluate the tag — the SDK detects the duplicate instance, tears the old one down cleanly (flushing its pending events first), and replaces it — but there's no reason to make it do that work.
Step 4: Consent Settings
You have two gates available, and they compose:
- GTM Consent Mode. If your CMP feeds Google Consent Mode, open the tag's Advanced Settings → Consent Settings and require
analytics_storagebefore the tag fires. The script then simply never loads for visitors who haven't consented. - ClickStream's own consent state. Independently of GTM, every event the SDK emits is gated by a per-category consent state (
analytics,identity,marketing). On opt-in compliance presets likegdpr_strict, the SDK collects nothing until consent is granted. It auto-detects OneTrust, Cookiebot, and Osano and mirrors their decisions — or any other CMP can bridge in withwindow.cs?.setConsent({ analytics: true, marketing: true, thirdParty: false }).
Practical upshot: you can fire the tag on All Pages and let the SDK's consent state hold events until your banner resolves, or gate the tag in GTM and load nothing pre-consent. Both are compliant paths; the SDK-side enforcement is covered in depth in GDPR as Cron Jobs.
Step 5: Preview, Publish, Verify
Use GTM's Preview mode first: connect Tag Assistant to your site and confirm the ClickStream tag shows as fired on a page load. Then Submit → Publish the container version.
Verification is immediate:
- Open the dashboard, pick your site, and watch the Live Sessions panel.
- Load any page of your site in an incognito tab. A session should appear within 1–2 seconds.
If nothing arrives after 30 seconds:
- Open DevTools → Network and filter for your tracking domain. You want 200s on
/sdk.jsand/v1/events. A 403 means the page's origin doesn't match the domains configured for your key — check Allowed Domains in the dashboard (wildcards like*.example.comare supported). - Confirm the
data-keyin the tag matches the key shown in the dashboard. - Re-check DNS:
dig +short t.example.comshould answer withfeynman.clickstream.com. - Confirm the tag actually fired — a consent gate in GTM that never resolves to granted will silently keep the tag out of the page.
The full troubleshooting matrix — including the npm-based install via @clickstreamhq/sdk for teams that would rather skip GTM entirely — lives on the install page.
Why First-Party Beats a GTM-Loaded Third-Party Pixel
Most tags in a GTM container load from the vendor's domain and identify visitors with JavaScript-set cookies. Safari's ITP caps those JS-set cookies at 7 days — which quietly resets a returning Safari visitor into a "new" visitor every week. ClickStream's identity cookie is set server-side, via Set-Cookie headers from your own CNAME'd subdomain, so it persists at the browser's long-term maximum of roughly 400 days. The mechanics and the measurement consequences are laid out in First-Party Cookie Persistence.
Beyond cookie lifetime, first-party routing means collection happens on a hostname you control: it's easier for your security team to review and allow-list, and the domain reputation stays with you rather than a multi-tenant analytics vendor. And once events are flowing, they're scored — 26 behavioral models classify intent, frustration, and bot traffic in real time, readable from page code through the Signals API. Billing counts human pageviews only, so the bot traffic GTM happily serves tags to never shows up on your invoice.
One honest tradeoff in the other direction: routing through GTM adds a dependency. If a content blocker blocks GTM itself, every tag inside the container — ClickStream included — stays out of the page. The direct script-tag install on the install page doesn't inherit that dependency. If GTM is your team's standard, that tradeoff is usually acceptable; just know it exists.
How Long Does This Actually Take?
Broken down honestly: the CNAME record is a two-minute edit, but propagation across resolvers takes 1–60 minutes depending on your provider. Dashboard verification polls for up to 5 minutes once the record resolves, and SSL typically completes within 60 seconds after that. The GTM side — tag, trigger, consent settings, preview, publish — is a few minutes of clicking. So: minutes of work, with DNS propagation as the one wait you don't control. Events appear in Live Sessions within seconds of the container going live.
From there, the interesting work starts — reading the visitor's intent and frustration scores from page code and acting on them. Getting Started with the Signals API is the next step.