Providers
This page covers what the providers that ship with ConsentLayer have in common: the consent category each one requires, deferred SDK loading, loading before consent, reverse proxies and error reporting. Each provider’s options and exact behavior are on its own page.
A provider is a plugin that connects one vendor to the instance. Browser
providers are passed to createAnalytics({ providers }). Other consent
systems, such as IAB TCF, Shopify Customer Privacy and Google Consent Mode,
are consent adapters instead.
Available providers
Section titled “Available providers”Each provider is a named export of its own entry point,
consentlayer/providers/<name>, so importing one never bundles another.
| Provider | Factory | Required consent | Required options |
|---|---|---|---|
| GA4 | ga4() from consentlayer/providers/ga4 |
analytics |
measurementId |
| Meta Pixel | meta() from consentlayer/providers/meta |
marketing |
pixelId |
| Google Tag Manager | gtm() from consentlayer/providers/gtm |
'none', or requiredConsent |
containerId |
| PostHog | posthog() from consentlayer/providers/posthog |
'none'; analytics with cookieless: false |
apiKey |
| Sentry | sentry() from consentlayer/providers/sentry |
'none' |
dsn |
| Contentsquare | contentsquare() from consentlayer/providers/contentsquare |
analytics |
tagId |
| Vercel Analytics | vercel() from consentlayer/providers/vercel |
'none' |
trackEvent |
| TikTok Pixel | tiktok() from consentlayer/providers/tiktok |
marketing |
pixelId |
| Hotjar (deprecated) | hotjar() from consentlayer/providers/hotjar |
analytics |
siteId, version |
The ID options of GA4, Meta, GTM, TikTok, PostHog, Sentry, Contentsquare and
Hotjar may be undefined or empty: the provider is then turned off, and with
debug: true it logs [consentlayer] <id> is off: <option> is not set. when
createAnalytics() creates the instance in the browser. Pass process.env
values directly instead of guarding each provider. String IDs are trimmed
first, so a trailing newline in an environment variable is harmless and a
whitespace-only value counts as unset.
A provider whose required consent is 'none' loads at boot and receives
calls regardless of the visitor’s choice. Every other provider loads only once
its category is granted (or at boot with loadBeforeConsent), receives page, track, identify and group
calls only while it stays granted, and is torn down when it is withdrawn.
The exact order of these hooks is described in
Lifecycle.
ga4(), meta(), gtm() and hotjar() validate their IDs when called and
throw on a value that is set but malformed:
| Provider | Option | Accepted |
|---|---|---|
ga4() |
measurementId |
G- followed by 4 to 16 uppercase letters or digits. |
meta() |
pixelId |
A string of 8 to 20 digits. |
gtm() |
containerId |
GTM- followed by 4 to 12 uppercase letters or digits. |
hotjar() |
siteId, version |
A positive integer, as a number or a string of digits. |
ga4() and gtm() also throw when serverContainerUrl is neither an HTTPS
URL nor a relative path starting with a single /. The other providers do not
check the format of their IDs, so a wrong one fails at the vendor instead.
Event names follow GA4 and each provider translates them to its own; see Events and identity. A custom plugin can also require one of your custom categories.
Loading SDKs later
Section titled “Loading SDKs later”posthog() and sentry() accept defer, which postpones loading the SDK
until after its consent requirement is met. A custom plugin
can set the same defer field.
| Value | Loads |
|---|---|
false (default) |
Immediately. |
'idle' |
In a requestIdleCallback with a 5,000 ms timeout, or after setTimeout(…, 1) where it is unavailable. |
'interaction' |
On the first pointerdown, keydown, scroll or touchstart event on window. |
number |
After that many milliseconds. |
Calls made to the provider in the meantime are held in order and delivered
once it has loaded. At most 100 calls are held per provider; later ones are
dropped and a single queue-full error is reported to onError. If consent
is withdrawn before the provider loads, it is not loaded and its held calls
are discarded.
Loading before consent
Section titled “Loading before consent”By default, GA4, Meta Pixel and TikTok Pixel load nothing until their
category is granted. With loadBeforeConsent: true, the vendor script is
loaded at boot with consent denied: gtag.js with the
Consent Mode defaults, the Meta pixel with fbq('consent', 'revoke') and the TikTok pixel
with ttq.holdConsent().
ga4({ measurementId, loadBeforeConsent: true })meta({ pixelId, loadBeforeConsent: true })tiktok({ pixelId, loadBeforeConsent: true })No hits are sent before consent either way: GA4 is configured only after analytics consent is granted, and the pixels send events only with marketing consent. The effect is that the script is already loaded when the visitor consents. The script request itself discloses the visitor’s IP address to Google, Meta or TikTok before consent.
Reverse proxies
Section titled “Reverse proxies”Ad blockers drop requests to posthog.com and sentry.io. Serving them
through your own domain avoids this; see PostHog
and Sentry.
The other ad-blocked providers need a different approach. For GA4 and Google
Tag Manager, set serverContainerUrl to a
server-side GTM container on
your own domain. For Meta and TikTok, use
server-side tracking instead.
Errors
Section titled “Errors”analytics.captureError(error, { level, tags, extra }) sends an error to
every active provider that handles errors: Sentry, and PostHog unless it is
created with posthog({ errors: false }). level is 'fatal', 'error' or
'warning'.
ConsentLayer also reports the window’s error events, with level fatal,
and unhandledrejection events. It attaches these handlers when boot()
runs, so errors thrown before then are not captured by them. captureError()
calls made before boot() completes are queued with every other call, up to
100 together, and delivered once it completes.
createAnalytics option |
Effect |
|---|---|
errors: true (default) |
captureError and the window handlers. |
errors: { globalHandlers: false } |
captureError only. |
errors: false |
No error reporting; captureError does nothing. |
The errors option of posthog() is separate: it only decides whether
PostHog receives the errors ConsentLayer reports.
In React, wrap the tree in ErrorBoundary from consentlayer/react; see
Report errors. In Next.js, also export
createGlobalError(analytics) from app/global-error.tsx; see
Global errors.
Writing your own
Section titled “Writing your own”A provider is an object typed with definePlugin from consentlayer. See
Writing a plugin and
What each provider receives.