Observe
Analytics & usage
Read Frontpage site analytics, plan meters, and the built page list from the CLI — with real response shapes.
What this covers
Three read-only observe commands share the RL-READ rate-limit class (see
Rate limits):
frontpage analytics— traffic dashboard JSON (pageviews, visitors, top pages/sources)frontpage usage— plan entitlements and AI / bandwidth / storage metersfrontpage pages— routes the site currently exposes (path + title)
Viewer role is enough. None of these publish or mutate the site branch.
Analytics
frontpage analytics
frontpage analytics --days 7
frontpage analytics --days 30 --site acme
# Structured ops (same cores as the editor agent tools)
frontpage analytics summary --days 30
frontpage analytics query --dimension path --measure count --limit 10
frontpage analytics funnel --steps '[{"path":"/"},{"path":"/pricing"}]' --days 14
frontpage analytics timeseries --metric pageviews --interval day --days 14
frontpage analytics compare --a '{"device":"mobile"}' --b '{"device":"desktop"}'
frontpage analytics sql --sql "SELECT path, count(*)::int AS n FROM analytics_events GROUP BY 1 ORDER BY n DESC LIMIT 10"
Bare analytics / analytics dashboard returns the legacy dashboard JSON (GET).
Subcommands use POST with allowlisted dimensions/measures; SQL is guard-validated and RLS site-scoped.
Without --json, the CLI prints the result object directly (pretty-printed JSON).
Typical dashboard shape (fields may grow; treat unknown keys as forward-compatible):
{
"days": 7,
"range": {
"from": "2026-07-26T06:54:57.611Z",
"to": "2026-08-02T06:54:57.611Z"
},
"totals": {
"events": 3389,
"pageviews": 526,
"visitors": 313,
"sessions": 396,
"conversions": 0,
"revenue": 0,
"totalSeconds": 1694871,
"avgScroll": 48
},
"deltas": {
"visitors": -70.2,
"sessions": -67.5,
"pageviews": -70.1,
"conversions": null,
"revenue": null
},
"topPages": [
{ "path": "/", "views": 315 },
{ "path": "/pricing", "views": 67 }
],
"topSources": [
{ "source": "direct", "sessions": 348 },
{ "source": "search", "sessions": 23 },
{ "source": "social", "sessions": 22 },
{ "source": "referral", "sessions": 19 },
{ "source": "paid", "sessions": 1 }
],
"pages": [
{
"path": "/",
"pageviews": 315,
"visitors": 220,
"sessions": 285,
"avgSeconds": 3301,
"avgScroll": 50
}
]
} --days
- Default is 7 when omitted.
- Pass an integer day window:
--days 1,--days 30, etc. range.from/range.toare ISO timestamps for the window that was queried.deltascompare against the previous equal-length window (null when not applicable).
Analytics reflect Frontpage first-party tracking on the live/staging site surfaces. Empty or sparse sites return zeros — that is success, not an auth failure.
Usage (plan meters)
frontpage usage
frontpage usage --site acme Prints plan entitlements and current-cycle meters. Useful when exit code 2 might mean AI budget rather than HTTP rate limiting.
{
"plan": {
"id": "pro",
"label": "Pro",
"customDomain": true,
"extensions": true,
"aiBudgetUsd": 50,
"bandwidthGb": 100,
"storageGb": 10,
"timeMachineDays": 30
},
"ai": {
"used": 12.4,
"limit": 50,
"pct": 0.248,
"warn": false,
"atLimit": false,
"over": false
},
"bandwidth": {
"used": 3.2,
"limit": 100,
"pct": 0.032,
"warn": false,
"atLimit": false,
"over": false
},
"storage": {
"used": 1.1,
"limit": 10,
"pct": 0.11,
"warn": false,
"atLimit": false,
"over": false
},
"members": {
"used": 2,
"limit": 5,
"pct": 0.4,
"warn": false,
"atLimit": false,
"over": false
},
"cycleResetsAt": "2026-09-01T00:00:00.000Z"
}
Exact plan ids and limits depend on the site’s subscription. Internal/demo plans may show very large limits.
Branch on ai.over / ai.atLimit (and the same flags on other meters) rather than hardcoding
plan names.
Pages list
frontpage pages
frontpage pages --json
frontpage pages --site acme --json Human mode prints path and title columns. JSON envelope:
{
"ok": true,
"command": "pages",
"data": {
"slug": "acme",
"pages": [
{ "path": "/", "title": "Acme — Home" },
{ "path": "/pricing", "title": "Pricing" },
{ "path": "/about", "title": "About" }
]
}
} Use this before SEO edits or agent prompts so you target paths that actually exist. Titles come from the site’s page metadata / build, not from analytics.
Agent recipes
# Weekly traffic snapshot
frontpage analytics --days 7 > /tmp/fp-analytics.json
# Before prompting: confirm routes
frontpage pages --json
# Diagnose exit 2 after a failed prompt
frontpage usage
# if ai.atLimit / ai.over → budget; else see /developers/rate-limits Related
- Rate limits — HTTP throttles vs plan meters
- Content & settings — SEO and page metadata writes
- Errors & exit codes — exit 2 recovery