Google Consent Mode v2 with FlowConsent
How FlowConsent implements Consent Mode v2: denied defaults before any tag, wait_for_update, cookieless gcs=G100 pings, and lost-race detection.
FlowConsent implements Google Consent Mode v2 out of the box: an inline stub records denied defaults for all four consent signals before any Google tag loads, the banner sends gtag('consent', 'update', …) when the visitor chooses, and Google's cookieless pings (gcs=G100) keep conversion modeling alive without violating a refusal. No extra template, no third-party plugin.
The stub: denied by default, before every tag
Your integration snippet starts with this inline script — it is generated for you in Builder → Deployment → Integration:
<script>
window.dataLayer=window.dataLayer||[];
function gtag(){dataLayer.push(arguments);}
gtag('consent','default',{
'ad_storage':'denied',
'analytics_storage':'denied',
'ad_user_data':'denied',
'ad_personalization':'denied',
'wait_for_update':500
});
gtag('set','url_passthrough',true);
gtag('set','ads_data_redaction',true);
</script>All four v2 signals — ad_storage, analytics_storage, ad_user_data, ad_personalization — start denied. The banner bundle registers the same defaults, but it loads asynchronously: a Google tag added by another channel (site-builder settings, a plugin) could beat it. The stub executes at HTML parse time, so the defaults are in place before any tag, whoever loads it. That is why the stub must stay before the loader in your snippet.
wait_for_update
wait_for_update: 500 tells Google tags to hold their first hits for up to 500 ms, giving the banner time to push the visitor's stored choice from a previous visit. A returning visitor who already accepted gets full measurement without seeing hits fire as denied first. The delay is configurable in your banner's Consent Mode settings.
url_passthrough and ads_data_redaction
Both are enabled by default and can be turned off in the banner configuration:
url_passthrough— passes ad-click information (gclid,dclid…) through URL parameters while consent is denied, so a later consent does not lose the attribution.ads_data_redaction— whenad_storageis denied, Google further redacts ad-click identifiers from its cookieless pings.
What a refusal looks like: gcs=G100
When the visitor refuses, tags stay in cookieless mode: no cookies are written and Google receives anonymous pings carrying gcs=G100 ("consent denied" signal). These pings are compliant with the refusal — FlowConsent's compliance scan recognizes them, reports them separately, and does not count them as violations. A site using Consent Mode correctly is never penalized for them.
The race FlowConsent cannot win — but detects
Consent Mode defaults only protect tags that enter the dataLayer after them. If a gtag('config', 'G-XXXX') is queued before the consent defaults — typically a site builder's native analytics integration injected above your custom code, as Webflow's settings do — Google processes it unrestricted and sets its cookies no matter what any CMP does afterwards.
The banner checks for exactly this at startup and again after page load: if a config precedes the consent default in the dataLayer, it logs a console error naming the tag IDs and reports a ConsentDefaultRaceLost event to FlowConsent telemetry. The fix is always the same: remove the tag from the channel that injects it early, and declare the service in Builder → Services so the banner manages it.