consent_assessment — v1

Back to project
IDcc9004ee-78ec-4cd3-bb60-e981280bb666
Lensconsent_assessment
Functionassess
Phasediagnosis
Topicsconsent, platform-coverage
Versionv1
Created2026-04-21T08:16:55+00:00

Content

{
  "dimensions": [
    {
      "name": "cmp_identification",
      "findings": [
        {
          "finding": "HubSpot consent banner script is loaded but does not appear to render a visible consent dialog or gate any tags",
          "evidence": "HubSpot banner script loaded from js-na2.hs-banner.com/v2/244051090/banner.js (signal_inventory: 'HubSpot consent banner script load'). However, gcs=G111 in GA4 requests indicates all consent types are granted by default with no user interaction, and dma=1 confirms the site is accessed from a DMA-applicable region (identity_resolution breakpoint: 'No consent management platform banner or consent gate observed').",
          "current_state": "can_be_improved",
          "target_state": "A fully functional CMP (e.g., Cookiebot, OneTrust, or a properly configured HubSpot cookie banner) should be deployed site-wide, presenting a clear consent dialog before any non-essential tags fire, especially for visitors in jurisdictions requiring prior consent (EU/EEA under GDPR, UK).",
          "priority": "high",
          "opportunity": "Deploying and properly configuring a CMP reduces regulatory compliance risk and establishes the foundation for consent-mode-based modelled conversions across Google, Microsoft, and other platforms."
        },
        {
          "finding": "No dedicated third-party CMP (Cookiebot, OneTrust, Usercentrics, Didomi) detected; only the HubSpot built-in banner is present",
          "evidence": "Scan network requests show no requests to cookiebot.com, onetrust.com, usercentrics.eu, didomi.io, or similar CMP vendors. The only consent-related script is js-na2.hs-banner.com/v2/244051090/banner.js loaded by HubSpot.",
          "current_state": "can_be_improved",
          "target_state": "For a site running 8+ ad/analytics platforms across multiple jurisdictions, a dedicated CMP with TCF 2.0 and Google Consent Mode v2 support is recommended over the basic HubSpot banner, which has limited integration capabilities with ad platform consent signals.",
          "priority": "high",
          "opportunity": "A dedicated CMP enables TCF 2.0 signals, Google Consent Mode v2, and per-vendor consent categorisation, unlocking modelled conversions and maintaining compliance across all ad platforms simultaneously."
        }
      ]
    },
    {
      "name": "consent_signal_mechanics",
      "findings": [
        {
          "finding": "Google Consent Mode is effectively in 'granted by default' state with gcs=G111, meaning all consent types (ad_storage, analytics_storage, ad_user_data, ad_personalization) are treated as granted without user interaction",
          "evidence": "GA4 collect request contains gcs=G111 (all consent granted) and gcd=13v3v3v2v5l1. Google Ads conversion request also shows gcs=G111, dma=1, npa=0, and ads_data_redaction=false. The 'G' prefix in gcs indicates consent was granted, and '111' means ad_storage, analytics_storage, and ad_user_data all granted.",
          "current_state": "can_be_improved",
          "target_state": "Google Consent Mode v2 should be implemented with a default state of 'denied' for ad_storage, ad_user_data, and ad_personalization in regions requiring prior consent (EEA/UK). The consent state should update to 'granted' only after explicit user opt-in via the CMP.",
          "priority": "high",
          "opportunity": "Proper Consent Mode v2 implementation with denied defaults enables Google to send cookieless pings for non-consenting users, which feed conversion modelling. This recovers an estimated 20-40% of signal that would otherwise be lost, while maintaining compliance."
        },
        {
          "finding": "Bing UET sends consent signals (both 'default' and 'update') with asc=G indicating all consent granted, but the consent source appears auto-configured rather than CMP-driven",
          "evidence": "Bing UET fires POST to bat.bing.com/actionp/0?ti=97194847&evt=consent&src=update with asc=G (granted) and separately &src=default with asc=G. The 'update' fires before 'default', suggesting the consent state was immediately overridden to granted without user action.",
          "current_state": "can_be_improved",
          "target_state": "Bing UET consent signals should be driven by actual CMP consent decisions, with the default state reflecting 'denied' in applicable regions and updating to 'granted' only after user opt-in.",
          "priority": "medium",
          "opportunity": "Correct Bing consent signalling enables Microsoft's consent-mode equivalent, allowing modelled conversions for Microsoft Ads campaigns and maintaining compliance."
        },
        {
          "finding": "No consent decision persistence mechanism or consent state variable was observed in the dataLayer",
          "evidence": "DataLayer events contain only gtm.js, gtm.dom, gtm.load, and gtm.scrollDepth. No consent-related dataLayer pushes (e.g., consent_update, cookie_consent_update, or similar) were observed. No gtag('consent', 'default', {...}) or gtag('consent', 'update', {...}) commands were detected in the dataLayer.",
          "current_state": "not_yet_configured",
          "target_state": "Consent decisions should be pushed to the dataLayer as structured events, enabling GTM triggers to conditionally fire tags based on consent state. Consent state should persist via cookies or localStorage across sessions.",
          "priority": "high",
          "opportunity": "DataLayer-driven consent signals allow GTM to properly gate tags by consent category, ensuring only consented tags fire and enabling accurate consent-state-aware measurement."
        }
      ]
    },
    {
      "name": "signal_loss_from_consent",
      "findings": [
        {
          "finding": "Currently zero signal loss from consent because all tags fire unconditionally \u2014 but this represents a compliance risk rather than a measurement strength",
          "evidence": "All 50+ signals in the signal inventory fire on page load regardless of consent state. Google Ads conversion (label=NeCfCNuMwOkaEPa1n68_), GA4 page_view, LinkedIn Insight Tag, Meta Pixel config, Twitter UWT, Bing UET, Reddit Pixel, HubSpot tracking, and PostHog all fire without any consent gate. The gcs=G111 parameter confirms no consent restriction is applied.",
          "current_state": "can_be_improved",
          "target_state": "Tags should be categorised into consent categories (necessary, analytics, advertising) and gated accordingly. With proper consent gating, estimated signal loss of 20-40% for non-consenting users should be offset by consent-mode modelled conversions from platforms that support it.",
          "priority": "high",
          "opportunity": "Implementing proper consent gating eliminates compliance risk from GDPR/ePrivacy violations (which can result in fines up to 4% of global revenue) while consent-mode-aware platforms like Google and Bing can model the missing conversions."
        },
        {
          "finding": "PostHog analytics fires via first-party proxy (kilo.ai/ingest) without any visible consent gating, potentially classifying it as exempt \u2014 but session recording likely requires consent",
          "evidence": "PostHog loads via kilo.ai/ingest/array, kilo.ai/ingest/static/posthog-recorder.js (session recording), kilo.ai/ingest/static/surveys.js, and kilo.ai/ingest/static/dead-clicks-autocapture.js. The first-party proxy makes cookie blocking less effective, but session recording captures detailed user behavior and likely requires analytics or functional consent under GDPR.",
          "current_state": "can_be_improved",
          "target_state": "PostHog session recording and autocapture should be gated behind analytics consent. Basic PostHog analytics (without session recording) could potentially fire under a 'functional/analytics' consent category if justified, but session recording should require explicit opt-in.",
          "priority": "medium",
          "opportunity": "Properly gating PostHog session recording under consent reduces compliance risk while maintaining product analytics capabilities for consenting users."
        },
        {
          "finding": "Bing Clarity (session recording) fires without consent gating, creating compliance exposure",
          "evidence": "Bing Clarity telemetry fires via POST to bat.bing.com/p/insights/c/a with gzipped session recording payload. Clarity scripts load from bat.bing.com/p/insights/t/97194847 and bat.bing.com/p/insights/s/0.8.59, triggered by the Bing UET tag chain. Session recording captures detailed user interactions.",
          "current_state": "can_be_improved",
          "target_state": "Bing Clarity session recording should be gated behind analytics or advertising consent, as it captures detailed user behavior data including mouse movements and interactions.",
          "priority": "medium",
          "opportunity": "Gating Clarity behind consent ensures session recording complies with privacy regulations while still being available for consenting users."
        }
      ]
    },
    {
      "name": "server_side_consent",
      "findings": [
        {
          "finding": "No server-side tag management container (e.g., server-side GTM) detected; all tag execution is client-side",
          "evidence": "All tracking requests originate from client-side scripts loaded via GTM (GTM-MDRNZRFX) or directly embedded. No requests to a server-side GTM endpoint (typically a first-party subdomain like sgtm.kilo.ai or tags.kilo.ai) were observed. The Google Ads conversion request includes capi=1 flag suggesting CAPI intent, but no server-side conversion forwarding was detected.",
          "current_state": "not_yet_configured",
          "target_state": "A server-side GTM container should be deployed to forward consented signals server-side, set first-party cookies server-side (extending cookie lifetime beyond ITP restrictions), and maintain consent state server-side. This is especially important given the capi=1 flag on Google Ads conversions indicating intent for server-side capability.",
          "priority": "medium",
          "opportunity": "Server-side GTM enables first-party cookie setting (extending cookie life to 2+ years vs 7 days under ITP), Enhanced Conversions via server, and consent-aware signal forwarding that is more resilient to ad blockers and browser restrictions."
        },
        {
          "finding": "PostHog is proxied through a first-party endpoint (kilo.ai/ingest) demonstrating server-side proxy capability, but this is not extended to marketing tags",
          "evidence": "PostHog requests are routed through kilo.ai/ingest/array, kilo.ai/ingest/static, kilo.ai/ingest/flags, and kilo.ai/ingest/api/surveys, confirming a first-party proxy pattern. Sentry monitoring also uses a first-party proxy at kilo.ai/monitoring. Neither proxy appears to be used for marketing tag signal forwarding.",
          "current_state": "can_be_improved",
          "target_state": "The existing first-party proxy infrastructure for PostHog and Sentry demonstrates capability. This should be extended to support server-side GTM or similar server-side tag management for marketing signals, enabling consent-aware first-party data collection with improved cookie persistence.",
          "priority": "medium",
          "opportunity": "Extending the existing proxy pattern to marketing signals improves cookie persistence, reduces ad blocker signal loss, and enables server-side consent enforcement."
        },
        {
          "finding": "No Enhanced Conversions or user-provided data matching is configured on any platform, limiting consent-resilient signal recovery",
          "evidence": "Google Ads conversion request contains em=tv.1 indicating no email hash is provided. Meta Pixel config loads but no fbq('init', ..., {em:...}) user data was observed. LinkedIn attribution_trigger has no hashed PII. No server-side conversion API (Google CAPI, Meta CAPI, LinkedIn CAPI) traffic was detected.",
          "current_state": "not_yet_configured",
          "target_state": "Enhanced Conversions should be enabled for Google Ads (hashed email/phone in conversion requests), Meta Conversions API should be implemented, and LinkedIn CAPI should be configured. These allow consent-compliant first-party data matching that works even when third-party cookies are unavailable.",
          "priority": "high",
          "opportunity": "Enhanced Conversions and server-side APIs are the primary mechanisms for maintaining attribution accuracy in a consent-constrained, cookieless environment. They can recover 5-15% additional conversion signal."
        }
      ]
    },
    {
      "name": "consent_aware_platform_coverage",
      "findings": [
        {
          "finding": "Google (GA4 + Google Ads) supports Consent Mode but it is not properly configured \u2014 all signals fire as if fully consented, eliminating the modelled conversion benefit",
          "evidence": "GA4 requests contain gcs=G111 and Google Ads requests contain gcs=G111, both indicating full consent granted. Google Consent Mode v2 parameters are present (gcd=13v3v3v2v5l1, dma=1, dma_cps=a) but the consent state never transitions from granted to denied, so Google's conversion modelling for non-consenting users cannot activate.",
          "current_state": "can_be_improved",
          "target_state": "With properly denied defaults in Consent Mode v2, Google sends cookieless pings that feed conversion modelling. At typical 60-80% consent rates, Google can model the remaining 20-40% of conversions, maintaining Smart Bidding signal quality. This requires the consent default to be 'denied' for ad_storage and ad_user_data.",
          "priority": "high",
          "opportunity": "Proper Consent Mode v2 activation is Google's primary consent-resilient measurement mechanism. Without it, the site cannot benefit from Google's modelled conversions when consent is denied, creating a cliff-edge signal loss when proper consent gating is eventually implemented."
        },
        {
          "finding": "LinkedIn, Twitter/X, Reddit, and Impact.com have no consent-mode equivalent \u2014 these platforms will lose all signal for non-consenting users when consent gating is implemented",
          "evidence": "LinkedIn Insight Tag (pid=7288028), Twitter UWT (txn_id=tw-pfume-pyq3r, pfume), Reddit Pixel (a2_gws68xi53fgh), and Impact Universal Tag fire client-side with no consent-mode fallback mechanism. None of these platforms support cookieless pings or modelled conversions.",
          "current_state": "can_be_improved",
          "target_state": "For platforms without consent-mode support, server-side conversion APIs should be configured (LinkedIn CAPI, Twitter Conversions API) to send consented conversion data server-side. For top-of-funnel signals, accept the signal loss for non-consenting users and focus measurement resilience on server-side conversion feedback.",
          "priority": "medium",
          "opportunity": "Server-side APIs for LinkedIn and Twitter maintain conversion signal quality regardless of client-side consent state, preventing measurement blind spots on these platforms."
        },
        {
          "finding": "Meta Pixel is loaded but no conversion events were observed \u2014 and Meta has no Consent Mode equivalent, requiring CAPI for consent-resilient measurement",
          "evidence": "Meta Pixel (498148151146096) config loads via connect.facebook.net/signals/config but no fbq('track', ...) conversion events were captured. Meta's measurement relies on _fbp cookie and CAPI for consent-resilient attribution. No Meta Conversions API (server-side) traffic was observed.",
          "current_state": "not_yet_configured",
          "target_state": "Meta Conversions API (CAPI) should be implemented server-side to send conversion events with hashed user data. This provides redundant signal that works regardless of client-side consent state and cookie availability, maintaining Meta's attribution and optimization capabilities.",
          "priority": "high",
          "opportunity": "Meta CAPI is essential for maintaining measurement quality on Meta Ads. Without it, consent-gating the Meta Pixel will eliminate all Meta conversion signal for non-consenting users, degrading campaign optimization."
        },
        {
          "finding": "Bing UET supports a consent mode equivalent (asc parameter) but it is auto-granted without CMP integration",
          "evidence": "Bing UET consent requests contain asc=G (granted) with both src=update and src=default. The cdb=AQAS parameter indicates consent database support. Bing supports modelled conversions when consent is denied, similar to Google's approach.",
          "current_state": "can_be_improved",
          "target_state": "Bing UET should be integrated with the CMP so that asc reflects actual consent state. When consent is denied, Bing can model conversions similarly to Google Consent Mode, maintaining Microsoft Ads optimization signal.",
          "priority": "medium",
          "opportunity": "Properly configuring Bing's consent signalling enables Microsoft's conversion modelling for non-consenting users, maintaining campaign optimization quality for Microsoft Ads."
        }
      ]
    },
    {
      "name": "compliance_and_configuration",
      "findings": [
        {
          "finding": "All advertising and analytics tags fire before any consent is obtained, representing a significant compliance violation risk under GDPR, ePrivacy Directive, and DMA",
          "evidence": "The dma=1 parameter in Google requests confirms the site is accessed from a DMA-applicable region. Despite this, all tags fire immediately: GA4 page_view, Google Ads conversion (bttype=purchase), LinkedIn Insight Tag, Meta Pixel, Twitter UWT, Bing UET + Clarity, Reddit Pixel, and HubSpot tracking all fire on page load without waiting for consent. The HubSpot banner script loads but no consent interaction was required before tag execution.",
          "current_state": "can_be_improved",
          "target_state": "In EU/EEA/UK, non-essential cookies and tracking technologies must not fire until the user provides explicit consent (opt-in). Tags should be categorised as: necessary (Sentry error monitoring \u2014 can fire immediately), analytics (GA4, PostHog, HubSpot analytics \u2014 require analytics consent), advertising (Google Ads, Meta, LinkedIn, Twitter, Bing, Reddit \u2014 require advertising consent).",
          "priority": "high",
          "opportunity": "Correct consent gating eliminates regulatory risk from GDPR enforcement (fines up to \u20ac20M or 4% of global turnover), DMA compliance requirements for gatekeeper platforms (Google, Meta), and ePrivacy cookie consent requirements."
        },
        {
          "finding": "Google Ads conversion tag with bttype=purchase fires on every page load with value=0, which is a misconfiguration independent of consent but exacerbated by the lack of consent gating",
          "evidence": "Google Ads conversion request to googleadservices.com contains en=conversion, label=NeCfCNuMwOkaEPa1n68_, bttype=purchase, value=0 firing on the homepage. This fires via GTM on every page load. The gcl_ctr=1~0~0~0 confirms no gclid cookie is present, and em=tv.1 confirms no enhanced conversion data.",
          "current_state": "can_be_improved",
          "target_state": "The purchase conversion should only fire on actual purchase confirmation pages with dynamic revenue values and transaction IDs. This is a tag configuration issue that should be resolved alongside consent implementation to ensure that when consent-gated conversion tracking is implemented, it tracks meaningful conversions.",
          "priority": "high",
          "opportunity": "Fixing this misconfiguration prevents inflated conversion counts that corrupt Smart Bidding optimization. Combined with consent gating, this ensures Google Ads receives accurate, consent-compliant conversion data."
        },
        {
          "finding": "ads_data_redaction is explicitly set to false, meaning user data is not redacted even when it should be under restricted consent scenarios",
          "evidence": "Google Ads conversion request contains data=ads_data_redaction%3Dfalse explicitly in the query string. This parameter should be set to true when consent for ad_user_data or ad_personalization is denied, to redact ad click identifiers from requests.",
          "current_state": "can_be_improved",
          "target_state": "ads_data_redaction should dynamically reflect the consent state: when ad_user_data consent is denied, ads_data_redaction should be true to strip click identifiers and ensure compliance with data minimisation requirements.",
          "priority": "high",
          "opportunity": "Dynamic ads_data_redaction ensures that even when tags fire in consent-mode (cookieless pings), user data is properly redacted, maintaining compliance and enabling Google's modelling without exposing personal data."
        },
        {
          "finding": "No consent audit trail or consent logging mechanism was observed",
          "evidence": "No requests to consent logging endpoints, consent receipt APIs, or consent management dashboards were detected in the scan. The HubSpot banner script loads but no consent decision storage or transmission was observed beyond the banner script itself.",
          "current_state": "not_yet_configured",
          "target_state": "Consent decisions should be logged with timestamps, consent version, and user identifiers for audit purposes. This is required under GDPR Article 7 to demonstrate that consent was validly obtained. Most dedicated CMPs provide this automatically.",
          "priority": "medium",
          "opportunity": "Consent audit trails provide defensibility in regulatory investigations and demonstrate good-faith compliance efforts, reducing risk of enforcement actions."
        }
      ]
    }
  ]
}