Consent and cookies
What the protection script does in cookie and cookieless mode, the one call that switches it, what your consent banner still controls, and how to verify it on your site.
Tapper runs from a single script on your website. This page covers what that script does in cookie mode and in cookieless mode, the one call that switches between them, what your consent banner's signals still control, and what you need to register in your consent management platform (CMP).
This page is documentation, not legal advice. How you classify Tapper and what consent you collect remain your decisions, together with your own advisers.
The consent call is case-sensitive. Use exactly "GRANTED" or
"DENIED", in uppercase. Any other spelling is ignored without an error,
so the visitor keeps the mode they were in.
Your integration does not change
Consent handling lives inside the script, not in your integration:
- The same Monitoring script and Conversion script tags stay exactly where they are.
- The snippet still calls
tapper.init(pk)with your public key. - You still report conversions with
window.tapper.push(...), unchanged.
One script, one integration - what it is allowed to do underneath depends on your cookie policy and on your own tapper.consent() call.
What Tapper does in each case
This is the one table for every consent case. Tapper has exactly two switches: tapper.consent("GRANTED") and tapper.consent("DENIED"). Nothing else your banner sends changes what Tapper does, with one exception: the Google Consent Mode signal fills the consent fields of the conversion upload to Google (ad_user_data and ad_personalization), and that is all it does.
| Case | Tapper cookies and storage | Monitoring | Matcher (on a page with no Tapper cookie) | Browser fingerprint (FingerprintJS and the probes) | gclid read from Google's click cookie (_gcl_aw/_gcl_dc) | Remarketing tags (Google, Meta, TikTok audiences) | Conversions |
|---|---|---|---|---|---|---|---|
tapper.consent("GRANTED") | Yes | On | Runs on the first page of the visit, before the Tapper cookie exists | Yes. If GRANTED arrives mid-visit, it runs once, for the same visitor | Yes | Yes | Recorded and attributed. On a page continued by the no-cookie matcher: recorded, never credited |
tapper.consent("DENIED") | No | On, cookieless | Runs on every page | No | No | No | Recorded with its order value, never credited and never uploaded to an ad platform, on every page: a page continued by the no-cookie matcher and a page-content rule's conversion (the rule's value) included. Invalid traffic monitoring continues cookieless |
| Consent first, before any Tapper call | No | On, cookieless | Runs on every page | No | No | No | Recorded with its order value, never credited and never uploaded to an ad platform: crediting a conversion captured without cookies is switched off today. A page-content rule's conversion (the rule's value) included |
| Region based, visitor inside the EEA or UK, before any Tapper call | No | On, cookieless | Runs on every page | No | No | No | Recorded with its order value, never credited and never uploaded to an ad platform: crediting a conversion captured without cookies is switched off today. A page-content rule's conversion (the rule's value) included |
| Region based, visitor outside the EEA and UK | Yes | On | Runs on the first page of the visit, before the Tapper cookie exists | Yes | Yes | Yes | Recorded and attributed. On a page continued by the no-cookie matcher: recorded, never credited |
| Cookie first, no Tapper call | Yes | On | Runs on the first page of the visit, before the Tapper cookie exists | Yes | Yes | Yes | Recorded and attributed. On a page continued by the no-cookie matcher: recorded, never credited |
| Google Consent Mode Reject (a banner signal) | Same as the mode's normal row | Same as the mode's normal row | Same as the mode's normal row | Same as the mode's normal row | Same as the mode's normal row | Same as the mode's normal row | Same as the mode's normal row. The upload to Google carries the Reject in its consent fields |
How the matcher works: on any page where Tapper holds no cookie of its own, including the first page of a visit and in every mode, Tapper tries to find the visitor before it creates a new visitor id. Every such page leaves a short-lived note for the next one, valid for 30 minutes after it was last used, so the chain carries every page of a visit, not only the second. It checks, in order: the ad click id in the page the visitor came from, together with the network and the browser; the page the visitor came from (the referrer), together with the network and the browser; then, for a visitor whose IP address changed during the visit (Wi-Fi to mobile data, for example), the same two again without the network, matched on the browser, the screen size and the language; then the IP address together with the browser. A match keeps the same visitor. When two visitors would match the same way, neither is matched: Tapper never guesses. A check that the connection's TLS fingerprint (JA4) agrees is built but parked: the load balancer does not supply that fingerprint today, so it never refuses a match. Only when nothing matches is a new visitor created. Monitoring is always on; where there is no cookie it runs cookieless and the matcher links the pages of the visit.
Who gets the matcher: every protected entity that has Recognise visitors without cookies on, for every request that arrives without the Tapper cookie. The setting is under Setup > Website > Monitoring, on the Cookie policy tab, one per protected entity, and on by default. Owners, admins and managers can turn it off; viewers see it but cannot change it. When it is off, none of the matching runs for that protected entity and no page-to-page notes are written. The match uses the page the visitor came from, an earlier ad click, or their IP address together with their browser, looking back up to 30 days. It also applies after tapper.consent("DENIED"), whose conversions are recorded with their order value and never credited or uploaded. A page the matcher recognizes continues the same visitor instead of starting a new one.
In short:
- A Google Consent Mode Reject in cookie mode does not turn off the remarketing tags or the
_gcl_aw/_gcl_dcread. Whether Tapper may write to the device is decided only by yourtapper.consent()call and your cookie policy; the Google signal only sets the consent fields of the upload to Google. - Conversions on matched cookieless pages are sent. They are recorded under the matched visitor and never credited, because a page recognized only by matching is never the same page load as the ad click. In cookie mode, a matched page that carries its own ad click id is credited like any ad click; in cookieless mode it is recorded and never credited, like every conversion captured without cookies today. After
tapper.consent("DENIED")a matched page's conversion is recorded the same way, with its order value, never credited. - After
tapper.consent("DENIED"), conversions of that visitor are recorded with their order value on every page, including a page continued by the no-cookie matcher and a page-content rule's conversion, so no money is lost, but they are never credited and never uploaded to an ad platform. Invalid traffic monitoring continues, cookieless.
What the script does in each mode
The script runs in one of two modes per visitor. The mode comes from the Cookie policy you set for that website, unless your site calls tapper.consent() for that visitor - see Your script's consent policy below. Signals from your consent banner, including Google Consent Mode, never choose the mode.
| Cookie mode | Cookieless mode | |
|---|---|---|
| Device storage | Writes the tsid cookie plus the local/session storage entries described below | Writes nothing to the device - no cookie, no local storage, no session storage, with one exception: when your site calls tapper.consent("DENIED"), Tapper stores that refusal (the decision and its time, never an identifier) so the next page does not ask again |
| Cross-session identity | Yes - the same visitor is recognized across page views and return visits | Yes, for invalid traffic protection - on a page where Tapper holds nothing of its own, it matches the visit before starting a new one (the page the visitor came from, then the ad click, then the network and browser), so the same visitor is recognized across pages and on a return visit without cookies. Its conversions are recorded, never credited (see Conversions below) |
| Invalid traffic and security signals | Captured | Partially captured - page views (the landing page, and later pages of the visit that Tapper matches back to it), events, clicks, and the tab record are still captured, and passive server-side/wire signals (IP, user agent, headers) ride along on every request regardless of mode. What does not run: the active browser-fingerprint probe fan-out (canvas, WebGL, audio, WebRTC, and the rest - skipped entirely, never subsetted), the client-side network fingerprint read (JA4/JA4H), and recovery of Google's _gcl_aw/_gcl_dc click-id cookies |
| Conversions | Recorded and attributed to the click that brought the visitor in, for as long as that identity is remembered. On a page continued by the no-cookie matcher: recorded, never credited | Still sent with its order value, currency, order id and click id - nothing is stripped - and marked as captured without storage, but nothing about it is stored on the device either. It is recorded with that value and never credited to an ad click or uploaded to an ad platform: crediting a conversion captured without cookies is switched off today, on the landing page too |
| Ad-platform audience scripts served through Tapper | Injected. A Google Consent Mode refusal of ad storage does not turn them off; it only fills the consent fields of the upload to Google | Not injected |
Cookieless mode costs attribution, not the conversion record. Tapper does not remove order value, currency, or the click id from a cookieless conversion - those still ride along, the same as in cookie mode, and the conversion is recorded with its value. What's missing is credit: today a conversion captured without cookies is never credited to an ad click, even on the landing page that carries the click id. A visitor who moves to another page or returns with no click id in the URL is still recognized for invalid traffic protection by matching.
What the script stores on a visitor's device (cookie mode only)
| Name | Type | Purpose | Duration |
|---|---|---|---|
tsid | Cookie | Holds the Tapper visitor identifier, together with the ad click id and any UTM parameters from the click that brought the visitor to your site. Used to attribute conversions to the correct click and to run traffic analysis. | 1 year. |
_tapper_lksd | Local storage | Records which ad click ids have already been seen in this browser, so the same click is not counted twice. | Until the visitor clears their browser storage. |
tbsid | Session storage | Identifies the current browser tab, so activity in one tab is not mixed with another. | Until the tab is closed. |
tcsh | Session storage | Written only on a page Tapper continued by matching (see Recognizing visitors without cookies). Holds an opaque handle, never the visitor identifier, so later pages in the same tab continue the same visit without matching again. | Until the tab is closed. |
_tapper_mode | Session storage | Persists the resolved cookie-mode decision for the rest of the current visit, so later page views in the same tab do not have to re-derive it. When Google Consent Mode has reported that the visitor refused ad storage, it also carries that refusal (tp_ad_storage: false, a yes/no value, never an identifier), so later pages stamp the same answer on the upload to Google from the start. | Until the tab is closed. |
__tapper_tcid | Shopify cart attribute | Shopify stores only. The Tapper visitor identifier, and nothing else (no ad click id), written into the visitor's Shopify cart once it holds an item, so a checkout that finds no Tapper cookie can still link the order to the visitor. The leading __ hides it from the buyer at checkout. It is stored by Shopify with the cart, not on the device. | As long as Shopify keeps the cart. A tapper.consent("DENIED") in the tab that wrote it clears it. |
tcrt | Session storage | Shopify stores only. Records which cart already carries the Tapper visitor identifier, so it is not written again on every page. | Until the tab is closed. |
cookietest | Cookie | Not ours - set and deleted by our fingerprinting dependency (FingerprintJS) as part of its device-signal checks. It rides on the same device budget as the entries above and is subject to the same gate. | Deleted immediately after it is set. |
None of these are written in cookieless mode, except the record of a tapper.consent("DENIED") refusal described above. If your site calls tapper.consent("GRANTED") mid-visit, the script starts writing them and carries the same visitor identity forward, so the click that brought them in is not lost.
The script only does anything at all when it can identify an ad click -
from a click id in the page URL, from a value it stored earlier, from a
Google click cookie already on the page, or, when it holds nothing of its
own, by matching this page once to an earlier page of the same visit or an
earlier visit. If none of these finds one, it removes its own cookie and
stops. A visitor who never arrives from an ad does not get a tsid.
Attributes of the tsid cookie
Register these in your CMP alongside the entry above:
| Attribute | Value |
|---|---|
| First-party | Yes - set by JavaScript via document.cookie on your own site. |
| Domain | The registrable domain of your site, for example .example.com. |
| Path | / |
| Flags | Secure, SameSite=None, Partitioned |
| Lifetime | 1 year from the moment it is first written. It is not extended on later visits while its value is unchanged. |
Cookies Tapper reads but does not set
If they are already present, the script reads Google's own _gcl_aw and _gcl_dc cookies to recover the click id. These are set by your Google tags, not by Tapper, and you declare them under Google in your CMP as you already do. The script reads them in cookie mode only; a Google Consent Mode refusal of ad storage does not stop the read, and after tapper.consent("DENIED") they are not read.
Two ways to tell Tapper about consent
Tapper listens only to your site's tapper.consent("GRANTED") and tapper.consent("DENIED") calls. A Google Consent Mode or banner-tool signal never turns Tapper on or off; it is only used for what Tapper hands to ad platforms, above all the conversion upload to Google. Tapper reads consent from two places, and they do different jobs:
- Door 1, your direct
tapper.consent()call, is the only thing that turns Tapper monitoring on or off. It moves the visitor between cookie mode and cookieless mode, in both directions. - Door 2, Google Consent Mode, never turns monitoring on or off, in either direction. Tapper records it and applies it to what it hands to, or takes from, ad platforms. The same goes for any other signal your banner publishes.
Door 1 - Call tapper.consent() directly
If your own CMP, cookie banner, or in-house consent flow knows the outcome, tell the script directly:
window.tapper.consent("GRANTED");
window.tapper.consent("DENIED");These are the only two values accepted, and they are case-sensitive -
exactly "GRANTED" or "DENIED", uppercase. "granted", "Denied", or
any other string is ignored; there is no lowercase alias. Call it as many
times as you like - a repeated call with the same decision is a no-op.
Door 2 - Google Consent Mode
If you already run Google Consent Mode through gtag or a CMP that
publishes it, Tapper reads it off gtag with no code from you. It does
not switch monitoring: a Reject in your banner does not make the visitor
cookieless or delete Tapper's storage, and an Accept does not start
cookie mode. What it does control:
- Not ad-platform tags or Google cookies. A denial of
ad_storagedoes not turn off ad-platform audience tags (Google, Meta, TikTok) or the read of Google's own cookies. Onlytapper.consent()changes those. A configured default or an implicit value is your site's configuration, not the visitor's answer, so it is never used to decide. - The Google Ads upload stamp.
ad_user_dataandad_personalizationare stamped on the conversions Tapper uploads to Google Ads - see below.
A Reject in your banner alone does not stop Tapper monitoring. Under
the Cookie first policy, a visitor who rejects only in your CMP stays in
cookie mode: Tapper still writes tsid, _tapper_lksd and tbsid, and
invalid traffic protection and attribution keep running. What that Reject changes is
the ad-platform side above and the consent sent to Google with the upload.
If your banner's Reject must also stop Tapper's storage, call
tapper.consent("DENIED") from it. The same holds the other way: under
Region-based or Consent first, an Accept in your banner alone does not
start cookie mode; call tapper.consent("GRANTED") from it.
The Google Ads upload stamp
Separately from monitoring, Tapper reads ad_user_data and
ad_personalization from Google Consent Mode and stamps them on the
conversions we upload to Google Ads - this is the consent status Google
requires on every upload for EEA and UK visitors. A visitor who denied them
in your banner is uploaded marked as denied. The
stamp comes from those two keys, not from ad_storage. If we hold no consent
signal for a visitor, that field is uploaded as unspecified - unless we have
confirmed the visitor is outside the EEA and UK, in which case it is
uploaded as granted. That confirmed-non-EEA/UK case is a statement about
jurisdiction, not about a choice the visitor made.
Your script's consent policy
The ladder is your call, then policy, then region: a tapper.consent() call from your site always wins; below that, your script's policy decides what every other visitor gets, including a visitor who answered only in your banner; region only matters inside the Region-based policy. A tapper.consent("DENIED") always applies regardless of policy - no policy can override it. Google Consent Mode and other banner signals are not on this ladder: they never move a visitor between modes, under any policy.
You set the policy yourself. Open Setup > Website in the sidebar, then the Monitoring area. Its three tabs are Cookie policy, Install script and consent (the monitoring script, the consent snippets and the conversion script) and Conversions (the conversion pages). Owners, admins and managers can change the policy.
There are three policies, and the control describes each one in the app:
| Policy | What it does |
|---|---|
| Region-based | Visitors in the EEA and the UK get no Tapper cookie or storage until your site calls tapper.consent("GRANTED"), and are still recognized across pages and on a return visit without cookies, for invalid traffic protection; everyone else gets cookie mode unless your site calls tapper.consent("DENIED"). Your banner does not change this. |
| Cookie first | Every visitor gets cookie mode unless your site calls tapper.consent("DENIED"). A Reject in your banner does not change this. |
| Consent first | No visitor gets a Tapper cookie or storage until your site calls tapper.consent("GRANTED"), and until then visitors are still recognized across pages and on a return visit without cookies, for invalid traffic protection. An Accept in your banner does not change this. |
Under every policy, a Google Consent Mode denial of ad_storage does not turn off ad-platform tags or the Google cookie read; its ad_user_data / ad_personalization answer still rides on the Google upload.
The line under the control always tells you what the selected policy does. If it starts with Default., nobody in your workspace has chosen a policy yet and you are on the one Tapper applies until someone does. This page does not say which policy applies to you - it is a setting you control.
Recognizing visitors without cookies
On any page where Tapper has no cookie of its own, under every policy, Tapper matches the visit once before it starts a new one: first the page the visitor came from, then the ad click, then the network and browser. A match continues the same visitor; no match starts a new one. This covers:
- Consent first, and Region-based for visitors in the EEA and the UK, before your site calls
tapper.consent("GRANTED"), including the first page of a visit. - A visitor after your site called
tapper.consent("DENIED"). - Cookie first and Region-based outside the EEA and the UK, on the first page of a visit, or when the cookie was cleared, expired, or deleted by the browser.
The match stores nothing on the device in cookieless mode. In cookie mode, a matched page with its own ad click is credited like any ad click and a page recognized only by matching (no click id) is recorded, never credited; in cookieless mode every conversion is recorded, never credited. If your site calls tapper.consent("GRANTED") mid-visit, Tapper switches to its cookie and keeps the same visitor.
EEA/UK and elsewhere under the region-based policy
- A
tapper.consent("DENIED")applies everywhere in the world, not only in the EEA and UK. - With the Region-based policy active and no
tapper.consent()call:- Visitors outside the EEA and UK get cookie mode - full attribution.
- Visitors inside the EEA and UK get cookieless mode - invalid traffic protection only - until your site calls
tapper.consent("GRANTED"). An Accept in your banner alone does not change this. - An unresolved location is treated the same as EEA/UK for this decision, because that is the only direction that cannot produce a claim we do not hold.
- The Consent first and Cookie first policies don't vary by region - see "Your Script's Consent Policy" above.
Example: Firing the hook from Google Tag Manager
If you want your banner to switch Tapper monitoring, wire it to Door 1. To do that through GTM instead of your CMP's own script:
<!-- Custom HTML tag, triggered on your CMP's own "consent updated" event -->
<script>
(function () {
if (typeof window.tapper === "undefined") return;
// Replace this with however your CMP exposes the visitor's choice
var granted = yourCmp.getConsentState("advertising") === true;
window.tapper.consent(granted ? "GRANTED" : "DENIED");
})();
</script>Fire this tag on your CMP's consent-update event, not on page load - the same rule that applies to Google Consent Mode applies here: only an actual choice should reach tapper.consent(), not a configured default.
If you already run Google Consent Mode correctly, it needs no code to reach Tapper's ad-platform and upload handling - the script reads it directly off gtag. It does not switch monitoring, so wire the hook above if your banner should.
Verifying it's working
Use this checklist to confirm each mode is doing what you expect for your
site. Land on the page from an ad click (or add a click id such as gclid
to the URL), because the script does nothing without one.
- Open your browser's DevTools Network tab and reload the page.
- Find the request the monitoring script makes to
users.ping(orusers.registerTabon a returning visit) and inspect its response JSON. It reports whether the visitor resolved as EEA or UK, which cookie policy your script is on, and that the consent gate is live. - Cookie mode (Cookie first with no
tapper.consent("DENIED"), Region-based outside the EEA and UK, or any policy aftertapper.consent("GRANTED")): the response carries the visitor's identifiers and the browser sets thetsidcookie plus_tapper_lksd(local storage) andtbsid(session storage) - check the Application → Cookies/Local Storage/Session Storage panels for them. - Reject in your banner only (Google Consent Mode denies
ad_storage, notapper.consent()call): on Cookie first,tsid,_tapper_lksdandtbsidare still there - that is expected, the banner does not switch monitoring. What changes:_tapper_modein session storage shows"tp_ad_storage":false, which only sets the consent fields of the upload to Google. Ad-platform audience tags from Tapper are still added. - Cookieless mode (
tapper.consent("DENIED")called, or Region-based in the EEA/UK or Consent first with notapper.consent("GRANTED")): none oftsid,_tapper_lksdortbsidappear after the request - this is the confirmation that cookieless mode is active. - Call
tapper.consent("DENIED")from the console in cookie mode:tsid,_tapper_lksdandtbsidare removed. Then calltapper.consent("GRANTED")and confirm the cookie and storage entries appear again.
Declaring Tapper in your CMP
Add the entries above to your cookie inventory so your banner reflects what actually runs on your site.
Invalid traffic and security signals are commonly classified as necessary or security in CMP inventories, because they exist to protect the site and the advertiser rather than to profile the visitor. Attribution and measurement storage is commonly classified as marketing or statistics.
Tapper cannot make that classification for you. The tsid cookie carries
both a traffic-analysis identifier and click attribution data in a single
entry, so where it belongs in your inventory depends on your own assessment
and your advisers. Classify it, then make sure your banner matches.
Withdrawing consent
When your site calls tapper.consent("DENIED"), the script:
- Deletes the
tsidcookie and the local/session storage entries above, and clears the Tapper visitor identifier it wrote into a Shopify cart from the same tab. - Stops attribution for that visitor going forward.
- Keeps invalid traffic protection running.
- Applies the withdrawal immediately, without a page reload.
A Reject reported only through Google Consent Mode is not a withdrawal from
Tapper monitoring. Tapper records it, its ad_user_data /
ad_personalization answer reaches Google on the upload stamp, and
nothing else changes: ad-platform tags, the Google cookie read and Tapper's
own storage stay in place.
Nothing on this page requires a change to your tags to keep working. If
your site calls tapper.consent() mid-visit, the script switches modes
without a page reload; a change reported through Google Consent Mode updates
the ad-platform side the same way, without changing the mode.