Files
analytics/README.md
T
2026-07-20 08:29:23 +02:00

4.9 KiB

analytics

Stateless API proxy for Google Analytics 4, Google Search Console, Google Ads and Sklik (Seznam), running in AppFactory behind the Caddy reverse proxy at /apps/analytics.

The service stores no secrets. Every credential is supplied per request as an X- header and used only to call the upstream API.

Endpoints

Interactive docs (Swagger UI): /docs — publicly https://services.csbot.cz/apps/analytics/docs.

Area Method Path
Meta GET /health, /version
GA4 Data POST /ga/data/properties/{id}/runReport
GA4 Data POST /ga/data/properties/{id}/runPivotReport
GA4 Data POST /ga/data/properties/{id}/batchRunReports
GA4 Data POST /ga/data/properties/{id}/batchRunPivotReports
GA4 Data POST /ga/data/properties/{id}/runRealtimeReport
GA4 Data POST /ga/data/properties/{id}/checkCompatibility
GA4 Data GET /ga/data/properties/{id}/metadata
GA4 Admin GET /ga/admin/accounts, /ga/admin/accountSummaries
GA4 Admin GET /ga/admin/properties (?accountId=), /ga/admin/properties/{id}
GA4 Admin GET /ga/admin/properties/{id}/dataStreams
Search Console POST /gsc/searchAnalytics/query (?siteUrl=), /gsc/urlInspection
Search Console GET /gsc/sites, /gsc/site, /gsc/sitemaps, /gsc/sitemap (?siteUrl=)
Google Ads POST /googleads/customers/{id}/search, /googleads/customers/{id}/searchStream
Google Ads GET /googleads/customers:listAccessibleCustomers
Sklik POST /sklik/login, /sklik/report/{entity}, /sklik/rpc/{method}
Sklik GET /sklik/limits, /sklik/write-limits
Sklik read GET /sklik/campaigns, /sklik/groups, /sklik/ads
Sklik write POST /sklik/{campaigns|groups|ads} — create, always paused
Sklik write PUT /sklik/{campaigns|groups|ads} — update by id (partial)
Sklik write DELETE /sklik/{campaigns|groups|ads}?ids= — remove (reversible)
Sklik write POST /sklik/{campaigns|groups|ads}/restore?ids=

Credentials (headers)

Google Analytics — token wins over service account:

Header Required Meaning
X-GA-Access-Token one of these Ready OAuth2 access token (used as Bearer).
X-GA-Credentials one of these Base64-encoded service-account JSON key; the proxy mints a token.
X-GA-Quota-Project no Google Cloud project id for quota/billing.

Google Search Console — same model, prefix X-GSC- (scope webmasters.readonly): X-GSC-Access-Token / X-GSC-Credentials (+ X-GSC-Quota-Project).

Google Ads — same OAuth (scope adwords) plus a developer token:

Header Required Meaning
X-GAds-Developer-Token yes Google Ads developer token.
X-GAds-Access-Token one of these Ready OAuth2 access token.
X-GAds-Credentials one of these Base64 service-account JSON (needs domain-wide delegation).
X-GAds-Login-Customer-Id no Manager (MCC) id → login-customer-id.
X-GAds-Quota-Project no Google Cloud project id.

Sklik:

Header Required Meaning
X-Sklik-Token yes Sklik API token from account settings.
X-Sklik-User-Id no Managed account id for agency/MCC access.
X-Idempotency-Key no Writes only. A retry with the same key replays the original result instead of creating a duplicate.

Sklik writes create everything paused (status: suspend) — Sklik's own default is active, so this is forced server-side. PUT is ordinary CRUD and can resume a campaign; set SKLIK_BLOCK_ACTIVATION=true to forbid that. Budget ceilings are off by default; enable them with SKLIK_MAX_*. DELETE is Sklik's soft delete and is reversible via /restore. See documentation/sklik.md.

Where to obtain each credential is described at the top of /docs (Swagger) and in documentation/.

Run locally

pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
# open http://localhost:8000/docs

Configuration (env)

Non-secret only — see app/config.py: ROOT_PATH, GA_DATA_BASE_URL, GA_ADMIN_BASE_URL, GA_SCOPE, GSC_DATA_BASE_URL, GSC_INSPECT_BASE_URL, GSC_SCOPE, GOOGLE_ADS_BASE_URL, GOOGLE_ADS_API_VERSION, GOOGLE_ADS_SCOPE, SKLIK_BASE_URL, SKLIK_LIST_PAGE_LIMIT, SKLIK_LIST_MAX_PAGES, HTTP_TIMEOUT_SECONDS, LOG_LEVEL.

Sklik write guard rails (all optional, all off by default): SKLIK_MAX_DAY_BUDGET_HALERS, SKLIK_MAX_TOTAL_BUDGET_HALERS, SKLIK_MAX_CPC_HALERS (0 = no ceiling), SKLIK_IDEMPOTENCY_TTL_SECONDS, SKLIK_BLOCK_ACTIVATION (default false), SKLIK_RPC_ALLOW_MUTATIONS (default true).

See documentation/ for per-integration detail.