consentpro-v2
2.6.2
Patch Changes
- a8ee5ce: Generate unique IDs for category and provider accordion panels so each preferences trigger references its own panel through aria-controls.
2.6.1
Patch Changes
- Updated dependencies [3dc13a0]
2.6.0
Minor Changes
9518dbb: Add Cookie Manager locale purposes and overlay them on preferences and cookie declaration after publish.
Draft translations live in D1 (
config_tracker_translations) and are not live on save. Publish writes a per-hostname R2 sibling attranslations/v2/...and purges it with the runtime cache. Visitors fetchGET /v3/cdn/translations/:siteId.jsononly when opening preferences or hydrating the cookie declaration; banner blocking still uses the inlined purpose.Production: apply D1 migration
0049_flat_leper_queen(wrangler d1 migrations apply DB --env production --remote) and confirm it withwrangler d1 migrations list DB --env production --remotebefore this Designer UI ships.GET /v3/projects/:id/languageshas no fallback ifsupported_languagesis missing.
Patch Changes
bb844a5: Add a Corner style option to banner styling for custom sites, switching the banner between its default, rounded and square corners.
The web app's banner style step gains a Corner style picker, stored per banner as
corner_styleand published to the runtime asstyle.cornerStyle. The runtime maps it to the banner's radius tokens:Corner style Buttons & badges ( --consentpro-radius-sm)Surfaces ( --consentpro-radius-md)Default SDK default SDK default Rounded 999px(pill)0.75remSquare 00The field is optional. Banners without it, and every Webflow site, keep the SDK's own radii.
bb844a5: Refetch the preview config when the visitor refreshes a preview page, so the latest unpublished changes show up. The debugger's own same-token navigations still reuse the loaded preview.
Updated dependencies [bb844a5]
Updated dependencies [c3fe401]
2.5.4
Patch Changes
bad22ee: Send the Google Consent Mode
updatewhen the site scanner asks for a consent mode.Separating defaults from updates in 2.5.3 made the
updateconditional on a stored choice or a GPC signal. A scan has neither: it carries no consent cookie and sends no GPC. The runtime therefore sent no Consent Mode signal at all, the container kept the template's denieddefault, and every consent-gated tag was withheld for the whole scan. Sites with a correct installation were reported as having no analytics cookies, because the scanner never saw the trackers it exists to find.The scanner announces itself with
consentpro-scannercontext, which now counts as a consent signal in its own right. The runtime sends the state the scan asks for, extending the 2.5.3 table:Situation Runtime behaviour Scan with consentpro-scannercontext=opt-out(accept all)updategranting every category, so all tags are observableScan with consentpro-scannercontext=opt-inupdatedenying every non-essential categoryThis also removes an older branch that skipped the update outright in
opt-inscanner context. It predated the defaults and updates split and would have kept the public scanner silent rather than sending the denied state it asks for.Visitor behaviour is unchanged. A page without the scanner parameters follows exactly the lifecycles 2.5.3 defines, so an opt-in visitor still receives nothing before choosing.
2.5.3
Patch Changes
9e01f4e: Stop sending a Google Consent Mode
updatebefore a visitor has made a consent choice, unless GPC applies.The runtime initialized
consentChoicesfromdefaultChoicesand pushed that straight to GTM, so a first-time visitor received anupdatebuilt from defaults they never chose. The Consent Pro GTM template already declares that state during Consent Initialization, so the runtime was duplicating thedefaultas a choice.Consent Mode updates and activation events now follow separate lifecycles:
Situation Runtime behaviour Opt-in banner, no stored choice No updateor activation events. The template owns the default.Opt-out, Don't Sell or Informational banner, no stored choice No update; emit activation events for permitted tags.GPC signal on an Opt-out or Don't Sell banner updatewith the opt-out the signal asks for.Visitor accepts, rejects or changes preferences updatewith the new choices and emit activation events.Returning visitor with a stored choice updaterestoring the stored choices and emit events.Opt-out, Don't Sell and Informational banners allow tracking until the visitor opts out. Their granted baseline remains a GTM
default, while the runtime still emitsconsent-updatedand<category>-activateddata layer events for permitted marketing and non-Google tags.This assumes the Consent Pro Init tag is installed on the Consent Initialization trigger, as the GTM setup guide requires. Without it nothing declares the denied
default, and an unset Consent Mode state behaves as granted.References:
2.5.2
Patch Changes
- d369b9f: Keep Banner Type and Geolocation aligned, and skip a second reload when the same preview token is already loaded.
- Updated dependencies [36435b2]
2.5.1
Patch Changes
fecdc78: Drive the custom-site "Powered by Consent Pro" mark from the project's own config.
The mark was decided entirely by plan tier: the served script inlined
window.fs_consent_pro_attribution = truefor free-tier sites and nothing else ever set it, so a paid custom site never showed it and the app's "Hide Consent Pro logo" toggle changed nothing outside the in-app preview. Preview links were worse —applyStoredreassigns the global from the fetched payload, which never carriesattribution, so a preview dropped the mark even on the free tier.consentpro-types
ConsentProV2RuntimeConfigurationgainshideBranding, carried through to the sanitized client config.
server
projectConfigToRuntimemapsbanner_settings.hide_brandingonto it, so it ships with every publish and with the preview config.
consentpro-v2
- Custom sites resolve
showAttributionfrom that config, defaulting to showing the mark. The free tier's license-derived global still wins, so a free site cannot switch it off.
9a490af: Pick the "Powered by Consent Pro" logo colour from the banner background.
consentpro-utils
- New
relativeLuminanceandcontrastingMonochromehelpers: WCAG 2.1 relative luminance, and a black/white pick by contrast ratio against a background.
web-components
ConsentBanner's wordmark now reads--consentpro-color-attribution, falling back to the banner's own text colour. The wordmark is alreadycurrentColor, so the variable flips it; the "Powered by" label keeps the banner's text colour.
consentpro-v2 / web-app
- Both set
--consentpro-color-attributionfrom the banner background, so the live banner and the style preview render the same logo.
- New
fecdc78: Fix the custom-site opt-in banner rendering without its reject button.
The button set only ever reached the runtime through the CDN copy fetch, so any failed fetch left
<consentpro-banner>on its own defaults, which show preferences and accept but defaultshowDenyButtontofalse. An opt-in banner rendered accept-only, silently, which is a consent-compliance failure rather than a cosmetic one. One way to trigger it:instanceConfigwrites theconsentpro-modequery param intobannerType, but that param can carry an instance key rather than a banner type (the debugger's keys are region-derived), and the copy request forus-or400s.consentpro-dictionary
BANNER_STRUCTUREand itsBannerStructuretype move to their own module and are exported fromconsentpro-dictionary/consent-copy. The record is unchanged; it was already locale-independent, so nothing about the served copy changes.- New
getBannerStructure(method)resolves an unvalidated banner type, falling back to theopt-instructure — the only one that always offers a deny button — rather than returningundefined.
consentpro-v2
- The custom-site banner resolves its button structure locally from
bannerTypeand layers the fetched copy's strings on top, so the button set no longer depends on the network.showGpcNoticeis now derived from the same local structure gated on the visitor's GPC signal, instead of from the fetched copy. instanceConfig's handling ofconsentpro-modeis left alone deliberately: it is shared with Webflow sites, and the local structure fallback already keeps the banner compliant for the unvalidated types it produces.- A failed copy fetch warns to the console instead of being swallowed, so a banner falling back to English defaults is diagnosable.
8384efa: Show a placeholder overlay on iframes blocked for want of consent on custom (non-Webflow) sites.
Custom sites have no pasted
fs-consent-element="placeholder"markup, so a blocked embed simply lost itssrcand rendered as a blank box. The overlay now ships as a web component thatcore/v2swaps into the blocked iframe itself.web-components
- New
<consentpro-placeholder>custom element, built as its ownplaceholder.jsCDN bundle. Like every other component in this package, its props are plain JS properties observed as no attribute, and its buttons dispatch bubbling, composedconsentpro:open-preferences/consentpro:allowevents.
consentpro-dictionary
getConsentCopyreturns aplaceholderblock (message,preferencesText,acceptAllText), so the overlay is localized like every other component.
server
GET /v2/cdn/web-components/placeholder.jsserves the new bundle, andcopy.jsoncarries theplaceholderstrings.
consentpro-v2
new/custom-site/placeholder.tsbuilds the blocked iframe's document as a string, which the existing blob path swaps into the iframe'ssrc. It is self-contained: the CDN module that registers the element, plus the script that waits for that registration, creates the element and assigns the copy as JS properties. No markup is parsed, mutated or serialized on the way, and the copy is escaped into the script rather than interpolated into HTML.- That script tag is pinned with the build-time
sha384hash, soplaceholder.jsis now SRI-checked like the other component bundles. - Blocked iframes wire the overlay's events through
custom-site/events.ts: the document is a same-originblob:, so the component'sconsentpro:*events reach the consent-state layer directly. - A blocked iframe's own
sandboxis stashed and dropped while the placeholder is shown, then restored verbatim before the original URL loads again. It applies to the untrusted embed, not to our placeholder, and withoutallow-scriptsit kept the overlay from ever rendering. iframe-blockednow fires once per blocked iframe, carrying the embed's URL. Re-rendering a placeholder whose copy arrived late no longer emits a second event whosesrchad already been replaced.
- New
d3e426d: Link the custom-site banner to the project's own privacy policy, or show no link at all.
The custom-platform banner always rendered a dead
<a href="#">Privacy Policy</a>: the project's privacy-policy URL never reached the runtime.consentpro-dictionary
getConsentCopyreturnsmessageHtmlWithoutPrivacyLinkalongsidemessageHtml— the same message with the whole privacy sentence removed, cut from the tokenized template so every locale ends on its own sentence terminator.messageHtmlis unchanged.
server / consentpro-types
privacy_page_urlmaps tolegal.privacyPolicyUrl, andsanitizeConfigForClientpublishes that one field.cookiePolicyUrlandcontactEmailstay server-side.
consentpro-v2
- The custom-site banner points the anchor at the configured URL (normalized through
new URL()and restricted to http(s), opened in a new tab), and drops the privacy sentence when no URL is configured.
8eefb34: Withdraw the GPC notice on custom sites the moment a visitor consents.
The notice was resolved once while the elements were built and never revisited, so a visitor who knowingly accepted while a GPC signal was active kept seeing the honored notice for the rest of the page load, in both the banner and the preferences panel. It now tracks the same
GPC.honoredstate the Webflow elements do, which § 7025(c)(6) requires from 1 January 2026.d7331e4: Style the preferences toggle and the dialog backdrop from the web app.
web-app
- The Open preferences colours card now carries Toggle Inactive Track, Toggle Active Track (the former "Preferences Checkbox"), Toggle Circular Handle and Preferences Overlay. Left on their defaults the columns stay
null, so an existing banner looks exactly as before. ColorFieldtakes analphaprop: an opacity track under the hue slider, a checkerboard behind every swatch, and a hex field that accepts#rrggbbaa. Only the overlay opts in — a colour that paints a surface has nothing to be translucent over.- The overlay starts at no backdrop (
#00000000). Choosing a colour on a transparent field lands at 20% opacity rather than staying invisible; the opacity track can still take it back to nothing.
web-components
ConsentPreferencesDialog's backdrop default drops from 10% black totransparent: a dialog washes the page only where a site asks for it. The backdrop box is unchanged otherwise, so click-to-close still works, and any site setting--consentpro-color-overlayis unaffected.
server / consentpro-types
checkbox_inactive_color,checkbox_handle_colorandpreferences_overlay_colorare read, validated and saved onbanner_settingsandbanner_instances, and published ascheckboxInactive,checkboxHandleandpreferencesOverlay. The overlay column validates#rrggbbor#rrggbbaa; the rest stay six digits.
consentpro-v2
- Maps those to
--consentpro-color-toggle-off,--consentpro-color-toggle-thumband--consentpro-color-overlay. The handle keeps whatever colour is picked in both switch states — nothing recolours it from the track any more.
- The Open preferences colours card now carries Toggle Inactive Track, Toggle Active Track (the former "Preferences Checkbox"), Toggle Circular Handle and Preferences Overlay. Left on their defaults the columns stay
Updated dependencies [9a490af]
Updated dependencies [fecdc78]
Updated dependencies [8384efa]
Updated dependencies [d3e426d]
2.5.0
Minor Changes
6757be6: Honor a GPC signal that post-dates a visitor's stored consent.
Previously the GPC signal only decided the defaults, so a visitor who consented first and enabled GPC afterwards kept their old consent indefinitely — while the banner still claimed the signal had been honored. The signal is now treated as a live opt-out request that wins over consent saved before it arrived, and a consent given knowingly after the signal was honored wins in turn (CCPA § 7025(c)(3)). The most recent expression of the visitor's preference governs.
consentpro-v2
- The consent cookie gains
gpcHonoredAt: when the runtime first observed the signal that was still active as of that write. It is stamped on every write made while the signal is present and cleared on writes made while it is absent, which is what distinguishes consent given before the signal from consent given knowingly after it. Browsers expose no "enabled at" timestamp, so this is the only recency information available. - On page load, a stored consent that still grants a non-essential category and predates the signal is revoked before blocking, trackers and analytics initialize — so no tracker ever sees the stale consent, and cookies set under the revoked categories are cleaned up on the same load. A consent record is written with
action: 'reject_all'andsource: 'gpc', and is never collapsed into a consent the visitor gives in the second that follows: a processed opt-out request is a compliance event in its own right, not an intermediate state. - The revocation runs only on pages the resolved instance is configured for. On an excluded page nothing can block a tracker or clean up a cookie, so recording an opt-out there would claim an enforcement that never happened; the stored consent is left untouched until the visitor reaches a managed page.
- Consent records now carry the id, action and source captured when the write happened, instead of reading them from the stores when the debounced request fires. Previously any two writes inside a second could hand the first record the second one's attribution.
- The banner is re-shown once on the page load where a category was actually revoked, so the visitor is told their saved preferences changed and gets the chance to consent knowingly instead.
fs-consent-gpcnow reflects whether the signal is being processed, not merely present, and updates live: it flips to"false"the moment a visitor accepts while a signal is active, hiding[fs-consent-element="gpc-honored"]rather than leaving a claim in place that is no longer true. This matters for § 7025(c)(6), which as of 1 January 2026 requires displaying whether the signal was processed.- Scope is unchanged: only Opt-Out and Do Not Sell instances. Opt-In consent is never revoked, and
fs-consent-gpcstays"false"on those instances: the attribute now tracks the same condition the behavior does, so it never claims a signal was processed where nothing acts on one. - A stored consent whose
gpcHonoredAtequals its owntimestampcounts as a knowing override rather than a consent the signal outranks. The two can only match when they were written together, which a consent predating the signal never is — and a custom integration writing the cookie by hand can land both in the same millisecond. FinsweetConsentPro.consents.set()now stampsaction: 'submit'andsource: 'api', like every other write path. Previously it inherited whatever wrote the consent before it, which with GPC in play would have recorded a site's own API call as a GPC-driven opt-out. It also means API-driven consent is recorded at all, where before the missing action caused the record to be dropped.
Existing GPC visitors who had granted consent are opted out once, on their next page view, and see the banner that one time.
documentation
developer/custom-integration.mddocumentsgpcHonoredAtand shows how to carry it forward when writing the cookie by hand. A custom integration that omits the stamp while a signal is active writes a consent that Consent Pro cannot distinguish from one given before the signal, and revokes on the visitor's next Webflow page view.
consentpro-types / server
ConsentSourceandConsentRecordSchema.sourceaccept'gpc'. The consents endpoint validates against that enum, so without this the GPC records would be rejected and silently dropped.
- The consent cookie gains
Patch Changes
2.4.2
Patch Changes
- Updated dependencies [f528b4f]
2.4.1
Patch Changes
- 2836963: fix: send only a Google Consent Mode
updatefrom the runtime and leave the baselinedefaultto the Consent Pro GTM template, which declares it at container initialization
2.4.0
Minor Changes
55656ae: Add optional public hostname and path prefix so reverse-proxied sites publish a hostname.json for the visitor host and expose the site information the runtime uses to compose public URLs.
The Webflow domain is unchanged. Custom-domain sites publish
publicHostnameand, when mounted under a prefix,pathPrefix. The runtime composes these with locale subdirectories and page slugs. Sites without these settings are unaffected.
Patch Changes
- Updated dependencies [55656ae]
2.3.6
Patch Changes
- f4354d3: fix: do not block Google Tag Manager container scripts (
gtm.js?id=GTM-*)
2.3.5
Patch Changes
03bd744: chore(deps): resolve open Dependabot PRs and clear the
pnpm auditbacklogDirect dependency updates:
app: axios 1.16.0 → 1.18.0, posthog-js 1.336.1 → 1.417.0consentpro-v1: nanoid 5.1.6 → 5.1.16, esbuild 0.27.3 → 0.28.1consentpro-v2: esbuild 0.27.3 → 0.28.1server: hono 4.12.21 → 4.12.34consentpro-debugger: vite 7.3.2 → 7.3.6
Transitive advisories are pinned to patched versions via
pnpm.overrides(tar, undici, brace-expansion, js-yaml, protobufjs, fast-uri, ip-address, postcss, nanoid, form-data, ws, adm-zip, shell-quote, sharp, dompurify, esbuild), takingpnpm auditfrom 89 findings (1 critical, 41 high, 35 moderate, 12 low) to 0.The posthog-js bump also removes the
@opentelemetry/*andprotobufjssubtrees, which were never reachable from the shipped extension bundle. Telemetry configuration is unchanged and the pinneddefaults: '2025-05-24'still applies, so capture behaviour is identical.Two advisories have no published fix and are recorded in
pnpm.auditConfig.ignoreCvesrather than resolved — CVE-2026-56876 (extract-zip, via@cloudflare/puppeteer) and CVE-2025-14505 (elliptic, via@webflow/webflow-cli). Neither is reachable from a shipped artifact.
2.3.4
Patch Changes
- Updated dependencies [4d7fcb3]
2.3.3
Patch Changes
3ea0afe: Ensure a project record per site, and dual-write core config to D1.
server
- New
services/v2/projects:ensureProject,getProjectUuidBySiteId,linkSiteAuthorizationProject. Project creation is idempotent and race-safe, and revives a soft-deleted project on re-authorization. - The Webflow OAuth callback creates the project and stamps it onto the site authorization on first authorization. Failures are logged and never block authorization.
- Temporary R2 → D1 dual-write (
configurator/temporary-d1-mirror):saveCoreConfigand site migration mirror the core runtime config intoproject_configs,webflow_project_configs,banner_instances,config_providersandconfig_trackers. R2 stays the source of truth and the mirror soft-fails, so a D1 error can never fail a publish. Sites only begin mirroring once they have a project row, so existing sites stay unmirrored until they re-authorize. project_uuidis stamped on scans, scan schedules, action item resolutions, policy profiles and policy documents, without overwriting a value that is already set.- Schema:
project_uuidforeign keys move fromON DELETE set nulltoON DELETE cascade, andproject_configsgainslocales. - Migrations
0038(addsproject_configs.locales) and0039(the foreign key change).0039is hand-written rather than drizzle-generated: the generated table rebuild issuesDROP TABLE, which on D1 fires the pre-existingpolicy_documents→policy_profilescascade and empties the table, because D1 runs each migration inside a transaction wherePRAGMA foreign_keys=OFFis silently ignored. It usesALTER TABLE DROP COLUMN/ADD COLUMNinstead, so no table is ever dropped. Side effect:project_uuidbecomes the last column on the six affected tables.
consentpro-v2
- The consent cookie is now always written with
sameSite: 'lax', andsecureis derived fromlocation.protocolinstead of configuration.storage.sameSiteandstorage.secureare no longer read by the v2 runtime.
consentpro-types
ConsentV2TrackerDefinitiongains an optionalnameforcookietrackers and an optionalkeyforlocal-storage/session-storagetrackers.
- New
34c5fc6: fix: invalidate stored consent cookie when the user changes region
2.3.2
Patch Changes
- Updated dependencies [a0173e0]
- Updated dependencies [81c0689]
- Updated dependencies [3fb6710]
- Updated dependencies [9d4c732]
2.3.1
Patch Changes
cb1d15a: chore: cleanup runtime bundle to remove non-prod strings and ensure proper treeshake
2487ddd: feat: runtime unblocking for manually blocked images
- Added
blocking/images.tsto the v2 runtime: images holding their URL infs-consent-srcwithfs-consent-categoriesare loaded automatically once the visitor accepts the required categories, and unloaded again when consent is revoked. Unblock-only by design — a live imagesrcfires its request immediately and cannot be intercepted. - Emit
image-blocked/image-unblockedevents, mirroring iframes. - Simplified the Consent Manager image instructions and docs: the manual consent-callback snippet is no longer needed, only the attribute swap.
- Added
Updated dependencies [cb1d15a]
2.3.0
Minor Changes
- f4ab509: feat: debugger auth
- 4435f7e: feat: same-origin library imports
Patch Changes
- 46a579b: chore: do not include license in CDN response
- 20a5755: fix: only load debugger in staging webflow.io
- 1f19ea2: fix: allow no animations
- 5407450: fix cookie declaration hydration
- fa75381: Enhance policy generator
- Updated dependencies [494b74c]
- Updated dependencies [73a3472]
- Updated dependencies [5407450]
2.2.9
Patch Changes
- Updated dependencies [e5d2aad]
2.2.8
Patch Changes
- Updated dependencies [353af98]
2.2.7
Patch Changes
- 023a021: fix(v2): apply overflow lock on iOS when disabling scroll
- 4edff91: fix: update show function to display banner when preferences element is absent; add test for re-showing banner without preferences element
2.2.6
Patch Changes
- ded7f80: update namings in usages of
consent-pro-**toconsentpro-** - 73aa49f: feat: consent pro debugger
- Updated dependencies [ded7f80]
- Updated dependencies [73aa49f]
2.2.5
Patch Changes
- Updated dependencies [ef22755]
- Updated dependencies [9cf51bd]
2.2.4
Patch Changes
- 9309ade: fix: preserve scroll on scrollable children
2.2.3
Patch Changes
- 9f95405: fix: make GPC flexible to anyone with GPC enabled, not just specific regions
- Updated dependencies [1a79dde]
2.2.2
Patch Changes
- ba3df41: fix: respect original script
typeafter unblocking - Updated dependencies [1a79dde]
2.2.1
Patch Changes
- 02e434b: fix: prevent race conditions when interacting with third party libraries
- c1bc061: fix: correct event listener target from window to document in waitDOMReady function
2.2.0
Minor Changes
- 6509630: feat: disable scroll behavior controls
Patch Changes
2.1.2
Patch Changes
- 683eeb0: chore: Update dependencies to latest versions across all packages and fix pnpm audit issues
2.1.1
Patch Changes
- ef4a3e5: fix(core-v2): remove double URL-encoding of fs-consent cookie
- js-cookie already calls handles encoding and decoding
- add test for it and for backward compatible encoded versions
2.1.0
Minor Changes
- 7cd69e6: feat: support clicks in blocked iframes
- 171ba65: feat: support blocking iframes inside Webflow lightboxes
- 0f15342: feat: support GPC signal
Patch Changes
- 3beee94: fix: unblock essential scripts marked with type="fs-consent"
- 171ba65: fix: don't process application/json scripts
- 7caea86: fix: flash of unstyled content when elements exist visible on the current page
- 7e10aef: fix: ensure that elements outside the shadow root are hidden
- 171ba65: fix: remove false positives in
iframe-blockedAPI events - f083ccd: improvement: no longer store provider & tracker metadata in each consent log
- 171ba65: fix: recursively process deeply nested nodes with the mutation observer
- 2a279e8: fix: only load consent pro when there is a matching region
- 9ad2133: fix: allow clicks outside preferences when focus-trap is activated
- Updated dependencies [e9bd587]
- Updated dependencies [6029a6c]