# 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.

> Canonical: https://www.flowconsent.com/en/doc/google-consent-mode
> Last updated: 2026-07-30
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**:

```html title="Consent Mode stub (first script in the <head>)"
<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`**: when `ad_storage` is 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.

> [!IMPORTANT]
> The opposite case is the one to fear: a hit telling Google consent was **granted** despite an actual refusal. The scan flags those as aggravated violations: they usually mean a tag escaped the banner entirely.

## 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.

> [!TIP]
> The installation assistant (Builder → Integration) verifies the whole chain on your live page: stub present, stub before every Google tag, loader with the right license.
