libconsent

Gating

Put consent in front of a script, an embed or an effect.

<ConsentScript>

For vendor snippets, without writing a wrapper component:

<ConsentScript
  id="hotjar"
  src="https://static.hotjar.com/c/hotjar-123.js?sv=6"
/>
<ConsentScript id="meta-pixel">{`
  !function(f,b,e,v,n,t,s){…}(window, document,'script', 'https://connect.facebook.net/en_US/fbevents.js');
  fbq('init', '000000000000000');
`}</ConsentScript>

The tag is added when consent is granted and removed when it is withdrawn.

Removing a tag is not the same as undoing it

A script that already ran has already done whatever it does. If withdrawal has to actually stop something, reload: local({ reloadOnRevoke: true }).

<CookieService>

Wrap anything that should only run with consent. It also puts the service in the preferences dialog, so the list there stays in step with what your app loads.

<CookieService id="hotjar">
  <HotjarSnippet />
</CookieService>

The id is usually all it takes — see the service catalog for what's built in and how to add your own.

Show something else instead

<CookieService
  id="youtube"
  fallback={<p>Allow marketing cookies to watch this.</p>}
>
  <iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" />
</CookieService>

Some Google scripts, like Google Analytics, can run in a limited mode without consent. Simply set consentMode on the <CookieService> and the adapter will handle it for you:

<CookieService id="google-analytics" consentMode>
  <GoogleAnalytics gaId="G-XXXXXXX" />
</CookieService>

See the Google Consent Mode page for details on what it does.

Render both cases

Pass a function when the placeholder needs the answer too:

<CookieService id="google-maps">
  {(granted) => (granted ? <Map /> : <StaticMapImage onClick={openSettings} />)}
</CookieService>

Categories

Every service belongs to one of four categories, and that is what gates it when the consent platform has no answer for the service itself:

Category
essentialNeeded to run the site. Always granted.
functionalPreferences, embedded maps, chat widgets.
analyticsMeasurement and product analytics.
marketingAdvertising, remarketing, conversion tracking.

Platforms use their own names for these; the adapter translates, so your components only ever see the four above.

useHasConsent

When you only need the answer:

const canTrack = useHasConsent("analytics");
const canHotjar = useHasConsent("hotjar");

Pass a category or a service id — whichever fits.

useCookieService

Same as <CookieService>, for work that happens in an effect rather than in the tree:

const granted = useCookieService("posthog");

useEffect(() => {
  if (!granted) return;
  posthog.init(KEY);
  return () => posthog.reset();
}, [granted]);

Listing services before they render

Services appear in the preferences dialog once they mount. If your banner shows on the first paint and you want the full list there right away, name them on the provider:

<ConsentProvider
  services={[
    { id: "google-analytics" },
    { id: "meta-pixel" },
    { id: "acme-chat", name: "Acme Chat", category: "functional" },
  ]}
>

Listing a service here and rendering it later is fine — it won't show up twice.

On this page