---
title: "analytics"
locale: "uk"
---
# analytics

---
title: Analytics API
description: First-party аналітика Ring — інгест і адмін-читання: app-події, device telemetry, Web Vitals, захоплення помилок і platform stats через перевірені маршрути /api/analytics
last_modified: "2026-09-06"
audience: both
---

# Analytics API

> **Info**
> Використовуйте вкладки **Founder** / **Developer** у бічній панелі, щоб відфільтрувати цю сторінку. Поверхні адмін-консолі споживають ці маршрути; сторонні провайдери — опційні env-хуки.

Ring постачає **first-party аналітичний пайплайн**: клієнтська телеметрія інгестується через `/api/analytics/*`, валідується Zod на межі маршруту, зберігається в `analytics_events` / `web_vitals` / `analytics_errors` і читається назад адмін-scoped GET-маршрутами. Зберігання можна повністю вимкнути на середовище — тоді кожен маршрут підтверджує без запису.

| Previous (GA-only setup) | Ring equivalent |
|--------------------------|-----------------|
| Third-party SDK only, data leaves your clone | First-party інгест у вашу власну базу |
| One opaque dashboard | Адмін-scoped читання + platform stats з role gates |
| No device/session context | Батчі `sessionId`, device telemetry з tunnel fan-out |
| Web Vitals left unmeasured | Інгест Core Web Vitals + обчислений `performanceScore` |

## Поверхня маршрутів

| Endpoint | Method | Auth | Purpose |
|----------|--------|------|---------|
| `/api/analytics/app` | POST | optional userId | Батчовані app-події → `analytics_events` |
| `/api/analytics/device` | POST | session required | Device telemetry → `device_telemetry` + fan-out у user tunnel |
| `/api/analytics/navigation` | POST | — | Легкий acknowledgement stub (без зберігання) |
| `/api/analytics/errors` | POST | optional userId | Захоплення клієнтських помилок → `analytics_errors` (відкладений запис) |
| `/api/analytics/errors` | GET | platform admin | Список помилок із фільтрами severity/component |
| `/api/analytics/web-vitals` | POST | optional userId | Core Web Vitals + `performanceScore` → `web_vitals` (відкладений запис) |
| `/api/analytics/web-vitals` | GET | platform admin | Підсумок `scope=platform` або per-user; timeframe `24h` / `7d` / `30d` |
| `/api/analytics/platform-stats` | GET | platform admin | Живі підрахунки для `users`, `entities`, `opportunities` |

### For founders

## Чому це важливо для вашого клону

- **Ваші дані залишаються на вашому Ring.** Інгест пише у вашу базу; нічого не йде до третьої сторони, доки ви самі не увімкнете env-хуки GA/Mixpanel/Amplitude.
- **Статистика адмін-консолі** — platform counts і підсумки Web Vitals закриті role gate на `platform admin`.
- **Kill switch** — `ANALYTICS_DISABLE_STORAGE=true` вимикає persistence без змін коду; endpoints продовжують відповідати.
- **Телеметрія docs і personal-page** — platform summary також агрегує docs 404 і візити personal-page (`getPlatformAnalytics`).

### Опційні сторонні хуки (лише env)

| Variable | Provider |
|----------|----------|
| `GA_TRACKING_ID` / `GA4_MEASUREMENT_PROTOCOL_SECRET` | Google Analytics |
| `MIXPANEL_TOKEN` | Mixpanel |
| `AMPLITUDE_API_KEY` | Amplitude |
| `SENTRY_DSN` | Sentry error tracking |
| `DD_API_KEY` / `DD_APP_KEY` | Datadog |

Жоден не обовʼязковий — власний пайплайн Ring працює без них.

### For developers

## Контракт інгесту

Усі записи **неблокуючі**: валідація синхронна, потім persistence у Next.js `after()`, тож відповідь клієнту ніколи не затримується. Схема батчу (перевірено в `features/analytics/lib/analytics-db.ts`):

{`{
  sessionId: string,        // 1–128 chars: a-zA-Z0-9 _ - : .
  userId: string | null,    // enriched from session when omitted
  events: [                 // 1–50 events per batch
    { type: string, data?: unknown, timestamp?: number }
  ]
}`}

Невалідні payload повертають `400` з першою Zod-проблемою. Батчі понад 50 подій відхиляються, а не тихо обрізаються.

### Куди пише кожен маршрут

| Route | Validation module | Storage |
|-------|-------------------|---------|
| `app` | `appAnalyticsBatchSchema` | `analytics_events` |
| `device` | `deviceTelemetryBodySchema` (`device-telemetry-db.ts`) | device telemetry + `publishToUserTunnel` через `telemetryChannelForDomain` |
| `errors` | `analyticsErrorPayloadSchema` | `analytics_errors` (userId збагачується всередині `after()`) |
| `web-vitals` | `webVitalsInputSchema` + `calculatePerformanceScore` | `web_vitals` із виявленими platform/browser |
| `navigation` | none (stub) | нічого — повертає `{ ok: true }` |

### Адмін-читання

- `GET /api/analytics/platform-stats` — гейт `isPlatformAdmin(session.user.role)`; паралельні `countDocs` над users / entities / opportunities.
- `GET /api/analytics/web-vitals?scope=platform&timeframe=30d` — platform summary через `getPlatformAnalyticsSummary`; без `scope` — per-user метрики.
- Aggregation SSOT: `features/analytics/services/get-platform-analytics.ts` (core summary + docs not-found + personal-page stats).

## Конфігурація

| Variable | Default | Effect |
|----------|---------|--------|
| `ANALYTICS_DISABLE_STORAGE` | unset | `"true"` підтверджує події без запису в базу |

## Повʼязана документація

  
- [api/admin](/docs/api/admin.md) — Next-step: адмін-scoped API-маршрути та RBAC-патерни після інгесту аналітики.

  
- [features/performance](/docs/features/performance.md) — Same-workflow: телеметрія Web Vitals живить сторінки performance.

  
- [architecture/data-validation](/docs/architecture/data-validation.md) — Deep-dive: Zod-охоронці межі маршруту, які використовує кожен інгест-маршрут.
