# Connecting Google sources

One Google sign-in covers GA4 (traffic), GTM (read-only tag audit), and Google Ads
(spend). Funnelkeeper asks for read scopes only and stores the refresh token encrypted.

## From the dashboard

Integrations → Connect with Google → consent → pick your property/container → done.

## From a terminal or agent

The browser step can't be skipped — Google requires a human consent screen. The flow
hands the URL out and polls:

```
POST /connect/google/start {"product_slug":"demo-product","kinds":["ga4","gtm"],"client":"cli"}
  → {"state":"…","auth_url":"https://accounts.google.com/o/oauth2/v2/auth?…","expires_at":"…"}
```

Give `auth_url` to the human. Then poll (bearer required; the state is bound to your
account and expires after 10 minutes):

```
GET /connect/google/status?state=…
  → {"status":"pending"}                          keep polling (2s, then 5s)
  → {"status":"complete","results":[…],"options":{"ga4_properties":[…],"gtm_containers":[…]}}
  → {"status":"error","error":"access_denied"}
```

When `options` holds more than one property or container, ask the human which, then:

```
POST /connect/google/select {"state":"…","ga4_property_id":"4210…","gtm_container_path":"accounts/…/containers/…"}
  → {"ok":true,"activated":["ga4","gtm"]}
```

Exactly one option? Pass it straight through — no need to ask.

## What GTM is for

Nothing is ever written to your container. The Keeper reads the live version weekly and
answers one question: is the GA4 tag this product expects present and unpaused? If spend
is running while the answer is no, you get an alert card — because every funnel number
under-counts until the tag is fixed.

## Google Ads

Spend sync activates automatically once Funnelkeeper's Google Ads developer token is
approved; until then your customer id is stored and the
[CSV bridge](/docs/api/#post-importgoogle-spend) covers spend imports.
