Documentation

Publisher consent API

A page-level JavaScript API for reading the visitor's consent state and reacting when it changes — available under every privacy regime, including the ones with no industry signal at all.

Why it exists

Under the IAB TCF you have __tcfapi; under GPP, __gpp; with Google's tags, Consent Mode. Under Brazil's LGPD, Türkiye's KVKK and most other regimes there is no such thing, and a publisher who wants to ask "may I run analytics for this visitor?" has nothing to call. __fcapi is that contract.

It is deliberately available everywhere, not only where no standard exists — you should not need one code path for a German visitor and another for a Brazilian one. Where TCF or GPP do apply their strings are included here too, so __fcapi is a superset rather than a rival.

Availability

It is defined at parse time, before any tag on the page, by a stub inside the consent script — so you can call it from the top of your <head> without waiting for anything. Before the full bundle loads the stub answers ping and accepts listeners; anything else is queued and replayed. Listeners you register against the stub are adopted by the real implementation, not dropped.

Commands

__fcapi(command, callback, parameter). The callback receives (data, success); the value is also returned synchronously once the CMP has loaded.

getConsentState

__fcapi('getConsentState', function (state) {
  if (state.consented.analytics) startAnalytics();
});
{
  apiVersion: "1.0", cmpId: 317, cmpStatus: "loaded", cmpLoaded: true,
  regime: "gdpr", gdprApplies: true,
  hasChoice: true,                    // false while the banner is still unanswered
  consented: { essential: true, analytics: false, marketing: false, … },
  categoriesById: { "1": true, "2": false, … },
  acceptedCategoryIds: ["1"],
  tcString: "…",                      // when TCF applies, else ""
  gppString: "…"                      // when GPP applies, else ""
}

consented is the field to gate on. Check hasChoice first: false means the visitor has not decided yet, which is not the same as a refusal.

Do not key on the category's display name — it is translated per language and a site owner can rename it at any time. consented and categoriesById are stable; the label is not.

addEventListener / removeEventListener

var id = __fcapi('addEventListener', function (ev) {
  // ev.eventName: "listenerRegistered" | "consentChanged"
  // ev.reason:    "cmpLoaded" | "save" | "update"
  // ev.state:     the same object getConsentState returns
  if (ev.state && ev.state.consented.marketing) loadAdTags();
});

__fcapi('removeEventListener', null, id);

The listener fires on every persisted change, including a withdrawal made mid-page — the case you most need to hear about and cannot poll for. Your handler is individually guarded: if it throws, other listeners still run.

ping

{ apiVersion: "1.0", cmpId: 317, cmpStatus: "stub" | "loaded", cmpLoaded: false | true,
  regime: null | "gdpr" | "canada" | "turkey" | "us" | "none", hasChoice: false | true }

regime is null while the visitor's region is still being resolved — deliberately, so you can tell "not yet" from "no regime applies" ("none").

Worked example

<script>
  // Safe at the very top of <head>: the stub is already there.
  window.__fcapi && __fcapi('addEventListener', function (ev) {
    var c = ev.state && ev.state.consented;
    if (!c) return;
    if (c.analytics && !window.myAnalyticsLoaded) {
      window.myAnalyticsLoaded = 1;
      startAnalytics();
    }
    if (!c.marketing) disableAdPersonalisation();   // also fires on a mid-page withdrawal
  });
</script>

window._fc_gcm — the computed Google Consent Mode signals

A companion global: the seven Google Consent Mode v2 types as the page computed them for this visitor, from cookie categories combined with IAB TCF purposes.

window._fc_gcm
// { ad_storage: "denied", ad_user_data: "denied", ad_personalization: "denied",
//   analytics_storage: "granted", functionality_storage: "granted",
//   personalization_storage: "denied", security_storage: "denied" }

It is refreshed before the __fcapi listeners are told about a change, so a handler that reads it is reading this decision and not the last one. It is published whether or not the project has Consent Mode switched on — that switch governs whether we push consent commands to your page, not whether the visitor decided. It never carries wait_for_update, which belongs to a consent default and which Google rejects on an update.

This is what our Google Tag Manager tag reads, and it is there for anyone driving Consent Mode by hand for the same reason.

Stability

apiVersion is 1.0. Changes are additive only — once you ship against this we will not quietly alter the shape; apiVersion moves if it ever has to.

← Google Tag Manager