Consent banners and the tag
Hold analytics until a visitor agrees, stop it when they withdraw, and connect those choices to your consent manager.
Who needs a banner
Without a consent gate, the tag starts when it loads and sets
_dsv, a first-party visitor cookie lasting 13 months.
Use the gate where consent is required. The setup below does not
decide your legal basis or replace advice about your site's use.
EU and UK. Do not assume that first-party analytics qualifies for an exemption. France's CNIL audience-measurement guidance has conditions on purpose, identifiers and retention. The UK's statistical-purposes exception does not permit tracking individual visitors. DataStated includes visitor journeys, payment attribution and three- or five-year history. Gate this use unless you have established that an exception applies.
Other regions. Your notice, legal basis and any opt-out duties depend on your use and your visitors. GPC and Do Not Track silence the tag; that behaviour is not a blanket compliance claim.
Three ways to gate the tag
1. Add the script only after consent. Call this function with the saved analytics choice, then again whenever it changes. It loads the script once, with the gate enabled, so a withdrawal while the download is pending still reaches the tag.
window.ds = window.ds || function () {
var call = Array.prototype.slice.call(arguments);
var queue = window.ds.q = window.ds.q || [];
if (call[0] === "consent" && (call[1] === "denied" || call[1] === "revoked")) {
queue.length = 0;
}
queue.push(call);
};
var dataStatedLoaded = false;
function setDataStatedConsent(granted) {
ds("consent", granted ? "granted" : "denied");
if (!granted || dataStatedLoaded) return;
dataStatedLoaded = true;
var script = document.createElement("script");
script.src = "https://app.datastated.com/ds.js?v=2026-09-10-consent";
script.defer = true;
script.setAttribute("data-site", "acme.com");
script.setAttribute("data-site-id", "dst_YOUR_SITE_ID");
script.setAttribute("data-require-consent", "");
document.head.appendChild(script);
}
2. Use your tag manager. A consent-aware trigger can
hold back a Custom HTML tag. It does not stop
a script that has already started. Keep data-require-consent
on the snippet and have your consent manager call
ds("consent", "denied") on withdrawal as well as
ds("consent", "granted") on acceptance.
3. Load the gated tag directly. This is the setup for the callbacks below. Put the queue stub before your consent manager can call it. The script may download before a choice; measurement waits.
<script>
window.ds = window.ds || function () {
var call = Array.prototype.slice.call(arguments);
var queue = window.ds.q = window.ds.q || [];
if (call[0] === "consent" && (call[1] === "denied" || call[1] === "revoked")) {
queue.length = 0;
}
queue.push(call);
};
</script>
<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"
data-require-consent></script>- Waiting: no cookie or storage reads or writes, no measurement requests, no listeners and no history patch. Goal, order and identify calls can queue in memory only during this initial wait.
- Granted:
ds("consent", "granted")starts measurement, replays that initial queue, and records the current page. Repeating the grant does not add another set of listeners. - Denied or revoked: either
ds("consent", "denied")ords("consent", "revoked")stops measurement. Pending calls are discarded, and calls made while denied or revoked are dropped, not saved for later. - Granted again: measurement starts with a fresh visitor id and the current page, without replaying activity from the denied period or adopting the old cross-domain id.
Withdrawal stops page, goal, order, identify, engagement, outbound,
scroll and checkout-return sends. It aborts pending fetches where
possible, cancels scheduled work, removes its listeners and observers,
and restores history methods and decorated links when it still owns
those changes. It clears accessible _dsv cookie scopes
and its active checkout-return session marker. It cannot recall a
request already sent or clear cookies on another origin; apply the
choice on every domain you measure. It does not erase server history.
A late identify response cannot restore the withdrawn visitor id.
window.datastated.visitorId is absent while inactive.
window.datastated.consent reports "waiting",
"granted", "denied" or "revoked";
an ungated tag starts at "n/a" and also accepts withdrawal.
GPC and Do Not Track take priority over any grant.
The tag keeps the choice in page memory only. Your consent manager must supply the saved choice on each page and every later change. Leave the tag waiting while the manager has no answer.
Consent manager callbacks
Use one integration, alongside the gated snippet above. The generic function is yours to wire into your manager's actual initialisation and saved-choice callbacks; it is not a consent-manager API.
function onAnalyticsChoice(granted) {
if (typeof granted !== "boolean") return;
ds("consent", granted ? "granted" : "denied");
}
Cookiebot: the
developer reference
documents the ready, accept and decline events and
consent.statistics. Register all three and check any
response already loaded.
function syncCookiebot() {
if (!window.Cookiebot || !Cookiebot.hasResponse) return;
ds("consent", Cookiebot.consent.statistics ? "granted" : "denied");
}
window.addEventListener("CookiebotOnConsentReady", syncCookiebot);
window.addEventListener("CookiebotOnAccept", syncCookiebot);
window.addEventListener("CookiebotOnDecline", function () {
ds("consent", "denied");
});
syncCookiebot();
OneTrust:
OneTrustGroupsUpdated
supplies the active groups on load and when preferences change.
Replace C0002 with your analytics group's id if different.
This listener does not replace an existing OptanonWrapper.
function syncOneTrust(groups) {
ds("consent", groups.indexOf("C0002") !== -1 ? "granted" : "denied");
}
window.addEventListener("OneTrustGroupsUpdated", function (event) {
syncOneTrust(event.detail);
});
if (typeof window.OnetrustActiveGroups === "string") {
syncOneTrust(window.OnetrustActiveGroups.split(","));
}
Klaro: add this service to your existing
configuration
before initialising Klaro. Keep onlyOnce false so the
callback can process both acceptance and withdrawal.
{
name: "datastated",
purposes: ["analytics"],
required: false,
optOut: false,
onlyOnce: false,
callback: function (consent) {
ds("consent", consent ? "granted" : "denied");
}
}
Osano: run this after its script has made
Osano.cm available. The
initialised and consent-saved events
supply the saved choice; the category-changed event can fire before
a visitor saves, so it is not used here.
function syncOsano(choices) {
if (!choices) return;
ds("consent", choices.ANALYTICS === "ACCEPT" ? "granted" : "denied");
}
Osano.cm.addEventListener("osano-cm-initialized", syncOsano);
Osano.cm.addEventListener("osano-cm-consent-saved", syncOsano);What a visitor can do without you
- Global Privacy Control or Do Not Track in the browser silences the tag; a consent grant cannot override it.
- Deleting
_dsvremoves that browser cookie. A later identify call or an allowed cross-domain link can associate a visitor again, so deletion is not a substitute for withdrawing consent. - A content blocker can block the tag or its measurement requests.
localStorage.datastated_ignore = "true"silences the tag when it starts. On a gated tag this key is not read before consent. It is intended for site owners excluding their own browser.
A clause for your cookie notice
Adapt this to your consent setup and the features you enable. Add any user ids, properties, payment matching or cross-domain linking you use, plus your retention period and a link to your consent controls.
Analytics. [Site name] uses DataStated to measure visits, goals and
orders after you accept analytics. Its first-party _dsv cookie holds
a random visitor id for up to 13 months, linking visits and the
orders or goals associated with them. A Stripe Checkout success page
can also use a sessionStorage marker to avoid repeating its report.
Raw IP addresses are not stored; a daily-salted hash is stored.
[Site name] controls this data and DataStated processes it on our
behalf. You can withdraw analytics consent through [consent controls].
Withdrawal stops the tag's measurement and clears its accessible
visitor cookie. It does not delete records already received.
GPC and Do Not Track silence the tag.
DataStated privacy policy: https://datastated.com/privacyWhat we do not claim
DataStated does not claim that no cookie banner is needed. The gate controls when this tag measures; your consent manager must present, remember and pass on the visitor's choices. See the privacy policy for the data collected.
Questions? Email us at hello@datastated.com.