# Google Analytics 4

> Link GA4 to BigQuery, give Patterna read access, and the reader maps the daily export.

Source: https://staging.patterna.nl/docs/connector-ga4

Patterna reads GA4 data from the BigQuery export, never from the GA4 API. You link GA4 to BigQuery, give a service account read access to the export dataset, and the jobs read new days on a schedule.

## 1. Link GA4 to BigQuery

1. In GA4, open **Admin → Product links → BigQuery links** and choose **Link**.
2. Pick the Google Cloud project that will hold the export.
3. Choose a data location in the EU.
4. Turn on the **Daily** export. Patterna does not read the intraday (streaming) table yet.
5. Submit. The first daily table, `events_YYYYMMDD`, appears in a dataset named `analytics_<property id>` within about a day.

## 2. Give the reader access

Grant Patterna's reader service account read access. Its address is shown on **Connectors → Google Analytics 4**.

1. In Google Cloud, open **BigQuery**, select the `analytics_<property id>` dataset and choose **Sharing → Permissions**.
2. Add the service account with the role **BigQuery Data Viewer**. This lets it read the tables and nothing else.
3. To run queries, the service account also needs **BigQuery Job User** on the project you name in the connector. The query jobs run in that project, so it carries the (small) query cost.

Patterna supplies the service account; the jobs run with its credentials. You never upload a key.

## 3. Turn on the connector

In **Connectors → Google Analytics 4**, fill in the project and dataset the card asks for and press **Test connection**. The connector runs on the connectors schedule: the scheduler checks every 15 minutes and runs it when your tenant's interval has passed.

## What the reader does

- Reads new daily tables with a query, row by row through the same mapping rules as [PostHog](https://staging.patterna.nl/docs/connector-posthog).
- `user_pseudo_id` is a device id. It is used only as an HMAC input to derive session and event ids. It is never stored.
- GA4's `user_id`, when you set one, becomes the Patterna user id. Set it to your random Patterna id, never your account id; or turn on `id_mapping: "hmac"` on the connector so it is replaced by a Patterna-minted keyed hash (under `PATTERNA_ID_SECRET`, which Patterna holds) before it is written. See [Identity across connectors](https://staging.patterna.nl/docs/identity-across-connectors).
- Event ids are derived from the source, so re-reading a day does not double count. Ingest is idempotent on `event_id`.
- Users who are `non_profiled` get a per-day rotating `session_id` instead of a user id.
- Each run writes a row with rows in, rows mapped and per-field drop counts.

## What is dropped

- Every user property and device field except OS, app version and locale.
- IP-derived geography and any coordinates.
- Free text such as page titles and search terms.
- Event types without a mapping.

The rules are the same as for PostHog: see [Data we never store](https://staging.patterna.nl/docs/data-we-never-store).

## Check it works

**Connectors → Google Analytics 4** shows the last run, rows in, rows mapped, fields dropped and errors. A failing run shows its error and the request id.
