Install the tag
The tag is one small script served from our own domain. Add it to your site and connect your consent controls where analytics requires permission.
The tag
<script defer src="https://app.datastated.com/ds.js?v=2026-09-10-consent"
data-site="acme.com" data-site-id="dst_YOUR_SITE_ID"></script>
This snippet starts tracking when it loads. Where analytics requires
consent, add data-require-consent before loading it and
connect your consent manager to ds("consent", "granted")
on acceptance and ds("consent", "denied") on withdrawal.
The gate waits without measurement until a grant; the attribute alone
does not display a consent prompt. Follow the
consent setup and withdrawal examples,
including the pre-load queue. Loading the script only after acceptance
is another option, but withdrawal still needs to stop the loaded tag.
Copy the exact snippet from your dashboard: the
data-site-id identifies the installation. Verify ownership
separately with the DNS TXT record or homepage meta tag shown on
Verify your domain.
Put the tracking tag in your <head>, or
anywhere in the page. It loads deferred, is 9,930 bytes minified (about 9.9 KB,
4,364 bytes or about 4.4 KB gzipped), and never throws into your page: if our endpoint is ever unreachable, your
site does not notice.
Upgrading an existing installation? Once this source release is
deployed, replace your snippet's src URL with
https://app.datastated.com/ds.js?v=2026-09-10-consent,
or the matching proxy URL from your dashboard. Keep
?v=2026-09-10-consent on proxy script URLs too. Browsers
may still have the old unversioned URL cached; deploying new code or
changing cache headers cannot clear those copies. The release response
uses public, max-age=300, must-revalidate. Check the
requested URL and loaded script before testing acceptance, withdrawal
and re-grant.
What it records
On each pageview the tag sends:
- the hostname and path of the page
- the referring URL, when the browser supplies one
- campaign tags on the link (
utm_source,utm_medium,utm_campaign,utm_term,utm_content), plus the indie shorthands?ref=,?via=, and?source=, which count as the source when no utm_source is present - an ad click identifier when present:
fbclid,gclid,gbraid,wbraid,gclsrc,ttclid,msclkid,twclidorli_fat_id - viewport width and the browser language
- a random visitor identifier from one first-party cookie
A click on a link to another domain sends the destination's host and path. When the tab is hidden or closed, the tag reports how long the page was visible, capped at 30 minutes. Goal calls send their names, optional values and properties; scroll goals send their names. Order calls can send an order id, value and currency.
If your site calls identify, the tag sends your user id,
any email you supply and up to ten properties. The server keeps the
email's SHA-256 hash rather than the address; user ids and properties
are stored as sent. With payment detection enabled, a Stripe success
page carrying a Checkout Session id also reports that id with the
visitor id. The server uses Stripe's payment record to determine the
amount and deduplicate the charge.
From the request itself the server keeps the browser, device and operating system parsed from the user agent, the country, region and city its edge reports, and a daily-salted hash of the address; the address itself is never stored. No fingerprinting, no raw IP addresses stored, no third-party scripts or cookies. The full detail lives in the privacy policy.
Framework notes
Every framework below comes down to the same thing: get the one script tag into the rendered HTML. Each one also has its own page in the sidebar with the exact steps.
- Plain HTML / static sites (Astro, Hugo, Jekyll, Eleventy): paste the tag into your base layout's
<head>. - Next.js: add it once in your root layout.
- React, Vue, Svelte single-page apps: paste the tag into
index.html. Route changes are tracked automatically, see below. - WordPress: paste the tag into your theme's header template, or use any "insert headers" plugin you already trust.
- Google Tag Manager: use a Custom HTML tag and connect it to your consent manager. Where analytics requires consent, use the tag's consent gate or a consent-dependent trigger, and handle withdrawal after loading. Follow the GTM guide and consent examples.
- Webflow, Framer and site builders: paste the tag into the site-wide custom code slot for the
<head>. - Shopify: skip the tag. The Shopify app installs its own pixel and brings the orders with it.
Single-page apps
The tag patches pushState and replaceState
and listens for popstate, so client-side route changes
count as pageviews on their own. No router integration, no manual
trackPageview() calls, and a repeated render of the same
path is not double-counted.
Apps that route on the URL fragment (/#/pricing) are the one exception: add data-hash-routing="true" to the tag and the hash becomes part of the path, with each hash change counted as a pageview.
Subdomains
Keep the same snippet on every subdomain and they count as one site:
the tag's data-site names the site, so a visit that
starts on blog.acme.com and buys on
app.acme.com is one visitor with one journey. Nothing to configure.
Several domains
A checkout on a different domain (pay.acme.io beside acme.com) is two visitors by default, because cookies do not cross domains. Add data-allowed-hosts to the tag on both sites, each naming the other, and a click between them carries the visitor id in the link, so the buyer on one side is the visitor on the other. The tag reference has the exact rules.
Privacy behaviour
Exclude your own visits
To browse your own site without counting yourself, open your browser console on your site and run:
localStorage.datastated_ignore = "true"That browser goes silent from the next page load: no cookie, no events, exactly as if a privacy signal were on. Repeat it per browser and per device you test from, and run delete localStorage.datastated_ignore to count again.
For rules that apply to everyone, your site's settings have an Exclusions section: excluded paths (exact, or /admin/* for everything under one) and excluded IP addresses. Matching visits are never recorded and never count toward your plan.
Verify it worked
Open your site in a normal browser window and click around. The setup checklist detects the first recorded pageview. Complete domain verification to open the analytics. If nothing arrives, walk the troubleshooting list.
Questions? Email us at hello@datastated.com.