Files
analytics/documentation/google-analytics.md
T
JiriUhlir 6934f22253 first
2026-06-18 11:58:23 +02:00

85 lines
3.1 KiB
Markdown

# Google Analytics (GA4)
Proxy over the GA4 **Data API** (`analyticsdata.googleapis.com/v1beta`) and
**Admin API** (`analyticsadmin.googleapis.com/v1beta`).
## Credentials
Token has precedence over the service account:
| Header | Meaning |
| --- | --- |
| `X-GA-Access-Token` | Ready OAuth2 access token, used directly as `Authorization: Bearer`. |
| `X-GA-Credentials` | **Base64** of a Google service-account JSON key. The proxy mints a short-lived token (scope `https://www.googleapis.com/auth/analytics.readonly`) via `google-auth` and caches it in memory until ~60 s before expiry. |
| `X-GA-Quota-Project` | Optional GCP project id → upstream `x-goog-user-project`. |
At least one of `X-GA-Access-Token` / `X-GA-Credentials` is required (otherwise
`401 missing_credentials`).
The service account (or token) must have access to the GA4 property — add its
`client_email` as a viewer in GA Admin → Property Access Management.
> Encoding the key: `base64 -w0 service-account.json` (Linux) or
> `[Convert]::ToBase64String([IO.File]::ReadAllBytes("service-account.json"))`
> (PowerShell).
## Data API endpoints
`property_id` may be the bare number (`123456789`) or `properties/123456789`.
| Method | Path | Upstream |
| --- | --- | --- |
| POST | `/ga/data/properties/{id}/runReport` | `:runReport` |
| POST | `/ga/data/properties/{id}/runPivotReport` | `:runPivotReport` |
| POST | `/ga/data/properties/{id}/batchRunReports` | `:batchRunReports` |
| POST | `/ga/data/properties/{id}/batchRunPivotReports` | `:batchRunPivotReports` |
| POST | `/ga/data/properties/{id}/runRealtimeReport` | `:runRealtimeReport` |
| POST | `/ga/data/properties/{id}/checkCompatibility` | `:checkCompatibility` |
| GET | `/ga/data/properties/{id}/metadata` | `/metadata` |
The POST body is the GA4 request object, forwarded unchanged. Example
`runReport` body:
```json
{
"dateRanges": [{ "startDate": "7daysAgo", "endDate": "today" }],
"dimensions": [{ "name": "country" }],
"metrics": [{ "name": "activeUsers" }]
}
```
## Admin API endpoints (read)
| Method | Path | Notes |
| --- | --- | --- |
| GET | `/ga/admin/accounts` | `pageSize`, `pageToken` |
| GET | `/ga/admin/accountSummaries` | accounts + their properties |
| GET | `/ga/admin/properties?accountId=123` | builds `filter=parent:accounts/123` |
| GET | `/ga/admin/properties/{id}` | single property |
| GET | `/ga/admin/properties/{id}/dataStreams` | data streams |
## Errors
`UpstreamError` is returned as JSON with the upstream status and body:
```json
{
"error": "upstream_error",
"status": 403,
"detail": "User does not have sufficient permissions for this property.",
"upstream_status": 403,
"upstream_body": { "error": { "code": 403, "status": "PERMISSION_DENIED" } }
}
```
Timeouts → `504`, unreachable/transport → `502`, token minting failure → `401`.
## curl example
```bash
curl -X POST "https://services.csbot.cz/apps/analytics/ga/data/properties/123456789/runReport" \
-H "X-GA-Access-Token: ya29...." \
-H "Content-Type: application/json" \
-d '{"dateRanges":[{"startDate":"7daysAgo","endDate":"today"}],"metrics":[{"name":"activeUsers"}]}'
```