---
title: "Visitor analytics for any site (admin drill-down)"
method: GET
path: "/stats/sites/{id}/analytics"
tags: ["Stats"]
---

# Visitor analytics for any site (admin drill-down)

`GET /stats/sites/{id}/analytics`

## Request

- Base URL: `https://api.nippy.host`
- URL: `https://api.nippy.host/stats/sites/{id}/analytics`
- Auth: `bearer` (a scheme the document does not define)

Admin-only per-site visitor analytics over a lookback window. Unlike the owner-facing `GET /sites/:id/analytics`, this works for any site regardless of ownership or the account’s plan — it powers the directory drill-down. Reads live from the analytics warehouse; counts are sampling estimates.

## Path parameters

- `id` string, required

## Query parameters

- `from` string
- `to` string
- `interval` '1m' | '5m' | '15m' | '1h' | '3h' | '6h' | '1d' | '1w'
- `tzOffset` number

## Response `200`

- APISiteAnalytics
  - `interval` '1m' | '5m' | '15m' | '1h' | '3h' | '6h' | '1d' | '1w', required: Series bucket width actually used (echoes the request, clamped to a width allowed for the window duration; falls back to that duration's default).
  - `granularity` 'minute' | 'hour' | 'day' | 'week', required: Class of the bucket interval (minute | hour | day) — drives axis-label formatting on the dashboard.
  - `from` string, required: Window start, ISO timestamp (UTC).
  - `to` string, required: Window end, ISO timestamp (UTC).
  - `totals` APIAnalyticsTotals, required
    - `views` number, required: Pageviews in the window.
    - `uniqueVisitors` number, required: Unique visitors (cookieless daily-hash distinct).
    - `visits` number, required: Visits (30-min idle gap defines a new visit).
    - `viewsPerVisit` number, required: Average pageviews per visit.
    - `bounceRate` number, required: Fraction of visits with exactly one pageview, between 0 and 1.
    - `avgVisitDurationSeconds` number, required: Average visit duration (visit_end - visit_start), in seconds.
    - `bytesServed` number, required: Total bytes served in the window — HTML pages, file downloads, sub-resources, ZIP archives. Sums across both `view` and `asset` events; ZIPs are estimated from R2 object sizes (slight over-count vs the wire bytes because ZIP compresses text).
  - `series` APIAnalyticsSeriesPoint[], required
    - `date` string, required: Bucket start (UTC). ISO date for daily buckets, ISO timestamp for hourly (24h range).
    - `views` number, required
    - `uniqueVisitors` number, required
    - `visits` number, required: Visits starting in this bucket.
    - `viewsPerVisit` number, required: Average pageviews per visit in this bucket.
    - `bounceRate` number, required: Fraction of this bucket’s visits with exactly one pageview (0..1).
    - `avgVisitDurationSeconds` number, required: Average visit duration in seconds for this bucket.
    - `bytesServed` number, required: Bytes served in this bucket.
  - `topPages` APIAnalyticsPageRow[], required: Top pages (visitor-scoped) over the window.
    - `path` string, required: Path of the page, as the worker saw it.
    - `visitors` number, required: Unique visitors who viewed the page.
    - `views` number, required: Pageviews of the page.
  - `entryPages` APIAnalyticsPageRow[], required: Visit-attributed entry pages — the first page of each visit.
    - `path` string, required: Path of the page, as the worker saw it.
    - `visitors` number, required: Unique visitors who viewed the page.
    - `views` number, required: Pageviews of the page.
  - `exitPages` APIAnalyticsPageRow[], required: Visit-attributed exit pages — the last page of each visit.
    - `path` string, required: Path of the page, as the worker saw it.
    - `visitors` number, required: Unique visitors who viewed the page.
    - `views` number, required: Pageviews of the page.
  - `topSources` APIAnalyticsBreakdown[], required: Top sources (referrer host). Same-site referrals are excluded; a genuine direct hit is the empty-label row, surfaced as "Direct".
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `topChannels` APIAnalyticsBreakdown[], required: Channel-grouped traffic (GA4-style channel taxonomy).
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `utmMediums` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `utmSources` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `utmCampaigns` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `utmContents` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `utmTerms` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `topCountries` APIAnalyticsBreakdown[], required: Top countries by visitors (ISO 3166-1 alpha-2 labels).
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `topRegions` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `topCities` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `topBrowsers` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `topOses` APIAnalyticsBreakdown[], required
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `topDevices` APIAnalyticsBreakdown[], required: `desktop` | `mobile` | `tablet` | "" (unknown).
    - `label` string, required: Dimension value. Empty string represents the "Unknown" bucket and is preserved verbatim — the dashboard renders it as such.
    - `visitors` number, required: Visitors contributing to this row.
  - `heaviestFiles` APIAnalyticsFileBandwidth[], required: Files that consumed the most bandwidth in the window, ranked by bytes served. Includes HTML pages, sub-resources (CSS/JS/images), direct file downloads and ZIP archives.
    - `path` string, required: Path of the file, as the worker saw it.
    - `bytes` number, required: Bytes served for this path in the window, summed across every response that included it (view or asset event).
    - `requests` number, required: Number of responses (view + asset events) that served the path.

## Other responses

- `403`: Admin access required
- `404`: Site not found

---

[API](https://skmtc.dev/nippy/apis/nippy-backend-api.md) · [All operations](https://skmtc.dev/nippy/apis/nippy-backend-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nippy/apis/nippy-backend-api/revisions/7ab23f040a55?raw)
