google-analytics
Traps to avoid when querying Google Analytics 4 through treg — cases where the GA4 Data API returns a confident wrong answer instead of an error. Use whenever answering questions about site traffic, visitors, pageviews, channels, conversions, or revenue from GA4.
git clone --depth 1 https://github.com/superdesigndev/treg /tmp/google-analytics && cp -r /tmp/google-analytics/.agents/skills/google-analytics ~/.claude/skills/google-analyticsSKILL.md
# GA4 via treg — what will silently mislead you
You already know the GA4 Data API. This file is **only** the things that return a plausible wrong
answer with no error. Everything here was verified live on 2026-07-22, and each trap was
confirmed by watching three independent agents walk into it.
Property id: `treg connections ls` → the `google-analytics` row's `resource_ref`.
## 1. `endDate:"today"` silently includes a partial day
**3 of 3 agents did this.** It inflates every number and you will not notice.
```
28daysAgo → today /top-page = 45,120 ← includes a partial day
28daysAgo → yesterday /top-page = 44,300
```
Use `yesterday` unless the user explicitly asks about today. If you must use `today`, say the
last day is partial.
## 2. Zero does not mean zero — check whether it's even tracked
**3 of 3 agents reported "$0 revenue and 0 conversions" for a business with real revenue.** Two
rated it high confidence; one argued the zero was trustworthy because `eventCount` was large.
`keyEvents`, `conversions`, and `totalRevenue` all return `0` when **nothing is instrumented**,
which is indistinguishable from genuinely zero. Before reporting any zero:
```bash
# does this property have ANY key events configured?
--data '{"dateRanges":[...],"metrics":[{"name":"keyEvents"}]}'
```
Don't request `keyEvents` and `conversions` in the same call — they're aliases and GA4 rejects
it with `400 Found duplicate metrics: conversions`. Pick one.
If `keyEvents` is 0 across a long window on a site with traffic, the correct answer is
**"conversions are not instrumented in GA4; this question can't be answered from this source"** —
never "revenue is $0". Revenue almost certainly lives in Stripe/PostHog instead.
## 3. A zero-row response has NO `rows` key at all
Not `rows: []` — the key is absent, and so is `rowCount`. The shape varies by query:
| Query | Top-level keys returned |
|---|---|
| grouped by a dimension | `['dimensionHeaders','metricHeaders','metadata','kind']` |
| metrics only (e.g. `keyEvents`) | `['metadata','kind']` — headers gone too |
A naive `d['rows']` raises `KeyError`, which reads as a malformed request. All three unskilled
agents were confused by this. Use `d.get('rows', [])`, treat empty as "no data", then apply
trap #2.
## 3b. Don't list `dateRange` as a dimension
Comparing two periods is a standard ask, and the obvious move errors:
```
400: "Field dateRange is not a dimension. This field can be used in a Pivot or
OrderBy like a dimension, but does not need to be listed in the Dimensions."
```
Pass 2+ entries in `dateRanges` and the API **auto-appends** the range as an extra dimension
value. Give the ranges `name`s to label them in the output.
## 4. Dimension sums do NOT equal totals — they overcount
Measured against a dimensionless true total (illustrative, ratios are the point):
| Grouped by | Sum | vs true total |
|---|---|---|
| `sessionDefaultChannelGroup` | | **~104%** |
| `country` | | **~104%** |
| `pagePath` | | **~189%** |
Sessions span multiple pages, so per-page sums double-count badly. **Never sum a dimension to
report a total** — run a separate dimensionless query.
## 5. `limit` defaults to 10,000 and truncates silently
An unlimited `pagePath` query returned exactly 10,000 rows with `"rowCount": 42613` — 32,613 rows
dropped, no warning. **`rowCount` is the truth; `len(rows)` is not.** Compare them before saying
"all" or "every".
## 6. The Admin API is a different host and is unreachable via `/call/`
The tool is bound to `analyticsdata.googleapis.com`. Anything on
`analyticsadmin.googleapis.com` — `accountSummaries`, property metadata — returns a **Google HTML
404**, not JSON. Two of three agents burned several attempts here, including trying to pass an
absolute URL (which gets concatenated into garbage).
To list properties, use treg, not the proxy:
```bash
treg connections resources <connection-id> # hits the Admin API server-side
```
## Everything else
Standard GA4 Data API. `runReport`, `runRealtimeReport`, `batchRunReports`, `runPivotReport`,
`checkCompatibility`, `/metadata` all verified working through `/call/`. Two minor notes:
metric values are **strings** (cast before arithmetic), and `metadata.timeZone` governs what
"today" means (a property reports in its own timezone, e.g. `Australia/Sydney`).
⚠️ *Reported but not observed here:* high-cardinality dimensions can collapse into an `(other)` row.
- API schema: https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema
- runReport: https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/properties/runReport
- Quotas: https://developers.google.com/analytics/devguides/reporting/data/v1/quotasAdd a provider to treg's OAuth registry (the ones treg holds its own approved app for). Use when asked to "add YouTube/Notion/Meta OAuth", "support connecting X", "add a new OAuth provider", or when a connect flow, capability picker, channel/account picker, or provider health probe needs building. Covers the code changes, the platform-side approval steps, and the pitfalls that don't announce themselves.
Use when setting up, changing or debugging treg's own conversion tracking — the ad-click capture, the AdConversion outbox, or the Data Manager uploader — and whenever asked whether conversions are "working", "live" or "verified". Also use before claiming any part of the pipeline is proven.
One-command local dev stack for tools-registry. Use when asked to "start the dev server", "run treg locally", "test login locally", "bring the stack up", or before any manual/browser test against localhost.
Traps when running Google Ads through treg — the API requirements and cleanup semantics that cost round-trips or money. Use whenever asked to analyse ad performance, audit spend, create or change campaigns, adjust budgets or bids, or do media buying.
Traps to avoid when querying Google Search Console through treg — cases where the API returns a confident wrong answer instead of an error, especially around totals and recent-date trends. Use whenever answering questions about organic search clicks, impressions, rankings, or index status.
tools-registry context + doc upkeep. Use to warm up a fresh session (orient on the architecture + recent commits) or when working on tools-registry — changing code, rules, content, data, or process (proxy · auth/secrets · API · CLI · the registry skill) — loads the relevant fragment(s) from docs/context so you act with accurate, cited context. Accepts an optional focus query (e.g. `/tools-registry-context <area>`). Also runs `/tools-registry-context sync` to update the doc fragments after changes (show → approve → apply). Mention it whenever a push to the main branch is near.
Write a treg.to agent page (/agents/<client>) or use-case page (/use-cases/<category>/<job>). Researches the real problem on Reddit and X with agent-reach BEFORE writing, so the page targets the words buyers actually use and quotes their own questions. Use when adding a page from marketing/pseo-ship-plan.md, or when asked to "write the <job> page" / "add the <agent> page".
Build a treg provider skill — the endpoint map + mistake map that lets an agent do real work on a platform API through treg's proxy. Use when adding a skill for a connected provider (Google Ads, LinkedIn, Meta Ads, TikTok, X, Instagram, Search Console), or when an existing provider skill needs verifying or extending.