GDPR / TCF consent: options, signals and macros reference
Every consent-verification option on the GDPR card, the order the ad server checks consent in, the request parameters and tag attributes it reads, what the cookie beacons and cookie sync do under a per-request cookie policy, the macros that pass consent downstream, and the troubleshooting-log lines that show the verdict.
Reference for Configure GDPR / TCF consent enforcement: the fields on the card one by one, how the ad server reaches its verdict, which request parameters it reads, and how the verdict and the signals travel on.
Consent-verification options
These tighten what counts as valid consent. All five are off by default, and none of them has any effect while the policy is Default.
| Field | What it does | Default |
|---|---|---|
| IAB vendor id | The vendor whose consent the TC string must grant. The request passes only when this id is in the string’s vendor-consent list. | 849 (Epom) |
| Restrict DSP mediation | Additionally drops OpenRTB creatives from the auction for no-consent requests, whatever the restriction says — they are excluded with the reason GDPR_MEDIATION_RESTRICTED. No other creative type is affected. | off |
| Check disclosed vendors | Also requires the vendor id in the string’s disclosed-vendors segment, not just the vendor-consent segment. Only works when the CMP actually emits that segment; when it does not, every string fails this check. | off |
| Verify CMP against the IAB list | Rejects the string when its cmpId is not on the IAB Europe Global CMP List, or is on it but marked deleted. The list is refreshed daily from IAB Europe; until it has been loaded for the first time every cmpId is accepted. | off |
| Enforce TCF policy version | Rejects strings whose TCF policy version is below Min TCF policy version. | off |
| Min TCF policy version | The floor for the check above; enabled only when it is ticked. 4 = TCF v2.2. The field limits input to 2–10 in the browser; the server does not check the range and stores whatever it is sent. | 4 |
| Honour GPC opt-out signal | Treats a Global Privacy Control opt-out — gpc=1 on the request, or a Sec-GPC: 1 header — as no consent. It is checked only for requests in GDPR scope, where it comes before every other consent check; a request outside GDPR scope is not affected. | off |
How the decision is made
For each ad request the server evaluates, in order:
- Is GDPR in scope? Yes when the ad request carries
gdpr=1; no when it carriesgdpr=0; and when the parameter is absent, yes when the request carries aucvalue at all, otherwise yes when the IP geolocates to a country on the EEA list. So the gate self-activates for European traffic even from tags that never send agdprflag. Clicks and the tracking hits that follow an ad apply the same rule, so they land on the same side of the gate as the ad request. - If it is not in scope, or the policy is Default → serve normally.
- If it is in scope, check consent, in this order: an honoured GPC opt-out fails
immediately; then
uc=1passes anduc=0fails without looking at the string; then a blank or undecodable string fails; then a string that is not TCF 2.x fails; then the policy-version, CMP-list, vendor-consent and disclosed-vendors checks, in that order. - On a failed check, apply the restriction: no banner is selected (Do not serve ads), or the ad serves under the cookie and anonymity rules in What “no consent” actually costs. With Restrict DSP mediation on, OpenRTB creatives are additionally removed from the auction, so a direct creative wins instead.
The EEA list is server-side configuration. It ships with 32 country codes, among them CH and GB, which are not EEA members; ask Epom support or your account manager to show or change it.
Request signals the ad server reads
| Signal | Meaning |
|---|---|
gdpr | 1 = GDPR applies, 0 = does not. Absent → inferred, see step 1 above. Tag attribute: data-gdpr. |
gdprConsentIab | The TCF 2.x consent string. Tag attribute: data-gdpr-consent-iab; set it and the tag stops asking the CMP. |
uc | Shortcut verdict: 1 = consented, 0 = not. Overrides the consent string. Tag attribute: data-user-consent. |
cookie-policy | Per-request cookie switch, 0–3 — see below. Tag attribute: data-cookie-policy. |
gpc / Sec-GPC | Global Privacy Control opt-out — gpc=1 as a request parameter, or Sec-GPC: 1 as an HTTP header. Read only when Honour GPC opt-out signal is on, and only for requests in GDPR scope. |
usPrivacy | The IAB US Privacy string, 1 followed by three of Y, N, - (e.g. 1YNN). Not part of the GDPR decision; forwarded to DSPs with Pass privacy signals to DSPs on. |
gpp, gppSid | The IAB GPP string and the comma-separated section ids that apply. Not part of the GDPR decision; forwarded to DSPs with Pass privacy signals to DSPs on. |
coppa | 1 for child-directed traffic. Not part of the GDPR decision; forwarded to DSPs with Pass privacy signals to DSPs on. |
How the JavaScript tag gets the string. The standard Epom tag looks for a __tcfapi v2 CMP
on the page (and, when the CMP lives in an ancestor frame, talks to it through the
__tcfapiLocator frame by postMessage), waits up to 5 seconds, and sends the result as gdpr
and gdprConsentIab. data-gdpr-consent-iab on the tag makes it skip the CMP lookup entirely.
Server-to-server, VAST and header-bidding integrations have to pass the string themselves.
Header-bidding callers do not use those names: /hb/bid reads the consent string from
user.consent or user.ext.consent, and the applies-flag from regs.gdpr or regs.ext.gdpr. A
bare regs.gdpr = 0 with no consent string is deliberately ignored rather than forwarded — it is
the shape a CMP that timed out leaves behind, and forwarding it would let an EEA visitor through
ahead of the country fallback.
Only TCF 2.x is accepted. A string that decodes to any other version is treated as no
consent, silently. There is no TCF 1.1 support: the ad tag reads no __cmp, and the
/rest-api/tcf/1.1/… endpoints answer 404.
How do I stop Epom setting cookies until the visitor consents?
The per-request switch is cookie-policy — data-cookie-policy="1" on a JavaScript tag,
&cookie-policy=1 on a VAST, native or API request URL, and &cookie-policy=$$COOKIE_POLICY$$
on a VAST or ad URL inside a creative or template so the inner request inherits the outer one’s
value. Values: 0 normal; 1 no cookies read or set and no server-side capping; 2 no cookies,
server-side capping still on; 3 no user-ID cookie only, other cookies and capping on. Any value
other than 0 is carried into that ad’s impression and click URLs, so the tracking hits stay
cookie-free too. (uc=0 / data-user-consent="0" is different: it marks the visitor as not
consenting, and the network’s no-consent Restriction decides what that means.)
A format that loads a second ad request of its own (a video slider’s inner VAST, an outstream
player) does not see the outer tag’s attribute. If cookies still appear with cookie-policy=1
set, look for an inner request URL without $$COOKIE_POLICY$$.
GDPR overrides a tag’s own cookie policy only for in-scope requests that fail the consent check; every other request keeps whatever the tag asked for.
The cookie beacons read it too. set-cookie.gif and the multi-cookie beacon
(/multi-cookie.gif, .js, .html) store nothing at all under cookie-policy=1 or 2 —
neither a cookie nor the localStorage copy the tag keeps for Safari. The cookie-policy and
gpc parameters themselves are never stored as data, so a beacon URL can carry the privacy signal
without it turning into a cookie of its own.
Cookie sync reads it as well. A /multi-cookie.* call whose policy forbids the user ID
(1, 2 or 3) performs no sync: the Epom user ID is not resolved, so it is neither carried
through the endpoint-domain chain nor handed to the partner URL through $$UUID$$, and the
third-party hop is skipped. The beacon still answers — a pixel, or the script without the sync —
and plain data cookies the call was given are still set where the policy allows them.
Passing consent downstream
Two macros carry the GDPR signal into any banner code, click or impression URL, piggyback or server-side tracker:
| Macro | Expands to |
|---|---|
$$GDPR$$ | The applies flag, 0 or 1. The IAB spelling ${GDPR} is accepted and normalised to it. |
$$GDPR_CONSENT_IAB$$ | The consent string. ${GDPR_CONSENT_XXXX} (XXXX = any vendor id, digits only) is accepted and normalised to it. |
$$GDPR$$ always resolves, to 0 or 1. $$GDPR_CONSENT_IAB$$ is removed when no string
reached the request, so a partner URL gets no gdpr_consent= at all rather than an empty one. See
the macros reference.
Four more forward the other privacy signals the request carried into banner code and the VAST tags
of demand you call by URL: $$US_PRIVACY$$, $$GPP$$, $$GPP_SID$$ and $$COPPA$$. Each is
removed when the request did not carry its value.
OpenRTB demand gets the signals in the bid request itself once Pass privacy signals to DSPs is on. While it is off, the macros above in the partner’s endpoint URL or custom parameters on the DSP partner remain the only route. Either way the signals change nothing about whether an ad is served — that is still the policy and restriction — and they are forwarded as they came, without being enforced: a US opt-out or a COPPA flag does not by itself anonymise the bid request.
Troubleshoot a single request
When delivery drops and you need to know whether GDPR is the reason, run a troubleshooting log task (Admin → Audit & diagnostics → Troubleshooting log tasks) over the affected traffic. Two lines answer the question:
TCF Consent Info: version=… , cmpId=… , vendorId=… , vendorConsent=… , vendorDisclosed=… , vendorLI=… , checkDisclosedVendors=… , purposes=[…]— the decoded string as the server read it.vendorConsent=falsemeans your id is not in the string;vendorDisclosed=falsewithcheckDisclosedVendors=truemeans the CMP is not emitting the disclosed-vendors segment.No banner can be selected due to failed GDPR policy constraints.— the request was in scope, failed the check, and the restriction is Do not serve ads.
The TCF line is written only when the request carried a consent string at all. A request with no string produces no TCF line — so a log that shows the refusal line and nothing else is telling you the string never arrived, which is a CMP or tag problem, not a settings problem. A request served under Do not use any cookies or server-side processing notes the skipped server-side capping in the same log.