Skip to content

consentpro-v2

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 = true for 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 — applyStored reassigns the global from the fetched payload, which never carries attribution, so a preview dropped the mark even on the free tier.

    consentpro-types

    • ConsentProV2RuntimeConfiguration gains hideBranding, carried through to the sanitized client config.

    server

    • projectConfigToRuntime maps banner_settings.hide_branding onto it, so it ships with every publish and with the preview config.

    consentpro-v2

    • Custom sites resolve showAttribution from 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 relativeLuminance and contrastingMonochrome helpers: 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 already currentColor, so the variable flips it; the "Powered by" label keeps the banner's text colour.

    consentpro-v2 / web-app

    • Both set --consentpro-color-attribution from the banner background, so the live banner and the style preview render the same logo.
  • 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 default showDenyButton to false. An opt-in banner rendered accept-only, silently, which is a consent-compliance failure rather than a cosmetic one. One way to trigger it: instanceConfig writes the consentpro-mode query param into bannerType, but that param can carry an instance key rather than a banner type (the debugger's keys are region-derived), and the copy request for us-or 400s.

    consentpro-dictionary

    • BANNER_STRUCTURE and its BannerStructure type move to their own module and are exported from consentpro-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 the opt-in structure — the only one that always offers a deny button — rather than returning undefined.

    consentpro-v2

    • The custom-site banner resolves its button structure locally from bannerType and layers the fetched copy's strings on top, so the button set no longer depends on the network. showGpcNotice is now derived from the same local structure gated on the visitor's GPC signal, instead of from the fetched copy.
    • instanceConfig's handling of consentpro-mode is 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 its src and rendered as a blank box. The overlay now ships as a web component that core/v2 swaps into the blocked iframe itself.

    web-components

    • New <consentpro-placeholder> custom element, built as its own placeholder.js CDN bundle. Like every other component in this package, its props are plain JS properties observed as no attribute, and its buttons dispatch bubbling, composed consentpro:open-preferences / consentpro:allow events.

    consentpro-dictionary

    • getConsentCopy returns a placeholder block (message, preferencesText, acceptAllText), so the overlay is localized like every other component.

    server

    • GET /v2/cdn/web-components/placeholder.js serves the new bundle, and copy.json carries the placeholder strings.

    consentpro-v2

    • new/custom-site/placeholder.ts builds the blocked iframe's document as a string, which the existing blob path swaps into the iframe's src. 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 sha384 hash, so placeholder.js is 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-origin blob:, so the component's consentpro:* events reach the consent-state layer directly.
    • A blocked iframe's own sandbox is 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 without allow-scripts it kept the overlay from ever rendering.
    • iframe-blocked now fires once per blocked iframe, carrying the embed's URL. Re-rendering a placeholder whose copy arrived late no longer emits a second event whose src had already been replaced.
  • 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

    • getConsentCopy returns messageHtmlWithoutPrivacyLink alongside messageHtml — the same message with the whole privacy sentence removed, cut from the tokenized template so every locale ends on its own sentence terminator. messageHtml is unchanged.

    server / consentpro-types

    • privacy_page_url maps to legal.privacyPolicyUrl, and sanitizeConfigForClient publishes that one field. cookiePolicyUrl and contactEmail stay 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.honored state 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.
    • ColorField takes an alpha prop: 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 to transparent: 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-overlay is unaffected.

    server / consentpro-types

    • checkbox_inactive_color, checkbox_handle_color and preferences_overlay_color are read, validated and saved on banner_settings and banner_instances, and published as checkboxInactive, checkboxHandle and preferencesOverlay. The overlay column validates #rrggbb or #rrggbbaa; the rest stay six digits.

    consentpro-v2

    • Maps those to --consentpro-color-toggle-off, --consentpro-color-toggle-thumb and --consentpro-color-overlay. The handle keeps whatever colour is picked in both switch states — nothing recolours it from the track any more.
  • Updated dependencies [9a490af]

  • Updated dependencies [fecdc78]

  • Updated dependencies [8384efa]

  • Updated dependencies [d3e426d]

    • consentpro-utils@2.1.1
    • consentpro-dictionary@0.1.6

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' and source: '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-gpc now 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-gpc stays "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 gpcHonoredAt equals its own timestamp counts 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 stamps action: 'submit' and source: '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.md documents gpcHonoredAt and 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

    • ConsentSource and ConsentRecordSchema.source accept 'gpc'. The consents endpoint validates against that enum, so without this the GPC records would be rejected and silently dropped.

Patch Changes

  • consentpro-dictionary@0.1.5
  • consentpro-utils@2.1.0

2.4.2

Patch Changes

  • Updated dependencies [f528b4f]
    • consentpro-dictionary@0.1.4
    • consentpro-utils@2.1.0

2.4.1

Patch Changes

  • 2836963: fix: send only a Google Consent Mode update from the runtime and leave the baseline default to 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 publicHostname and, 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]
    • consentpro-utils@2.1.0
    • consentpro-dictionary@0.1.3

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 audit backlog

    Direct dependency updates:

    • app: axios 1.16.0 → 1.18.0, posthog-js 1.336.1 → 1.417.0
    • consentpro-v1: nanoid 5.1.6 → 5.1.16, esbuild 0.27.3 → 0.28.1
    • consentpro-v2: esbuild 0.27.3 → 0.28.1
    • server: hono 4.12.21 → 4.12.34
    • consentpro-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), taking pnpm audit from 89 findings (1 critical, 41 high, 35 moderate, 12 low) to 0.

    The posthog-js bump also removes the @opentelemetry/* and protobufjs subtrees, which were never reachable from the shipped extension bundle. Telemetry configuration is unchanged and the pinned defaults: '2025-05-24' still applies, so capture behaviour is identical.

    Two advisories have no published fix and are recorded in pnpm.auditConfig.ignoreCves rather 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]
    • consentpro-dictionary@0.1.2
    • consentpro-utils@2.0.3

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): saveCoreConfig and site migration mirror the core runtime config into project_configs, webflow_project_configs, banner_instances, config_providers and config_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_uuid is stamped on scans, scan schedules, action item resolutions, policy profiles and policy documents, without overwriting a value that is already set.
    • Schema: project_uuid foreign keys move from ON DELETE set null to ON DELETE cascade, and project_configs gains locales.
    • Migrations 0038 (adds project_configs.locales) and 0039 (the foreign key change). 0039 is hand-written rather than drizzle-generated: the generated table rebuild issues DROP TABLE, which on D1 fires the pre-existing policy_documentspolicy_profiles cascade and empties the table, because D1 runs each migration inside a transaction where PRAGMA foreign_keys=OFF is silently ignored. It uses ALTER TABLE DROP COLUMN / ADD COLUMN instead, so no table is ever dropped. Side effect: project_uuid becomes the last column on the six affected tables.

    consentpro-v2

    • The consent cookie is now always written with sameSite: 'lax', and secure is derived from location.protocol instead of configuration. storage.sameSite and storage.secure are no longer read by the v2 runtime.

    consentpro-types

    • ConsentV2TrackerDefinition gains an optional name for cookie trackers and an optional key for local-storage / session-storage trackers.
  • 34c5fc6: fix: invalidate stored consent cookie when the user changes region

    • consentpro-dictionary@0.1.1
    • consentpro-utils@2.0.3

2.3.2

Patch Changes

  • Updated dependencies [a0173e0]
  • Updated dependencies [81c0689]
  • Updated dependencies [3fb6710]
  • Updated dependencies [9d4c732]
    • consentpro-dictionary@0.1.0
    • consentpro-utils@2.0.3

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.ts to the v2 runtime: images holding their URL in fs-consent-src with fs-consent-categories are loaded automatically once the visitor accepts the required categories, and unloaded again when consent is revoked. Unblock-only by design — a live image src fires its request immediately and cannot be intercepted.
    • Emit image-blocked / image-unblocked events, mirroring iframes.
    • Simplified the Consent Manager image instructions and docs: the manual consent-callback snippet is no longer needed, only the attribute swap.
  • Updated dependencies [cb1d15a]

    • consentpro-utils@2.0.2
    • consentpro-dictionary@0.0.11

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]
    • consentpro-dictionary@0.0.10
    • consentpro-utils@2.0.1

2.2.9

Patch Changes

  • Updated dependencies [e5d2aad]
    • consentpro-dictionary@0.0.9
    • consentpro-utils@2.0.1

2.2.8

Patch Changes

  • Updated dependencies [353af98]
    • consentpro-dictionary@0.0.8
    • consentpro-utils@2.0.1

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-** to consentpro-**
  • 73aa49f: feat: consent pro debugger
  • Updated dependencies [ded7f80]
  • Updated dependencies [73aa49f]
    • consentpro-dictionary@0.0.7
    • consentpro-utils@2.0.1

2.2.5

Patch Changes

  • Updated dependencies [ef22755]
  • Updated dependencies [9cf51bd]
    • consentpro-utils@2.0.1
    • consentpro-dictionary@0.0.6

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]
    • consentpro-dictionary@0.0.5
    • consentpro-utils@2.0.0

2.2.2

Patch Changes

  • ba3df41: fix: respect original script type after unblocking
  • Updated dependencies [1a79dde]
    • consentpro-dictionary@0.0.4
    • consentpro-utils@2.0.0

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

  • consentpro-dictionary@0.0.3
  • consentpro-utils@2.0.0

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-blocked API 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]
    • consentpro-utils@2.0.0
    • consentpro-dictionary@0.0.2