Skip to content
OpenSmartRoute
Skillv1.0.0

ga4-realtime-api

Pull current-session / active-user data from the GA4 Realtime endpoint — a separate API surface from runReport with different metrics, dimensions, and freshness guarantees (~30 min rolling window inst

by jeremylongshore(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from jeremylongshore/tons-of-skills-marketplace (skills/.curated/ga4-realtime-api/SKILL.md). Install upstream with npx skills add jeremylongshore/tons-of-skills-marketplace --skill ga4-realtime-api. Copyright stays with the author (MIT).

GA4 Realtime API

Overview

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.

Prerequisites

  • A GA4 Data API credential with access to the target property, configured through ga4-auth-setup.
  • Python with google-analytics-data installed.
  • A numeric property ID; realtime data is inherently a rolling, roughly 30-minute view and is not a replacement for historical reporting.

Instructions

Examples

Minimum viable call

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.

Realtime metrics (the full list)

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.

Realtime dimensions (the full list)

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.

Common realtime queries

"How many people are on my site right now?"

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)

"Active users by country, right now"

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}")

"Which events are firing in the last 30 min?"

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.

"Top pages right now"

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.

Filters

Same shape as runReportFilterExpression / 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.

Quotas — different from Data API

Realtime has its own quota bucket. Defaults (2026):

  • 5,000 requests per project per day
  • 250 requests per property per day
  • 60 requests per minute per property

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.

Don't poll faster than 30s

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.

Output

The API returns the current rolling-window aggregate or a bounded set of dimension rows, such as active users by country or event count by name. A valid empty rows list means no currently reportable activity, so callers should render zero rather than treat it as a transport failure.

Error Handling

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.

Resources

  • ga4-auth-setup — prerequisite
  • ga4-data-api-query — for any window longer than 30 min
  • ga4-common-reports — for canonical reports (DAU/MAU/retention) which are NOT realtime-able

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/jeremylongshore-tons-of-skills-marketplace-ga4-realtime-api/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

jeremylongshore-tons-of-skills-marketplace-ga4-realtime-api.ocm.jsonjson
{
  "ocm": "1",
  "id": "jeremylongshore-tons-of-skills-marketplace-ga4-realtime-api",
  "kind": "skill",
  "name": "ga4-realtime-api",
  "description": "Pull current-session / active-user data from the GA4 Realtime endpoint — a separate API surface from runReport with different metrics, dimensions, and freshness guarantees (~30 min rolling window instead of T-48h). Trigger with \"GA4 realtime\", \"active users right now\", \"GA4 current sessions\", \"who's on my site now\".",
  "publisher": "jeremylongshore",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "saas",
      "analytics",
      "google-analytics",
      "ga4",
      "realtime",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Pull current-session / active-user data from the GA4 Realtime endpoint — a separate API surface from runReport with different metrics, dimensions, and freshness guarantees (~30 min rolling window instead of T-48h). Trigger with \"GA4 realtime\", \"active users right now\", \"GA4 current sessions\", \"who's on my site now\"."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/jeremylongshore/tons-of-skills-marketplace",
      "path": "skills/.curated/ga4-realtime-api/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/jeremylongshore/tons-of-skills-marketplace/blob/HEAD/skills/.curated/ga4-realtime-api/SKILL.md",
      "key": "jeremylongshore/tons-of-skills-marketplace/skills/.curated/ga4-realtime-api/SKILL.md"
    },
    "compatibility": "Designed for Claude Code",
    "allowed_tools": [
      "Bash(python3:*),",
      "Bash(curl:*)"
    ],
    "license": "MIT"
  },
  "instructions": "# GA4 Realtime API\n\n## Overview\n\nThe Realtime API is GA4's \"what's happening right now\" endpoint. Different from `runReport`:\n\n| | `runReport` (Data API) | `runRealtimeReport` (Realtime) |\n|---|---|---|\n| Freshness | ~24-48h lag, stable | Last ~30 min, rolling |\n| Window | Any date range | Implicit — last 30 min |\n| Metrics | ~50 supported | ~10 supported (subset) |\n| Dimensions | ~150 supported | ~15 supported (subset) |\n| Quota | Per-property daily | Separate Realtime quota |\n| Use case | Reports, dashboards, trend analysis | Live dashboards, monitoring, \"are we down?\" |\n\nDon't try to use `r",
  "cost": {
    "context_tokens": 1625
  }
}

Fetch it by URL: GET /api/v1/registry/jeremylongshore-tons-of-skills-marketplace-ga4-realtime-api/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.