> ## Documentation Index
> Fetch the complete documentation index at: https://constanza101-borrissol-28.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Analytics 4 with Consent Mode v2 in Borrissol

> How Borrissol implements GA4 with Consent Mode v2 Advanced: cookieless default, cookie banner, localStorage persistence, and denied-state modeling.

Google Analytics 4 loads on every visit to borrissol.com via `gtag.js`, but it operates in a cookieless mode by default. Cookies are only set after the visitor explicitly clicks **Accept** on the cookie banner. This is achieved through Google Consent Mode v2 Advanced — the most privacy-preserving GA4 integration pattern available, and the one required for full GDPR compliance in EU markets like Spain and France.

## How Consent Mode v2 works in this project

Consent Mode v2 separates the GA4 **loading** decision (always load) from the **cookie** decision (only set after consent). The flow on every page visit is:

<Steps>
  <Step title="Consent Mode initialized — denied by default">
    Before the GA4 snippet loads, `Layout.astro` initializes Consent Mode with all storage types set to `denied`. This is the "Advanced" pattern: the script loads, but Google is explicitly told it may not write cookies or read device storage.

    ```js theme={null}
    window.dataLayer = window.dataLayer || [];
    function gtag() { dataLayer.push(arguments); }

    // Must run BEFORE the GA4 snippet
    gtag('consent', 'default', {
      analytics_storage:  'denied',
      ad_storage:         'denied',
      ad_user_data:       'denied',
      ad_personalization: 'denied',
      wait_for_update:    500,
    });
    ```
  </Step>

  <Step title="GA4 loads via gtag.js">
    The GA4 measurement script loads in the `<head>` of every page via `Layout.astro`. In denied state it fires a cookieless ping — Google uses this to model anonymous, aggregate traffic data without storing any PII.
  </Step>

  <Step title="Cookie banner is shown to new visitors">
    `CookieBanner.astro` checks `localStorage` for a previously saved consent decision. If no value is found, the banner is displayed with two actions: **Accept** and **Decline**.
  </Step>

  <Step title="Consent state updated on user action">
    When the visitor clicks **Accept**, the banner calls `gtag('consent', 'update', { analytics_storage: 'granted' })` and saves `'accepted'` to `localStorage`. GA4 then sets its measurement cookies and begins full tracking for that session and all future sessions.

    When the visitor clicks **Decline**, `'rejected'` is saved to `localStorage`. The banner is dismissed and GA4 continues in cookieless mode for all future visits.
  </Step>

  <Step title="Consent restored on return visits">
    On every page load, `Layout.astro` reads `localStorage` inside the same inline script that sets the consent default. If the saved value is `'accepted'`, it calls `gtag('consent', 'update', { analytics_storage: 'granted' })` immediately — before the GA4 snippet fires — so returning visitors never see the banner again and GA4 operates in full mode from the first pageview. `CookieBanner.astro` also reads `localStorage` independently to decide whether to show the banner at all.
  </Step>
</Steps>

## The cookie banner (`CookieBanner.astro`)

The banner is a minimal two-button component rendered server-side by Astro and activated client-side:

* **Accept** — updates consent to `granted`, saves `'accepted'` to `localStorage`, hides the banner
* **Decline** — saves `'rejected'` to `localStorage`, keeps GA4 in cookieless mode, hides the banner

No cookies are read or written before the user makes a choice. The banner's state is persisted entirely in `localStorage`, not in a cookie itself — keeping the pre-consent state clean.

<Note>
  The privacy policy text visible in `PrivacySection.astro` is translated for all four languages via `ui.ts`. The keys `cookie.accept`, `cookie.decline`, `cookie.text`, and `privacy.*` cover all banner and policy copy.
</Note>

## Layout.astro integration

`Layout.astro` is responsible for the correct script ordering in `<head>`:

1. Consent Mode default initialization (inline `<script>` — must run synchronously)
2. `gtag.js` loader (`<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX">`)
3. GA4 configuration call (`gtag('config', 'G-XXXXXXXX')`)

This order is critical. If the GA4 loader runs before the consent default is set, GA4 may attempt to write cookies before the denied state is registered.

## What happens in denied state

In denied state (the default for new visitors and visitors who clicked Decline):

* GA4 fires a cookieless ping on each pageview
* Google applies **modeled data** — statistical inference that estimates traffic patterns from consented users and applies them to cookieless sessions
* **No PII is stored.** No `_ga` or `_gid` cookies are written. No device fingerprinting occurs.
* The site remains fully functional; the only difference is that individual sessions are not tracked

<Tip>
  Google's modeled data in Consent Mode v2 Advanced means aggregate traffic metrics (pageviews, sessions, bounce rate) remain useful in GA4 even when most visitors decline. The modeling accuracy improves over time as the proportion of consenting users provides a reference baseline.
</Tip>

## GDPR compliance summary

| Requirement               | Implementation                                                                    |
| ------------------------- | --------------------------------------------------------------------------------- |
| No cookies before consent | ✅ Consent Mode `denied` default blocks all GA4 cookies                            |
| Explicit consent required | ✅ Two-action banner (Accept / Decline), no pre-ticked boxes                       |
| Consent persisted         | ✅ `localStorage` — restored on return visits without re-asking                    |
| Right to withdraw         | ✅ Visitor can clear browser localStorage/cookies at any time                      |
| Privacy policy            | ✅ Inline `PrivacySection.astro` on every home page, translated in all 4 languages |
| Third-party analytics     | ✅ GA4 only — no other tracking scripts                                            |

## Adding tracking beyond GA4

<Warning>
  Do not add cookies, pixel trackers, or third-party analytics scripts without updating `CookieBanner.astro` to include the new consent type. Every storage or tracking mechanism that requires GDPR consent must be gated behind the same `gtag('consent', 'update', …)` call that currently governs GA4. Adding a tracker outside this flow would break the site's GDPR compliance.
</Warning>

If a second analytics service (e.g. a heatmap tool) is added in the future:

1. Add the new consent category to the `gtag('consent', 'default', …)` defaults in `Layout.astro`
2. Gate the tool's initialization behind a `gtag('consent', 'update', …)` grant
3. Update the privacy policy copy in `ui.ts` for all four languages to disclose the new tool
