---
title: "Get Analytics"
method: GET
path: "/v2/analytics"
---

# Get Analytics

`GET /v2/analytics`

Return the schema-driven analytics payload for the caller's org.

Requires organization admin role or higher. Window params are validated by
FastAPI (bad timestamps / inverted range fail as 422 before this runs).

The Sessions metric's row-level table is not inlined — fetch it from
``/v2/analytics/{metric}/detail``.

## Query parameters

- `start_time` string, date-time, nullable — Start timestamp (inclusive), ISO 8601 with timezone. Defaults to 30 days ago.
- `end_time` string, date-time, nullable — End timestamp (exclusive), ISO 8601 with timezone. Defaults to now.
- `granularity` 'day'

## Response `200`

Successful Response

- AnalyticsResponse — The full schema-driven analytics payload for one organization.
  - `generated_at` string, date-time, required
  - `window` AnalyticsWindowResponse, required — The selected range and how the payload's figures were bucketed — the granularity and the timezone whose day boundaries were used. A day bucket is only meaningful relative to a zone, so ``timezone`` says which one: render every date and DATETIME cell in it, and label them with it. UTC for every org today; if bucketing ever moves to a per-org local day, this field carries that zone and rendering follows with no client change.
    - `start` string, date-time, required
    - `end` string, date-time, required
    - `granularity` 'day', required
    - `timezone` string, required — IANA timezone whose day boundaries the buckets use, and which every date and DATETIME cell in the payload should be rendered in (e.g. 'UTC')
  - `comparison` AnalyticsComparisonResponse, required — The period-over-period overlay window (prior period of equal length).
    - `start` string, date-time, required
    - `end` string, date-time, required
  - `sections` SectionResponse[], required — Ordered; drives page layout. Empty sections are omitted.
    - `id` 'AT_A_GLANCE' | 'USAGE' | 'TEAM_ADOPTION' | 'MOST_INVESTIGATED' | 'TEMPORARY', required — Routes a metric into a page section; section order drives page layout.
    - `title` string, required
    - `metrics` MetricResponse[], required
      - `id` 'active_users' | 'new_users' | 'session_starters' | 'sessions' | 'sessions_and_users' | 'sessions_per_user' | 'activity_heatmap' | 'top_users' | 'top_channels' | 'top_sessions' | 'investigators', required — Stable, public metric ids. Append-only — never rename or repurpose.
      - `name` string, required
      - `description` string, required — User-visible tooltip
      - `render_kind` 'SINGLE_SPARKLINE' | 'MULTI_SPARKLINE' | 'FEEDBACK_BREAKDOWN' | 'COMPOUND_TIMESERIES' | 'ACTIVITY_HEATMAP' | 'RANKED_TABLE' | 'INVESTIGATORS', required — The metric → component contract; the FE picks a component and reads the matching ``AnalyticsData`` variant off this. SINGLE_SPARKLINE: one line, overlaid with its prior-period points. MULTI_SPARKLINE: several current-period lines, each with only its prior total. FEEDBACK_BREAKDOWN: a headline rate + per-polarity (👍 / 👎) counts and trends. COMPOUND_TIMESERIES: a dual-axis chart; see ``CompoundTimeseriesData``. ACTIVITY_HEATMAP: a GitHub-style day-by-day calendar of per-day counts; see ``HeatmapData``. RANKED_TABLE: a ranked leaderboard table (columns + pre-sorted rows of cells); see ``RankedTableData``. INVESTIGATORS: an avatar leaderboard of session starters with streak/new badges; see ``InvestigatorsData``.
      - `has_detail` boolean, required — Whether GET /v2/analytics/{id}/detail serves a view; False means it 404s.
      - `data` AnalyticsData, required — A metric's computed result; exactly one variant is set, matching ``render_kind``.
        - `single_sparkline` SparklineData — A single-line sparkline carrying both the current- and prior-period points, so the FE can overlay current vs previous in one chart.
          - `label` string, required
          - `total` number, nullable
          - `previous_period_total` number, nullable
          - `points` TimeseriesPoint[], required
            - `date` string, required — ISO 8601 date (YYYY-MM-DD); a day boundary in the payload's bucketing timezone
            - `value` number, required
          - `previous_period_points` TimeseriesPoint[], required
            - `date` string, required — ISO 8601 date (YYYY-MM-DD); a day boundary in the payload's bucketing timezone
            - `value` number, required
          - `bottom_chart_detail` RankedTableData — A ranked leaderboard table (e.g. top users / channels by session count). Rows are pre-sorted (row index + 1 is the rank); every row's ``cells`` keys match ``columns``, so the table can carry any number of columns. **A compact rendering takes each row's headline number from the first COUNT column.** That is how the leaderboard card picks its progress-bar value, so a table rendered that way carries exactly one COUNT column: the value it ranks by. Tables only ever rendered in full may carry several, in whatever order reads best, and there ``sort`` alone says what the rows are ranked by.
            - `columns` RankedTableColumn[], required
              - …
            - `rows` RankedTableRow[], required
              - …
            - `sort` RankedTableSort — Which column ``RankedTableData.rows`` are pre-sorted by and in which direction, so the FE can render the sort indicator on that column (and default any client-side re-sort to match). ``column`` is a ``RankedTableColumn.key``.
              - …
            - `hide_search_bar` boolean
        - `multi_sparkline` MultiSparklineData — Several current-period lines (each with only its prior-period total), headlined by all lines combined vs the prior period.
          - `total` number, nullable
          - `previous_period_total` number, nullable
          - `series` AnalyticsSeries[], required
            - `label` string, required
            - `points` TimeseriesPoint[], required
              - …
            - `previous_period_points` TimeseriesPoint[]
              - …
            - `total` number, nullable
            - `previous_period_total` number, nullable
            - `axis` 'PRIMARY' | 'SECONDARY' — Which y-axis a series sits on: PRIMARY (left) or SECONDARY (right). Single-axis charts leave every series on PRIMARY.
        - `feedback_breakdown` FeedbackBreakdownData — Headlined by the window 👍/👎 counts (this period vs prior), with each polarity's daily trend.
          - `counts` FeedbackTotals, required — Window feedback counts by polarity (👍 / 👎).
            - `positive` integer, required
            - `negative` integer, required
          - `previous_period_counts` FeedbackTotals, required — Window feedback counts by polarity (👍 / 👎).
            - `positive` integer, required
            - `negative` integer, required
          - `positive_points` TimeseriesPoint[], required
            - `date` string, required — ISO 8601 date (YYYY-MM-DD); a day boundary in the payload's bucketing timezone
            - `value` number, required
          - `negative_points` TimeseriesPoint[], required
            - `date` string, required — ISO 8601 date (YYYY-MM-DD); a day boundary in the payload's bucketing timezone
            - `value` number, required
        - `compound_timeseries` CompoundTimeseriesData — A dual-axis chart (series spread across the two ``axes``), headlined by the primary-axis total vs the prior period.
          - `total` number, nullable
          - `previous_period_total` number, nullable
          - `series` AnalyticsSeries[], required
            - `label` string, required
            - `points` TimeseriesPoint[], required
              - …
            - `previous_period_points` TimeseriesPoint[]
              - …
            - `total` number, nullable
            - `previous_period_total` number, nullable
            - `axis` 'PRIMARY' | 'SECONDARY' — Which y-axis a series sits on: PRIMARY (left) or SECONDARY (right). Single-axis charts leave every series on PRIMARY.
          - `axes` AnalyticsAxis[], required
            - `id` 'PRIMARY' | 'SECONDARY', required — Which y-axis a series sits on: PRIMARY (left) or SECONDARY (right). Single-axis charts leave every series on PRIMARY.
            - `label` string, required
        - `activity_heatmap` HeatmapData — A GitHub-style activity calendar: one cell per day across the window. Shading is left to the FE — it owns the palette and how many intensity levels the "Fewer → More" key has — so this carries only the per-day truth plus the window headline.
          - `cells` HeatmapCell[], required
            - `date` string, required — ISO 8601 date (YYYY-MM-DD); a day boundary in the payload's bucketing timezone
            - `count` integer, required — Investigations that day
          - `total` integer, nullable
        - `ranked_table` RankedTableData — A ranked leaderboard table (e.g. top users / channels by session count). Rows are pre-sorted (row index + 1 is the rank); every row's ``cells`` keys match ``columns``, so the table can carry any number of columns. **A compact rendering takes each row's headline number from the first COUNT column.** That is how the leaderboard card picks its progress-bar value, so a table rendered that way carries exactly one COUNT column: the value it ranks by. Tables only ever rendered in full may carry several, in whatever order reads best, and there ``sort`` alone says what the rows are ranked by.
          - `columns` RankedTableColumn[], required
            - `key` string, required
            - `label` string, required
            - `format` 'count' | 'text' | 'datetime', required — How the FE renders a column's cells — alignment and display intent in one flag, so it never has to sniff a value (append-only; the FE keys off these). COUNT: right-aligned, locale-formatted. The only numeric format, so also what marks a column as a ranking value (see ``RankedTableData``). TEXT: left-aligned, verbatim. DATETIME: ISO 8601, rendered in ``AnalyticsWindowResponse.timezone`` so a row's timestamp can't disagree with the day bucket the charts count it in.
            - `link_href_template` string, nullable
          - `rows` RankedTableRow[], required
            - `cells` object, required
            - `entity_id` string, nullable
          - `sort` RankedTableSort — Which column ``RankedTableData.rows`` are pre-sorted by and in which direction, so the FE can render the sort indicator on that column (and default any client-side re-sort to match). ``column`` is a ``RankedTableColumn.key``.
            - `column` string, required
            - `order` 'asc' | 'desc' — Sort direction for a ranked table (append-only; the FE keys off these values).
          - `hide_search_bar` boolean
        - `investigators` InvestigatorsData — Avatar leaderboard of the period's session starters (sorted by session count desc) plus the headline counts; every session starter is included.
          - `investigators` Investigator[], required
            - `name` string, required
            - `session_count` integer, required
            - `streak_weeks` integer, required
            - `is_on_streak` boolean, required
            - `is_new` boolean, required
          - `total_count` integer, required
          - `new_count` integer, required
          - `streak_count` integer, required

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/traversal/apis/fastapi.md) · [All operations](https://skmtc.net/traversal/apis/fastapi/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/traversal/fastapi/revisions/2134ebffd1ef/schema)
