IAB TCF
Any TCF v2.2 CMP, through the __tcfapi all of them expose.
npm i @libconsent/tcfimport { ConsentProvider } from "@libconsent/core";
import { tcf } from "@libconsent/tcf";
<ConsentProvider adapter={tcf()}>{children}</ConsentProvider>;Every CMP registered with the IAB Transparency & Consent Framework has to expose
the same window.__tcfapi. This adapter talks to that and nothing else, so one
package covers Sourcepoint, Quantcast Choice, Didomi, Google's own CMP, Sirdata,
InMobi and the rest of the TCF long tail.
It does not load your CMP
There is no script to add — the adapter reads whichever TCF CMP is already on the page. Keep loading yours however you do today.
Options
| Option | Default | |
|---|---|---|
purposes | see below | Remap TCF purpose ids onto categories. Merged with the defaults. |
specialFeatures | none | Fold special features into categories. Empty by default — see below. |
strategy | "all" | Whether a category needs every purpose behind it, or just one. |
legitimateInterest | true | Count purposes established under legitimate interest as granted. |
vendors | — | Map your service ids onto Global Vendor List ids. |
commands | — | TCF has no "open the UI" call. Wire your CMP's own in. |
Purposes
TCF v2.2's eleven purposes, and what each one gates here:
| # | Purpose | Category |
|---|---|---|
| 1 | Store and/or access information on a device | essential |
| 2 | Use limited data to select advertising | marketing |
| 3 | Create profiles for personalised advertising | marketing |
| 4 | Use profiles to select personalised advertising | marketing |
| 5 | Create profiles to personalise content | functional |
| 6 | Use profiles to select personalised content | functional |
| 7 | Measure advertising performance | marketing |
| 8 | Measure content performance | analytics |
| 9 | Understand audiences through statistics | analytics |
| 10 | Develop and improve services | analytics |
| 11 | Use limited data to select content | functional |
A category is granted when every purpose behind it was consented to. That is the safe reading — a user who allowed audience measurement but refused profiling has not accepted analytics — but if your vendors only need one of the ad purposes, say so:
tcf({ strategy: "any" });Or move a purpose somewhere else entirely:
tcf({ purposes: { 10: "functional", 11: "marketing" } });Special features
The two special features — precise geolocation and active device scanning — are
a separate question from the purposes, and they stay out of the categories by
default. A user may happily accept advertising while refusing a location prompt,
and folding that refusal into marketing would switch off every ad script on
the page.
They are reported as services instead, so you gate exactly what needs them:
<CookieService id="geo-ads" aliases={["special-feature-1"]}>
<GeotargetedAds />
</CookieService>If your vendors genuinely cannot run without one, map it onto a category. A mapping can only take a category away, never grant one:
tcf({ specialFeatures: { 1: "marketing" } });Outside the EEA
When the CMP reports gdprApplies: false there is nothing to consent to and the
banner never shows. Every category is granted, rather than blocking every script
for users the framework does not cover.
Vendors
Consent for individual vendors is reported under their Global Vendor List id, both bare and prefixed:
<CookieService id="google-ads" aliases={["755", "vendor-755"]}>
<GoogleAds />
</CookieService>Naming ids in every component gets old, so map them once:
tcf({
vendors: {
"google-ads": 755,
"acme-dsp": [12, 34], // both have to be allowed
},
});No default map ships with the adapter: GVL ids change as vendors register and deregister, and a stale one silently gates the wrong thing.
Opening the settings
TCF describes consent; it has no call to show a dialog. That is your CMP's own API, so pass it through:
tcf({
commands: {
openSettings: () => window._sp_.gdpr.loadPrivacyManagerModal("123456"),
},
});Anything you pass shows up in useConsent().supports, so a "Cookie settings"
link can check before rendering itself.
Prefer a dedicated adapter when one exists — Didomi reports per-vendor consent and can open its own preference centre, neither of which TCF alone gives you.
Google Consent Mode
The adapter cannot tell which CMP is behind the API, and most TCF CMPs write the Consent Mode signals themselves. libconsent writes them too by default, since both derive from the same consent and a missing signal is worse than a duplicate one. Turn it off if you would rather not:
<ConsentProvider adapter={tcf()} consentMode={false}>