Install
$ agentstack add skill-usetemi-skills-google-analytics ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Google Analytics
Architecture
ga4 is a standalone Python CLI that wraps three GA4 APIs:
- Data API (v1beta + v1alpha) —
ga4 data …— reporting, realtime, metadata, funnels, audience exports - Admin API (v1beta + v1alpha) —
ga4 admin …— accounts, properties, streams, key events, custom dims/metrics, measurement secrets, links, audiences, access bindings, annotations - Measurement Protocol —
ga4 mp …— event ingestion (send + validate against debug endpoint)
All commands emit JSON to stdout with indent=2. Errors go to stderr as plain text with exit 1. Destructive operations require --yes/-y on the CLI; the skill adds an additional user-confirmation layer (see Destructive operations below).
Auth is OAuth-user-only via ga4 auth login --client-secret . The CLI owns its own state at ~/.config/skills/ga4/ (not under the skill's path — ga4 is usable outside this skill).
Before First Use
- Install —
uv sync --project /abs/path/to/skills/google-analytics - Create an OAuth Desktop client in GCP — https://console.cloud.google.com/apis/credentials → Create Credentials → OAuth client ID → Desktop app → download the JSON. ADC (
gcloud auth application-default login) is deliberately not supported — Google is phasing out analytics scopes on the default gcloud client ID. - Auth —
ga4 auth login --client-secret /path/to/downloaded.json. A browser opens for consent. On a headless machine, open an SSH tunnel first:ssh -L 8086:localhost:8086and open the printed URL on a machine with a browser. Scopes default to readonly + edit + manage-users; override with--scope(repeatable) for provision / user-deletion. - Grant GA access — in GA Admin → Access Management, add the Google account you just authed with as Viewer (reads) or Editor/Administrator (writes, user management). See
references/setup.mdfor click-path. - Default property (optional, recommended) —
ga4 config set-property 123456789. - Verify —
ga4 doctorshould be all-green.
Canonical invocation
uv run --project /path/to/skills/google-analytics ga4 [args]
For brevity, examples below use ga4 directly. When running from outside the skill directory, always use the full uv run --project form.
Destructive operations
Before running any delete or archive subcommand, show the user the exact command (including target resource name) and ask for confirmation in conversation. Only pass --yes/-y after an affirmative answer in the current turn. Never chain multiple destructive ops without re-confirming each one.
The CLI's --yes flag is a non-interactive guardrail. The skill's job is to make sure a human explicitly agrees before a properties delete, key-events delete, custom-dimensions archive, custom-metrics archive, audiences archive, access-bindings delete, access-bindings batch-delete, annotations delete, data-streams delete, measurement-secrets delete, links firebase-delete, links ads-delete, links bigquery-delete, properties submit-user-deletion, or accounts delete is executed. If the user is in a hurry, still ask — a single clear confirmation is cheap compared to clobbering a production property.
Command index
ga4 auth, ga4 config, ga4 doctor
| Command | Purpose | Min scope | |---|---|---| | ga4 auth login --client-secret | OAuth Desktop flow | n/a | | ga4 auth status | Report OAuth credential status | n/a | | ga4 auth whoami | Scopes and expiry on the current token | readonly | | ga4 auth logout | Remove OAuth credentials | n/a | | ga4 config set-property | Persist default property (stored as properties/) | n/a | | ga4 config get default-property | Read default | n/a | | ga4 config show | Dump all config | n/a | | ga4 doctor | Health check (config, OAuth credentials, scopes, Admin API ping) | readonly |
Property ids accept either 123456789 or properties/123456789.
ga4 data — Data API
| Command | Purpose | Min scope | |---|---|---| | ga4 data run-report -p -d -m -s -e | Standard report | readonly | | ga4 data run-pivot-report -p --request-json @body.json | Pivot report | readonly | | ga4 data batch-run-reports -p --requests-json @bodies.json | Up to 5 reports in one call | readonly | | ga4 data batch-run-pivot-reports -p --requests-json @bodies.json | Up to 5 pivot reports | readonly | | ga4 data run-realtime-report -p -d -m | Last 30 (or 60 for GA360) minutes | readonly | | ga4 data run-funnel-report -p --request-json @funnel.json | Funnel analysis. Alpha. | readonly | | ga4 data check-compatibility -p -d -m | Validate dim+metric combo | readonly | | ga4 data get-metadata -p | Dimensions + metrics catalog for the property (pass properties/0 for universal) | readonly | | ga4 data audience-exports create --audience -d | Create audience export | readonly | | ga4 data audience-exports get / list / query | Audience export lifecycle | readonly |
Common run-report flags: --dimension-filter-json, --metric-filter-json, --order-by-json, --metric-aggregation, --cohort-spec-json, --comparisons-json, --limit, --offset, --currency-code, --keep-empty-rows, --return-property-quota, --request-json (full body override).
Filter/order/cohort JSON can be inline (--dimension-filter-json '{"filter":...}') or a file (--dimension-filter-json @/tmp/f.json). See references/data-api.md for the filter grammar.
ga4 admin accounts — Accounts
| Command | Purpose | Min scope | |---|---|---| | accounts list / get / summaries-list | Read accounts | readonly | | accounts update --display-name … | Rename | edit | | accounts delete --yes | Soft-delete | edit | | accounts search-change-history | Audit trail | readonly | | accounts run-access-report -d -m | Who-accessed-what audit | readonly | | accounts get-data-sharing-settings | Read sharing settings | readonly | | accounts provision-ticket --display-name … --redirect-uri … | New-account provisioning ticket | edit |
ga4 admin properties — Properties
| Command | Purpose | Min scope | |---|---|---| | properties list --account / get -p | Read properties | readonly | | properties create --parent --display-name … --time-zone … | Create | edit | | properties update -p --display-name … | Update (or --body-json + --update-mask) | edit | | properties delete -p --yes | Soft-delete | edit | | properties get-data-retention -p / update-data-retention … | Retention settings | edit | | properties get-attribution-settings -p / update… | Attribution model. Alpha. | edit | | properties get-signals-settings -p / update… | Google Signals. Alpha. | edit | | properties run-access-report -p … | Access audit at property scope | readonly | | properties search-change-history -p | Change history | readonly | | properties acknowledge-user-data -p --acknowledgement … | Prereq for Measurement Protocol secrets | edit | | properties submit-user-deletion -p --user-id … | GDPR deletion. Alpha. Irreversible. | user.deletion |
ga4 admin data-streams, measurement-secrets
| Command | Purpose | Min scope | |---|---|---| | data-streams list -p / get -p | Read streams | readonly | | data-streams create -p --type WEB_DATA_STREAM --display-name … --uri … | Create web stream | edit | | data-streams create --type ANDROID_APP_DATA_STREAM --package-name … | Android | edit | | data-streams create --type IOS_APP_DATA_STREAM --bundle-id … | iOS | edit | | data-streams update -p --display-name … | Rename | edit | | data-streams delete -p --yes | Delete | edit | | data-streams get-global-site-tag -p | gtag snippet. Alpha. | readonly | | data-streams get-enhanced-measurement -p / update… | EM settings. Alpha. | edit | | data-streams get-data-redaction -p / update… | PII redaction. Alpha. | edit | | measurement-secrets list -p / get, create --display-name …, update, delete | MP secrets CRUD (requires acknowledge-user-data first) | edit |
ga4 admin key-events, custom-dimensions, custom-metrics
| Command | Purpose | Min scope | |---|---|---| | key-events list -p / get / create --event-name … --counting-method … / update / delete --yes | Conversion events (replaces conversionEvents) | edit | | custom-dimensions list -p / get / create --parameter-name … --display-name … --scope EVENT / update / archive --yes | Custom dims | edit | | custom-metrics list -p / get / create --parameter-name … --measurement-unit … / update / archive --yes | Custom metrics | edit |
ga4 admin links — Third-party links
| Command | Purpose | Min scope | |---|---|---| | links firebase-list -p / firebase-create --firebase-project projects/… / firebase-delete --yes | Firebase links | edit | | links ads-list -p / ads-create --customer-id … / ads-update / ads-delete --yes | Google Ads links | edit | | links bigquery-list -p / bigquery-get / bigquery-create --project projects/… [--daily-export …] / bigquery-update / bigquery-delete --yes | BigQuery links. Alpha. | edit |
ga4 admin audiences, access-bindings, annotations — all alpha
| Command | Purpose | Min scope | |---|---|---| | audiences list -p / get / create --body-json @audience.json / archive --yes | Audiences. Alpha. | edit | | access-bindings list --account (or --property) / get / create --user -r predefinedRoles/admin / update / delete --yes | Per-user roles. Alpha. | manage.users | | access-bindings batch-{create,get,update,delete} --bindings-json @list.json | Batch operations. Alpha. | manage.users | | annotations list -p / get / create --title … --annotation-date YYYY-MM-DD (or --start-date/--end-date) / update / delete --yes | Reporting-data annotations. Alpha. | edit |
Alpha endpoints may change shape without notice; keep an eye on google-analytics-admin release notes if you script against them.
ga4 mp — Measurement Protocol
| Command | Purpose | |---|---| | ga4 mp send --measurement-id G-XXX --api-secret … --events-json @events.json | Fire-and-forget send to /mp/collect | | ga4 mp validate --measurement-id G-XXX --api-secret … --events-json @events.json | Debug endpoint — returns per-event validation findings |
Single-event shortcut: --event-name purchase --event-params '{"value":12.34,"currency":"USD"}'. For Firebase/app streams, replace --measurement-id with --firebase-app-id. --endpoint eu routes through the EU regional endpoint.
MP limits (enforced locally before sending): 25 events/request, 40-char event names, 25 params/event. See references/admin-api.md for full limits including param value length.
Writing reports
# Last 7 days of active users by country
ga4 data run-report -p 123456789 -d country -m activeUsers -s 7daysAgo -e today
# Week-over-week comparison with two date ranges via request JSON
cat /tmp/wow.json
{
"dimensions": [{"name": "deviceCategory"}],
"metrics": [{"name": "engagementRate"}, {"name": "sessions"}],
"date_ranges": [
{"start_date": "7daysAgo", "end_date": "yesterday", "name": "this_week"},
{"start_date": "14daysAgo", "end_date": "8daysAgo", "name": "last_week"}
]
}
EOF
ga4 data run-report -p 123456789 --request-json @/tmp/wow.json
# Filter: only mobile, only pages matching /blog/*
cat /tmp/filter.json
{"andGroup": {"expressions": [
{"filter": {"fieldName": "deviceCategory", "stringFilter": {"value": "mobile"}}},
{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "BEGINS_WITH", "value": "/blog/"}}}
]}}
EOF
ga4 data run-report -p 123456789 -d pagePath -m sessions -s 7daysAgo -e today \
--dimension-filter-json @/tmp/filter.json
For deep filter grammar (AND/OR/NOT, string/numeric/between/in-list filter types), the valid metric-aggregation set, cohort specs, and the "quota token" math, read references/data-api.md.
Admin safety
- Always
list/getfirst beforeupdate/delete/archive. Validate you're targeting the right resource. - Use
search-change-historyto audit recent changes before making new ones, and to find who made the last change to a resource. - Alpha endpoints may change shape. If you get an unexpected schema error, check the
google-analytics-adminpackage version and the alpha changelog. update_mask— most admin updates require a field mask. The CLI auto-computes it from flag-based updates, but for--body-jsonupdates you must pass--update-maskexplicitly.- Scopes — the CLI requests the union of scopes its commands need. If a command 403s with "insufficient permissions", re-auth with a broader scope (see Before First Use).
Funnel / audience / access patterns
- Funnels (
run-funnel-report) are built as an array of steps, each with a filter expression. The response has two sub-reports — funnel table and funnel visualization. Seereferences/data-api.mdfor step-design patterns (sequential vs. any-order steps, breakdown dimensions, continuous vs. direct). - Audiences (
audiences create) have a deeply nested schema (filter clauses, scopes, sequences). Build the JSON separately and pass--body-json @audience.json. Start from an existing audience (audiences get) to see the shape. - Access bindings use
predefinedRoles/*role names. Common:predefinedRoles/no-cost-data,predefinedRoles/read-and-analyze,predefinedRoles/editor,predefinedRoles/admin. Changes at account scope apply to all properties.
Interpreting output
Engagement benchmarks, attribution model differences, funnel drop-off heuristics, audience sequence vs. condition patterns, realtime reporting caveats, and BigQuery long-term-storage tradeoffs are all in references/playbook.md. Read it before drawing conclusions about whether numbers are "good" — GA4's sampling and attribution defaults differ meaningfully from UA and from other analytics tools.
Troubleshooting
- "No credentials. Run: ga4 auth login …" — Exactly what it says. Get a Desktop OAuth client JSON from GCP and log in.
- "Permission denied" — The Google account you auth'd with doesn't have GA access. Grant Viewer/Editor in GA Admin → Access Management. Verify with
ga4 admin accounts summaries-list. - "Quota exhausted" — Pass
--return-property-quotaon a report to see live consumption. Data API tokens reset hourly/daily. GA360 gets 10x limits. - "insufficient_scope" — The stored token was obtained with fewer scopes than this command needs. Re-run
ga4 auth login --client-secret --scope(repeatable) to include them. - "No property id" — Pass
--property/-p, setGA_PROPERTY_ID, orga4 config set-property. - Alpha schema changed — Pin
google-analytics-adminandgoogle-analytics-datainpyproject.toml, thenuv sync. - Realtime report is empty — The realtime window is only the last 30 minutes (60 for GA360). If there's genuinely no active traffic, the report will be empty; this is correct.
- MP send returned 2xx but the event didn't appear —
mp sendalways returns 2xx regardless of validity. Usemp validatefirst to check for rejection reasons.
Configuration files
~/.config/skills/ga4/config.json— default property and other CLI settings~/.config/skills/ga4/credentials.json— OAuth user creds (written byga4 auth login)- Override the config dir with
GA4_CONFIG_DIR=/path/to/dir
Migrating from earlier versions
If upgrading from a build that stored config at ~/.config/ga4/, run ga4 config migrate --apply to move the credentials and config to the new location. ga4 auth status emits a deprecation_warning until the migration runs.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: usetemi
- Source: usetemi/skills
- License: MIT
- Homepage: https://usetemi.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.