Skip to main content

Video engagement analytics

A finished video session leaves behind more than a recording. Orbit collects a per-participant engagement feed for every session, aggregates theme-level chapter analytics across your recordings, and rolls up org-wide room usage — sessions, room-minutes, peak participants, and the never-joined bucket. This guide covers what each feed returns, how to read it, and which product questions each one answers. All routes live under https://api.orbit.devotel.io/api/v1 and are scoped to your tenant: you can only ever read engagement for your own sessions.

1. What the engagement feed returns

The engagement feed answers, for one realized session of one room: who spoke and for how long, who held the floor, who shared their screen, and who raised a hand. The host’s meeting client buffers the active-speaker, screen-share, and hand-raise signals during the call and sends one finalized rollup per participant when the room ends — you read the result; you never have to collect signals yourself. The session-scoped read is:
It returns four blocks: Each participant row carries participant_identity, display_name, speaking_duration_seconds, speaking_share, screen_share_duration_seconds, hand_raise_count, dominant_segments (that participant’s floor-holding windows), and first_spoke_at / last_spoke_at. Three reading rules:
  • has_data: false means the session predates engagement capture or never finalised a rollup — render an empty state, not a table of zeros.
  • The participant list is paginated (?limit=, ?offset=, ?after= — default page 50, maximum 200). Page through with the opaque page.next_cursor as ?after=; a stale or garbled cursor degrades to the first page rather than erroring. Session totals and the dominant timeline stay computed over the full roster on every page, so a paged read never understates them.
  • Sessions predate capture gracefully: a 404 means the session id is not in your workspace; a 200 with has_data: false means the session exists but has no engagement rows yet.

2. Reading one session’s engagement

Page through the participant list and read the aggregates:
Sort is already most-speaking first, so the first page is your speaker leaderboard. A speaking_share of 0.85 on row one tells you one voice dominated; ten rows clustered between 0.05 and 0.15 reads as a balanced panel. Row-level hand_raise_count and screen_share_duration_seconds flag active participants who barely spoke — the audience questions and the demo segments show up there. The dominant_timeline overlay answers “who held the floor when”: plot each window as a block on the session’s timeline and you get the host/segment structure of a webinar — long host windows at the open, short panel windows mid-call, a return to the host for the close.

3. Session pages vs the org-wide aggregate

Per-session engagement answers “what happened inside this meeting.” The org-wide aggregate answers “how is the organisation using video rooms.” They are two different lenses — do not try to derive one from the other.
from and to are ISO 8601 bounds; omit both and the window defaults to the last 30 days. The response carries a summary plus a daily series (one bucket per UTC day, capped at one year of buckets) for sessions-over-time charts: Read unused_rooms and error_sessions apart. A high unused_rooms count means rooms were minted and never joined — wasted scheduled meetings, or an embed creating rooms speculatively. It is a utilisation signal, never a fault. error_sessions is the metric to page on: those rooms reached participants and then failed. (The legacy alias join_failures, equal to unused_rooms, stays on the wire for older readers; render unused_rooms.)

4. Chapter analytics across recordings

Where engagement reads one session live, chapter analytics reads your recordings at aggregate: the auto-chaptered themes on your recordings are grouped over a window so you can see which topics recur and how long they run.
Each row is { theme, occurrence_count, avg_duration_ms, recordings_count } — a normalised chapter title, how many chapters carry it, their average length, and how many distinct recordings contained it, most-frequent first, capped at 50 themes. The window defaults to the last 30 days. Use it to answer “what do our calls actually spend time on” — a rising Pricing objection theme tells sales enablement what to train; themes that only appear on one recording (recordings_count: 1) are one-offs, not trends.

5. Mapping metrics to product questions

A sample dashboard read: chart the org aggregate’s daily.sessions as a sparkline, summary.unused_rooms as a stat next to total_sessions (a ratio, not a raw count), summary.recording_success_rate as a gauge, and the chapter themes as a top-N bar chart. For live “who is talking now” during a call, use the in-call snapshot read covered in Monitor in-call video quality — this feed is for after the room ends.

Worked example: a weekly engagement report

Keep the poll size small (?limit=5 here) when you only need the leaderboard; page the full roster only when a report needs every participant.

What to check when something looks wrong

  • has_data: false on a recent session — the rollup is sent at room-end; give it a moment, then re-read. Sessions that predate engagement capture never gain rows.
  • A 404 — the session id is wrong for this workspace, not “no data”; the two are deliberately different signals.
  • Participants missing from a long roster — you are reading page one of a paginated list; follow page.next_cursor.
  • recording_success_rate: null — nothing attempted a recording in the window, not a failure.
  • High unused_rooms — usage signal, not an outage; look at how and when your rooms are created before treating it as a defect.

Where to go next