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

# Get Analytics

`GET /v2/analytics`

## Request

- Base URL: `https://api.traversal.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.traversal.com/v2/analytics`
- Auth: none declared

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'
- `actor_type` 'user' | 'service_account'

## 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' | 'actor', 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. ACTOR: left-aligned text naming a person or service account; the FE marks the row's ``actor_type`` beside it.
            - `link_href_template` string, nullable
          - `rows` RankedTableRow[], required
            - `cells` object, required
            - `entity_id` string, nullable
            - `actor_type` 'user' | 'service_account', 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``.
            - `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
            - `entity_id` string, required
            - `actor_type` 'user' | 'service_account', 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

## Changes

> 66 revisions in range; 9 not diffed.

- **2026-09-30** `4fa2a4911e01`: 2 warning, 5 info
  - added the new `actor` enum value to the `sections/items/metrics/items/data/ranked_table/anyOf[subschema #1: RankedTableData]/columns/items/format` response property for the response status `200`
  - added the new `actor` enum value to the `sections/items/metrics/items/data/single_sparkline/anyOf[subschema #1: SparklineData]/bottom_chart_detail/anyOf[subschema #1: RankedTableData]/columns/items/format` response property for the response status `200`
  - added the new optional `query` request parameter `actor_type`
  - added the required property `sections/items/metrics/items/data/investigators/anyOf[subschema #1: InvestigatorsData]/investigators/items/actor_type` to the response with the `200` status
  - …3 more

[Operation history](https://skmtc.dev/traversal/apis/traversal-api/changes/v2/analytics/get.md)

---

[API](https://skmtc.dev/traversal/apis/traversal-api.md) - [All operations](https://skmtc.dev/traversal/apis/traversal-api/llms.txt) - [OpenAPI document](https://skmtc.dev/traversal/apis/traversal-api/revisions/31e1a8b7cf89?raw)
