From ga4-pack
Pull current-session and active-user data from the GA4 Realtime API, distinct from runReport with ~30-min freshness. Use for live dashboards and monitoring.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ga4-pack:ga4-realtime-apiThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
The Realtime API is GA4's "what's happening right now" endpoint. Different from `runReport`:
The Realtime API is GA4's "what's happening right now" endpoint. Different from runReport:
runReport (Data API) | runRealtimeReport (Realtime) | |
|---|---|---|
| Freshness | ~24-48h lag, stable | Last ~30 min, rolling |
| Window | Any date range | Implicit — last 30 min |
| Metrics | ~50 supported | ~10 supported (subset) |
| Dimensions | ~150 supported | ~15 supported (subset) |
| Quota | Per-property daily | Separate Realtime quota |
| Use case | Reports, dashboards, trend analysis | Live dashboards, monitoring, "are we down?" |
Don't try to use runReport for now-data — its freshest data point is yesterday. Use runRealtimeReport.
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
RunRealtimeReportRequest, Metric, Dimension,
)
client = BetaAnalyticsDataClient()
resp = client.run_realtime_report(RunRealtimeReportRequest(
property="properties/123456789",
metrics=[Metric(name="activeUsers")],
))
# Single-row response when there are no dimensions
total = int(resp.rows[0].metric_values[0].value) if resp.rows else 0
print(f"Active users right now: {total}")
No date_ranges block — the implicit window is the last 30 min. Adding one will error.
| Metric | What it counts |
|---|---|
activeUsers | Unique users in the last 30 min |
screenPageViews | Pageviews + screenviews in the last 30 min |
eventCount | Total events in the last 30 min |
conversions | Conversion events in the last 30 min |
keyEvents | Key events (post-2024 rename of conversions) |
Custom-event aggregates (e.g. purchase_revenue) are NOT in the Realtime API. If you need realtime revenue, derive it from eventCount filtered to eventName=="purchase" plus your average AOV.
| Dimension | Use |
|---|---|
country, city | Geo of currently-active users |
deviceCategory | desktop / mobile / tablet split |
unifiedScreenName / unifiedScreenClass | App screen / web title |
eventName | Event-type breakdown |
streamId, streamName | When property has multiple data streams (web + iOS + Android) |
platform | web / ios / android |
appVersion, audienceName, audienceId | When defined in the property |
That's the full list. ~15 dims total. Compare to runReport's ~150.
resp = client.run_realtime_report(RunRealtimeReportRequest(
property="properties/123456789",
metrics=[Metric(name="activeUsers")],
))
print(int(resp.rows[0].metric_values[0].value) if resp.rows else 0)
resp = client.run_realtime_report(RunRealtimeReportRequest(
property="properties/123456789",
metrics=[Metric(name="activeUsers")],
dimensions=[Dimension(name="country")],
limit=20,
))
for r in resp.rows:
print(f"{r.dimension_values[0].value:25s} {r.metric_values[0].value}")
resp = client.run_realtime_report(RunRealtimeReportRequest(
property="properties/123456789",
metrics=[Metric(name="eventCount")],
dimensions=[Dimension(name="eventName")],
limit=30,
))
This is the live event firehose — useful to verify a new tracking deployment is actually firing.
resp = client.run_realtime_report(RunRealtimeReportRequest(
property="properties/123456789",
metrics=[Metric(name="screenPageViews")],
dimensions=[Dimension(name="unifiedScreenName")], # NOT pagePath — that's Data-API-only
limit=20,
))
Realtime doesn't expose pagePath directly. Use unifiedScreenName (the page title) or unifiedScreenClass. To get path-level granularity in realtime, push a custom event with the path as a parameter, then query by eventName + that custom dimension.
Same shape as runReport — FilterExpression / Filter blocks. Realtime supports dimension_filter and metric_filter but not the full set of dimensions / metrics; check the Realtime API schema before writing complex filters.
Realtime has its own quota bucket. Defaults (2026):
For a live dashboard polling every 10s: that's 6 RPM, well within limits. For a hot incident where you want minute-by-minute data, you can poll up to 60x/min per property.
The data window is the last 30 min. Polling faster than ~30s wastes quota without meaningful resolution change. For most "live" use cases, 60s polling is plenty.
| Issue | Why |
|---|---|
activeUsers doesn't match the GA4 web UI's "Realtime" overview | The UI uses a slightly different window (~5 min default) and may include in-flight events not yet reportable via API. Web UI > API for instant-incidents. |
| Empty rows on a busy site | Property may be using a different stream you didn't filter for. Add Dimension(name="streamId") to see splits. |
400 INVALID_ARGUMENT: Realtime reports do not support dimension X | Using a Data-API-only dimension (e.g. pagePath, sessionSource). Use a Realtime dimension. |
| Latency between front-end event and Realtime visibility | ~10-30 seconds is normal. If >2 minutes, check the GA4 DebugView for event delivery issues. |
ga4-auth-setup — prerequisitega4-data-api-query — for any window longer than 30 minga4-common-reports — for canonical reports (DAU/MAU/retention) which are NOT realtime-ablenpx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin ga4-packQueries Google Analytics 4 reports and properties using the Data and Admin APIs. Useful for traffic, sessions, users, conversions, and realtime data.
Inspects PostHog Live tab for real-time web analytics: users online, pageviews, top pages, referrers, devices, browsers, countries, and bot traffic. Answers 'who is on my site right now?' and identifies bots.
Generates copy-paste GA4 Data API Python recipes for DAU/MAU/WAU, retention, top pages, channel attribution, funnel, geo, and device reports. Trigger with 'GA4 DAU' etc.