Installation
Install ConsentLayer and the SDKs of the providers you use, then configure TypeScript and your Content Security Policy.
Install the package
Section titled “Install the package”pnpm add consentlayernpm install consentlayeryarn add consentlayerbun add consentlayerConsentLayer has no runtime dependencies.
System requirements
Section titled “System requirements”| Environment | Requirement |
|---|---|
| Node.js | 22 or later. The server entry points use the global fetch and Web Crypto (crypto.subtle, crypto.randomUUID) APIs. |
| Edge runtimes | Any runtime with fetch and Web Crypto, such as the Next.js Edge runtime. |
| Browsers | Chrome and Edge 94, Firefox 93, Safari and iOS Safari 15.4, or later. The package is compiled to ES2022, and CI checks its code and syntax against these versions. Your bundler transpiles it if you target older browsers. |
| React | 18.3 or 19, only for consentlayer/react and consentlayer/next. |
| Next.js | 15 or 16, only for consentlayer/next, in the App Router or the Pages Router. |
| Vue | 3.5.17 or later, only for consentlayer/vue and consentlayer/nuxt. |
| Nuxt | 4, only for consentlayer/nuxt. |
| Svelte | 5.14.3 or later, only for consentlayer/svelte and consentlayer/sveltekit. |
| SvelteKit | Only for consentlayer/sveltekit, which imports $app/navigation. Tested with SvelteKit 3. |
| Solid | 1.9 or later, only for consentlayer/solid and consentlayer/solidstart. |
| Solid Router | 0.16 or 1.x, only for consentlayer/solidstart, with or without SolidStart. Tested with SolidStart 2. |
| Angular | 20 or later, only for consentlayer/angular. The Angular Router is optional. |
| PostHog | posthog-js 1.438 or later, only for consentlayer/providers/posthog. |
| Sentry | @sentry/browser 11 or later, only for consentlayer/providers/sentry; @sentry/nextjs 11 for consentlayer/sentry/server and consentlayer/sentry/next. |
| TypeScript | 5.0 or later, with moduleResolution set to bundler, node16 or nodenext. |
Every provider and consent adapter works with every framework binding and with the script tag.
Optional peer dependencies
Section titled “Optional peer dependencies”Providers built on a vendor’s npm SDK declare it as an optional peer
dependency. Install it only if you use that provider. Every other provider
loads the vendor’s script from the vendor’s CDN at runtime, after consent is
granted. The Vercel provider takes track from @vercel/analytics, which you
install and import yourself.
| Import | Peer dependency |
|---|---|
consentlayer/react |
react, react-dom |
consentlayer/next |
react, react-dom, next |
consentlayer/vue |
vue |
consentlayer/nuxt |
vue, nuxt |
consentlayer/svelte, consentlayer/sveltekit |
svelte |
consentlayer/solid |
solid-js |
consentlayer/solidstart |
solid-js, @solidjs/router |
consentlayer/angular |
@angular/core, @angular/router |
consentlayer/providers/posthog |
posthog-js |
consentlayer/providers/sentry |
@sentry/browser |
consentlayer/sentry/server, consentlayer/sentry/next |
@sentry/nextjs |
Module format
Section titled “Module format”ConsentLayer is published as ES modules only, with type declarations and
source maps. Each feature is a separate entry point declared in the
package’s exports field, and the package is marked "sideEffects": false,
so bundlers include only the exports you import. Provider SDKs and heavier
features, such as Sentry Session Replay, are split into chunks that are
loaded with dynamic import() when they are first needed. See
Reduce bundle size.
| Entry point | Exports |
|---|---|
consentlayer |
createAnalytics, definePlugin, storage helpers and core types |
consentlayer/react |
AnalyticsProvider, hooks, ErrorBoundary, MetaPixelNoscript, GtmNoscript |
consentlayer/next |
AnalyticsProvider for Next.js, which tracks navigation itself |
consentlayer/vue |
The consentLayer Vue plugin, composables, MetaPixelNoscript and GtmNoscript |
consentlayer/nuxt |
The Nuxt module, which sets up consentlayer/vue from a config file |
consentlayer/svelte |
consentLayer for your root component, the use* functions, MetaPixelNoscript and GtmNoscript |
consentlayer/sveltekit |
The same, with page views on SvelteKit navigation and handleErrorWith |
consentlayer/solid |
AnalyticsProvider, hooks, ErrorBoundary, MetaPixelNoscript, GtmNoscript |
consentlayer/solidstart |
The same, with page views on Solid Router navigation |
consentlayer/angular |
provideConsentLayer, the inject* functions, provideMetaPixelNoscript and provideGtmNoscript |
consentlayer/providers/<name> |
One provider factory: ga4, gtm, meta, tiktok, posthog, sentry, contentsquare, hotjar, vercel |
consentlayer/adapters/<name> |
One consent adapter: tcf, shopify, google-consent-mode |
consentlayer/ecommerce |
productParams, cartParams, orderParams |
consentlayer/server |
createAnalyticsHandler, sendServerEvent, createConsentHandler, requestInfo, consent stores |
consentlayer/server/<name> |
One server destination: meta, tiktok, sgtm, ga4 |
consentlayer/sentry/server, consentlayer/sentry/next |
Sentry configuration for Next.js |
consentlayer/testing |
checkPlugin |
consentlayer/react and consentlayer/next start with a 'use client'
directive, so you can import them from a React Server Component without adding
your own client boundary.
The full list of exports is in the API reference.
TypeScript
Section titled “TypeScript”Because the entry points are resolved through the exports field,
TypeScript needs a module resolution mode that reads it. Projects created with
create-next-app already use bundler.
{ "compilerOptions": { "moduleResolution": "bundler" }}With "moduleResolution": "node" (also called node10), imports such as
consentlayer/react fail with error TS2307, “Cannot find module”.
Content Security Policy
Section titled “Content Security Policy”If your site sends a Content Security Policy, allow the scripts ConsentLayer
injects for the providers you use, and the hosts each vendor’s script then
sends data to. meta() and tiktok() also run their vendor’s base code as an
inline script.
With a nonce-based script-src, pass the nonce of the current response to
createAnalytics(). ConsentLayer sets it on every script it injects, inline
or external, so neither the inline base code nor the vendors’ hosts need to
be listed when the policy also has 'strict-dynamic':
const nonce = typeof document === 'undefined' ? undefined : document.querySelector<HTMLScriptElement>('script[nonce]')?.nonce
const analytics = createAnalytics({ nonce, providers: [meta({ pixelId })] })The example reads the nonce from a script your server already gave one, as Google Tag Manager’s own snippet does.
| Provider | script-src |
Data hosts |
|---|---|---|
| GA4 | https://www.googletagmanager.com |
Google’s CSP guide |
| Google Tag Manager | https://www.googletagmanager.com, plus the hosts of each tag in the container |
Google’s CSP guide |
| Meta Pixel | https://connect.facebook.net |
https://www.facebook.com in connect-src and img-src |
| TikTok Pixel | https://analytics.tiktok.com |
Not documented by TikTok |
| Contentsquare | https://*.contentsquare.net |
Contentsquare’s CSP guide |
| Hotjar | https://*.hotjar.com |
Hotjar’s CSP guide |
| Shopify Customer Privacy | https://cdn.shopify.com |
Your checkout domain in connect-src |
| PostHog | Bundled from npm | https://*.posthog.com in connect-src; see PostHog’s CSP guide |
| Sentry | Bundled from npm | The ingest host of your DSN in connect-src; Session Replay also needs worker-src 'self' blob: |
| Vercel Analytics | 'self' |
'self' |
Google’s guide lists more hosts when Google Signals or Ads features are on, and
the Google Tag Manager container runs whatever its tags inject. Tags such as
Custom HTML need 'unsafe-inline', unless you pass nonce: gtm() then
sets it on gtm.js, and Google Tag Manager passes it to the scripts it adds. Meta and TikTok publish no CSP documentation: start from the hosts
above and add those your browser console reports as blocked.
Your own domain
Section titled “Your own domain”Where a vendor supports it, sending data through your own domain shortens the policy, and keeps working when browsers or extensions block the vendor’s hosts:
| Provider | Option | Policy |
|---|---|---|
| GA4, Google Tag Manager | serverContainerUrl, with a server-side GTM container on your domain |
Your container’s origin in connect-src and img-src, and in script-src when it serves the scripts |
| PostHog | apiHost, pointing to a reverse proxy |
'self' or your proxy’s origin |
| Sentry | tunnel, a route on your server |
'self' in connect-src |
A first-party endpoint is something you run and maintain. ConsentLayer doesn’t require it, and it doesn’t change what consent is needed: data sent through your domain still goes to the vendor.
Next steps
Section titled “Next steps”- React: create the instance, add a consent banner and track page views in a React application.
- Next.js: the same in the Next.js App Router, plus server errors and a server-side tracking route.
- Vue: the same with the
consentLayerVue plugin and Vue Router. - Nuxt: the same with the
consentlayer/nuxtmodule and a config file. - Svelte & SvelteKit: the same with
consentLayer()in your root layout or component. - Solid & SolidStart: the same with
<AnalyticsProvider>in the router’s root or around your application. - Angular: the same with
provideConsentLayer()in the application config. - JavaScript and Astro: the same without a framework
binding, with
createConsentController(). - Script tag: ConsentLayer and a ready-made banner from a CDN, for sites without a build step.
- Providers: the options and consent category of each provider.