Skip to content

Analytics + Beacon

Lightweight, privacy-respecting metrics: which Stories get how many mounts, segmented by language and audience.

Beacon (anonymous mount tracking)

http
POST /v1/cdn/{space}/_beacon
Content-Type: application/json

Body (all fields optional):

json
{
  "story_uuid": "abc-...",
  "segment_key": "eu-visitors",
  "lang": "de-AT",
  "referrer": "https://blog.acme.com/post-1",
  "device": "desktop"
}

Response: 204 No Content always. Beacon failures NEVER block the page — fire-and-forget.

How the SDK uses this

meta.beacon_url on every CDN-story response carries the absolute URL of this endpoint. The SDK auto-pings it after mount with the resolved story UUID, segment, and locale. The Astro/Next/Nuxt SDKs are opt-in — set beacon: true in createClient().

Rate-limited at 600/min/IP. No auth. Data retained 90 days then aggregated into rollups.

Reading aggregated data

http
GET /v1/spaces/{slug}/analytics/stories?from=2026-05-01&to=2026-05-27&granularity=day

Auth: auth:sanctum + space.scope middleware (role: viewer or higher).

Response:

json
{
  "data": [
    {
      "story_uuid": "abc-...",
      "slug": "welcome",
      "mounts": 4291,
      "by_lang": { "en": 3120, "de-AT": 980, "es-ES": 191 },
      "by_segment": { "default": 3812, "eu-visitors": 479 },
      "by_day": [
        { "date": "2026-05-26", "mounts": 174 },
        { "date": "2026-05-27", "mounts": 203 }
      ]
    }
  ],
  "meta": { "from": "2026-05-01", "to": "2026-05-27", "total_stories": 12 }
}

Per-story timeline

http
GET /v1/spaces/{slug}/stories/{uuid}/analytics?days=30

Returns daily mounts + by_lang + by_segment + by_device + a sparkline prepared for the admin UI.

AI insights (optional)

http
POST /v1/spaces/{slug}/analytics/ai-insights

Runs a one-shot LLM analysis over the last 30 days of mount data and returns plain-text observations:

  • Stories trending up/down vs prior period
  • Locales over-/under-served
  • Segments not seeing variants (opportunity)
  • Outliers (sudden traffic spikes)

Rate-limited: 10/hour per Space. Costs apply (LLM token cost passed through).

Privacy + GDPR

  • Beacon stores no PII. No cookies set. No fingerprinting. No IP retained past the rate-limit window (10 min).
  • referrer is truncated to scheme + host (no path, no query) before storage.
  • device is the literal string desktop / mobile / tablet — no UA strings, no model numbers.
  • Operators can disable the beacon entirely by setting PEACOCK_BEACON_ENABLED=false in the API env. CDN responses then omit meta.beacon_url.

See also