script.attributes on a script element, then run gateScripts from @cookiechimp/core/gate. The attributes use data-cc-src, data-cc-category, and data-cc-service, so no gated request starts before consent. Pass the resulting config to blockDynamic from @cookiechimp/core/dynamic as well if third-party code can create scripts.
Call preset.queue.install(window) before application code can call gtag. It preserves early calls in the selected data layer. Pass config.consentMode to installConsentMode from @cookiechimp/core/consent-mode.
GTM uses basic consent mode by default and is gated. With consentMode: "advanced", GTM loads immediately and installing its queue first writes denied Consent Mode v2 defaults before the loader is inserted. GTM adds no Consent Mode mapping of its own: analytics_storage follows the analytics category and the ad signals follow the marketing category, whichever category gates the container.
Other vendors
Each vendor has its own opt-in subpath, so nothing ships unless you import it:
All of them are gated: the loader script is inert (
type="text/plain") until its category is granted. preset.queue.install(window) only creates the vendor’s queue global (fbq, clarity, posthog, analytics, hj, lintrk, ttq) so early calls are kept; it never inserts a script or sends a request.
IDs are checked against a strict pattern and encoded before they are placed in a URL, and loader URLs always use the fixed origin above. PostHog and Segment accept a custom globalName, which must be a plain identifier. Invalid values throw in development and warn in production, where the preset falls back to its default global name or region.
These vendors do not read Google Consent Mode, so they add no Consent Mode mapping. Google signals keep following core’s categories and defaults.
Revoking consent after a vendor script loaded
Gating only stops a script that has not run yet. To reach a script that already loaded, callpreset.sync(consent) with your core consent runtime. It installs the queue stub, applies the current state of the preset’s category, then subscribes to consent changes and calls the vendor’s own consent API whenever that category flips. It returns an unsubscribe function. Changes to other categories make no call. When the vendor script has not loaded yet, the call goes into the stub queue and the vendor replays it on load, so it is never lost.
preset.revoke says what a revoke can do once the script has loaded:
"api"(Meta Pixel, Clarity, PostHog, TikTok): the vendor API is called on every revoke and grant, as in the table above."reload"(Segment, Hotjar, LinkedIn): there is no consent API to call, sosyncmakes no vendor call. The gated script is not injected again until the category is granted, but code that already loaded keeps running until the page reloads. For Segment this means the loaded analytics.js keeps sending events. The SDK never reloads the page for you; checkpreset.revoke === "reload"and reload, or ask the visitor to, when that category is revoked.