# Insights & Reporting (/docs/workflows/insights-and-reporting)

> For the complete documentation index, see [llms.txt](https://docs.tandemcx.ai/llms.txt). Any page on this site can be fetched as Markdown by appending `.md` to its URL.

**Insights** reports on conversations your account has actually handled. It has three pages
(Usage Reports, Call Logs, and Voice Trends) plus a read-only replay of any single workflow run
on the flow canvas.

Reporting is derived from what your conversations emit as they run, so one appears once it has
finished. It is a record of what happened, not a live view of what is happening now — for that,
use **Supervisor**.

To compare your AI agents on containment, resolution, and transfers, see [Agent
Performance](/docs/agents/performance).

## Channels

Insights covers more than phone calls. Every conversation records the **channel** it happened
over, and each page has a **Channel** filter offering the media your account actually has data for
in the selected range.

| Channel      | What it covers                                     |
| ------------ | -------------------------------------------------- |
| **Voice**    | Phone calls, inbound and outbound                  |
| **Web Chat** | Conversations from a chat widget on your website   |
| **SMS**      | Text messages that started or continued a workflow |
| **MMS**      | Picture and multimedia messages                    |
| **Email**    | Email conversations                                |

You only see a Channel filter when your account has more than one medium in range — with only
phone calls, the control would have nothing to narrow.

<Callout type="info">
    If you have used Insights before, some of your **SMS** conversations were previously counted and
    listed as calls. They were always in the data; there was no way to tell them apart. Historical
    conversations have been re-labeled, so a total you noted down earlier may now split differently
    across channels. The sum is unchanged.
</Callout>

### What a duration means depends on the channel

**Avg Duration**, the Duration column, and the Minutes total are wall-clock length from start to
end. That is a call's talk time, but on a web chat it includes the time a visitor spent reading
before replying, and on a text message it means very little at all. Compare durations **within** a
channel, not across them; the Channel filter is what makes that possible.

### A conversation with no channel

A conversation whose medium was never recorded shows **—** rather than being assumed to be a call.
Choosing any specific channel excludes it, since "not known" is not a medium.

## Dates and times are UTC

Every date bucket, range preset, and timestamp in Insights is **UTC**, and the controls are
labeled to say so. "Today" therefore begins at 00:00 UTC, which may not be your local midnight.

This matters when comparing against a report from somewhere else: if the numbers are close but
not equal, check whether the other report uses local time before assuming one is wrong.

## Usage Reports

Seven totals for the range you select, a volume chart, and a per-day table.

### Calls and runs count different things

The two are counted differently.

- The **Total Calls** card counts _conversations_ — one per conversation, however many workflows
  it passed through, and on **every** channel.
- The table's **Runs** column counts _workflow runs_. A conversation that hands off from one
  workflow to another contributes a run to each.

So on an account where workflows chain, summing the Runs column gives a **larger** number than
the Total Calls card. Both are correct; they answer different questions ("how many people got in
touch?" versus "how much work did this workflow do?").

There is a second reason the two can differ, and it is the more common one on a multi-channel
account: **the table only has rows for conversations that ran a workflow.** A web chat handled
entirely by an AI agent runs none, so it counts in the cards and in the chart but has no row in
the table below. There is no workflow to attribute it to. Filtering by workflow narrows the whole
page to workflow runs for the same reason.

### The other cards

| Card                | Meaning                                                                                                     |
| ------------------- | ----------------------------------------------------------------------------------------------------------- |
| **Total Transfers** | Conversations that were transferred out of a flow                                                           |
| **Avg Duration**    | Mean length of conversations that have a recorded duration                                                  |
| **Transfer Rate**   | Transfers as a share of conversations, with the change in **percentage points** against the previous period |
| **Completed**       | Conversations that finished normally                                                                        |
| **Abandoned**       | Conversations that ended before the flow finished — the caller hung up, or the visitor stopped replying     |
| **Failed**          | Conversations where a step errored                                                                          |

Averages and durations skip conversations that have no recorded length — a call rejected at a
concurrency limit never connected, so counting it as zero seconds would pull the average down.
For the same reason a missing duration shows as **—** rather than `0s`.

Transfers are a **voice and chat** idea. A text message or an email is never transferred, so on an
account with a lot of messaging traffic the Transfer Rate is diluted by conversations that could
never have been transferred. Filter to a channel to read it fairly.

### Failed under-reports slightly

A step that errored _and_ never reported finishing leaves no error record, so its call is counted
**Abandoned** rather than Failed. Treat Failed as a floor, not an exact count.

### Large accounts see a top-N table

The detail table lists the busiest workflows, up to a limit. If your account has more workflows
than that in the range, a notice above the table says how many are not listed. The chart and the
seven cards always cover **every** workflow, so the totals stay complete even when the table is
trimmed.

## Call Logs

Every conversation in range, newest first, with search and filters for channel, status, type,
workflow, agent, and date range. The list is paged; the page you are on is part of the address, so a link you share
opens on the same page it did for you.

<Callout type="info">
    **One row per conversation is being rolled out.** If your Call Logs still has **Workflow** and
    **Workflow ID** columns, it is the earlier list described under [One row per workflow
    run](#one-row-per-workflow-run) below, and the rest of this section does not apply yet.
</Callout>

### One row per conversation

A conversation is one row, however many workflows it went through. A caller who reaches an AI
agent, has it invoke two workflows, and is then handed off is a single row with a single
**Conversation ID** — the same id every part of the call reported under.

The columns are Channel, Conversation ID, Source, Destination, Handled by, Start Time (UTC),
Duration, and Status. Channel is shown as an unlabeled icon; hover over it to see the name.

An inbound voice call's **Destination** is labeled **Toll-free** or **Local** by the kind of
number it came in on. That's how its call minutes are billed on the Billing page's **Usage** tab,
and hovering over the label says so. The label shows even when the workflow's **Redact Data in
Logging** setting hides the numbers. A [browser test
call](/docs/workflows/test-a-workflow-with-a-browser-call) reads **Browser test call** under
**Source** and has no **Destination**. A conversation's page shows the same under **From** and
**To**. Calls made before the label was added have none.

**Status** is the conversation's outcome, not one leg's. A conversation whose workflow failed
reads **Failed** even if the call itself completed, because a step that errored is the more useful
fact.

### Sub-tenant calls

If your organization has [sub-tenants](/docs/overview/sub-tenants), Call Logs lists their
conversations beside your own, with an **Organization** column and an **Organization** filter to
narrow the list. This needs administrator access in your organization. Every role Tandem issues
today (Owner, Admin and Member) carries it. Usage Reports and Voice Trends cover your own
organization only.

Opening a sub-tenant's conversation shows its details log, step timeline and recording. Its call
summary, transcript, wrap-up and collected data are not shown from the parent organization, and its workflow
steps have no **View in Flow**. A sub-tenant row names the caller's contact without linking to
it. Switch to the sub-tenant to see any of these.

### Who handled a conversation

**Handled by** shows the first workflow or AI agent that took the conversation, marked with the
Workflows or Agents icon, and **+N** when more followed. Hover over it to see every one, in the
order they took the call.

The **Type** filter sorts conversations by what handled them:

- **Workflow only**: one or more workflows ran, and no AI agent took part.
- **Agent only**: an AI agent handled it, and no workflow ran.
- **Workflow + agent**: both, in either order. A workflow that hands the call to an agent and an
  agent that hands it to a workflow both count.

A conversation nothing answered, such as one the caller abandoned before a workflow or agent
picked up, matches none of the three.

The **Agent** filter lists the agents with conversations in the selected range. It matches a
conversation when the agent answered it or was switched to during it. Picking a workflow and an
agent shows only conversations both of them handled.

Switches between agents are read from the call details log, so on a conversation older than that
log only the agent that answered counts. See [Conversations older than the action
list](#conversations-older-than-the-action-list).

### Filters from Agent Performance

A drill-down sheet on [Agent Performance](/docs/agents/performance#drill-downs) ends with **Open
these conversations in Call Logs**. The link opens Call Logs on that agent, the sheet's date range
and channels, and the sheet's own conditions. Each condition shows as a chip above the list, for
example **Not contained**, **Ended: Caller hung up**, **Outcome: Unresolved**, **Sentiment:
Negative**, **Taken over**, **Version: v2.1**, **Transfer to: Billing · Failed**, **Tool: lookup ·
failed**, **Repeat contact**, or **Day: Oct 3, 2026 (UTC)**. These conditions have no control in
the **Filters** menu, so the chips are where you see and change them.

To drop one, click the **x** on its chip. The list refreshes without that condition and keeps the
rest. A chip that carries two conditions, such as a transfer destination and its result, drops
both. When the last chip is gone, the list is the agent's calls in the range.

Each conversation is listed once, even if the agent handled it more than once. Agent Performance
counts every time the agent answered, so its number can be higher than the number of rows here.

These conditions describe one agent's calls, so they apply only while exactly one agent is chosen
in the **Agent** filter. With none or several, the chips stay and a note reads "These filters
describe one agent's calls, so they are not applied until exactly one agent is chosen."

If the list is not filtered by the chips, a warning reads "These filters aren't supported yet, so
this list isn't filtered by them." Treat the list as unfiltered. It appears when the server did
not confirm that it applied the conditions.

### The call details log

Expanding a row lists everything that happened on the conversation, in order, with a time and the
actor for each: the agent starting, a workflow being invoked, a hand-off out and back, a switch
from one agent to another, a transfer, the conversation ending.

A workflow entry carries that run's **step timeline** underneath it — every step in order, how long
each took, and which exit it left by — which is what the earlier list showed for the row as a
whole.

**View in Flow** sits on the workflow entry rather than on the row. With more than one workflow on
a call there is no single flow to open, so the button belongs to the run you picked. It replays
that run on the canvas step by step, highlighting the path it took, and always loads the workflow
**version that ran** — a call from before an edit still replays against the flow as it was.

If a hop shows a name you do not recognise, it is a kind of hop this page is older than. The log
shows it under its raw name rather than hiding it.

Four things the log deliberately does not contain:

- **Variable values.** Step inputs and outputs are not retained in reporting.
- **Tool arguments and tool results.** The log records that a tool ran, not what it was passed.
- **What was said.** Use the row's transcript button, described below.
- **A status, on rows where nothing recorded one.** Those show **—** rather than a guess.

### Recorded calls

A call that was recorded, or that Tandem tried to record, carries a small icon beside its
**Status**. Hover over it to see which of three states the recording is in:

- **Recorded** — the recording is stored.
- **Recording pending** — the recording has ended and is being stored.
- **Recording failed** — no recording of this call was stored.

A pending recording moves to one of the other two once it is stored or fails. A call with no
icon was not recorded, or is still in progress. Calls recorded before this indicator was added
show no icon either.

Expanding the row repeats the state as a badge next to **Call Details**:

- **Recording: 4m 12s** — the length of the stored audio. It can be shorter than the call's
  **Duration**, because a stretch where recording was paused is missing from the audio.
- **Recording: Ready** — stored, with no length available.
- **Recording: Processing** — still being stored.
- **Recording: Failed** — followed by the reason when Tandem has one, such as **No audio
  captured** or **Deleted to protect card details**. The second means Tandem deleted the
  recording because it could not confirm that recording had paused during card entry.

There is no way to play a recording from Call Logs yet. See [Call
Recording](/docs/overview/call-recording) for which calls are recorded.

### What a conversation cost

A conversation's page shows a **Cost** section under its summary: each charge on the conversation
with its quantity and cost, and the total, at your contract's rates. It is the same figure the
Billing page's **By Conversation** view lists; see [Usage](/docs/overview/billing#usage). Call,
IVR, and AI Voice time is rounded up to the next half minute, and the section says so; see [How a
call is billed](/docs/overview/billing#how-a-call-is-billed). On a browser test call, it also says
why the call shows a **Local call, in** charge. It is
not shown inside a sub-tenant, or on a sub-tenant's conversation opened from its parent, because a
sub-tenant's usage is billed to its parent.

### Answer detection on outbound calls

An outbound call placed by a Convert to Voice node with **Detect Human or Answering Machine** on
shows what detection decided. The verdict is a badge in the **Status** cell. Hover over it to see
the reason. Open the call and the **Details** tab lists it as **Answer detection**, with the reason
in parentheses.

- **Human** — a person answered.
- **Machine** — an answering machine or voicemail answered.
- **No answer** — the call was not answered.
- **Detection failed** — the call was answered, but no human or machine verdict could be
  produced. The workflow takes the node's `detectionFailed` exit.

The reason is the rule that produced the verdict, such as **Brief greeting**, **Voicemail phrase
heard**, **Continuous speech**, or **No clear speech before the time limit**. A verdict that
carries no reason, such as **No answer**, shows the verdict alone. A label Tandem does not
recognise appears under its raw name.

A call with no badge did not use detection, or was placed before this was recorded. An outbound
call whose workflow was started through the API has no channel until detection reports or a voice
agent takes the call. It is then listed with the **Voice** channel and the **Outbound** direction.

### Conversations older than the action list

The action list is recorded from the change forward and nothing was filled in behind it. An older
conversation shows its workflow runs and their step timelines, with no list of hops above them. It
also keeps whatever ids it reported under at the time, so a call that produced two rows then still
produces two rows now.

### Reading a web chat

The transcript button at the end of a row (the speech-to-text icon, **View Transcript** on hover)
opens the conversation and shows everything that was said, in order. It appears on **Voice** and
**Web Chat** rows only — those are the channels a transcript is kept for.
If a web chat's full transcript has aged out, the panel shows the agent's own retained history
instead and says so above it: that history is trimmed from the front, so a long conversation may
not start where the visitor did.

The download button beside the panel's close saves the whole conversation as a text file — the
header, then one line per message. Times in the file are UTC, not your local time, so the file still
reads correctly for whoever you send it to.

### A call a supervisor took over

<Callout type="info">
    **This is being rolled out** with [the transcript after a
    take-over](/docs/agents/live-conversations#after-a-supervisor-takes-a-call-over).
</Callout>

When a supervisor took a call over from its agent, the conversation's details say who did and when
(**Taken over (UTC)**), how they closed it out (**Supervisor disposition**, with their note), and
why, when they said (**Why they stepped in**). The supervisor's disposition sits beside the agent's
own **Disposition** rather than replacing it, and also appears on a call a supervisor joined and
closed out without taking over.

The transcript carries on past the agent's last turn. A line reads **[name] took over the call.
The agent left.**, and what the caller and the supervisor said after it follows. A downloaded
transcript includes both parts.

### One row per workflow run

The earlier list, still in place for organizations the change has not reached.

A conversation that ran a workflow gets **one row per run**, so one that chained two workflows
appears twice, and the rows carry **Workflow** and **Workflow ID** columns instead of **Handled
by**. A conversation that ran no workflow, such as a web chat handled entirely by an AI agent, gets
a single row with **—** in those columns and an empty execution path. Nothing is being withheld
there: without a workflow run there are no steps to list.

Expanding a row shows that run's **execution path** and its **View in Flow** button. There is no
action list and no transcript panel.

## Voice Trends

A flow diagram of how conversations actually moved through your steps, with a **Top Paths** table
beneath it.

Despite the name, this page covers every channel that runs a **workflow** — an SMS-driven flow is
drawn here alongside a phone menu. What it cannot show is a conversation that ran no workflow,
because there are no steps to draw. Use the Channel filter to look at one medium's flow shape on
its own.

### Global and per-workflow views

- **Global** groups by _step type_ — "Play Message", "Condition", "Transfer to Queue". Useful as
  a shape-of-traffic overview across everything.
- **Per Workflow** groups by _step name_, giving the real picture of one flow. Select one or more
  workflows to switch to it.

Global is intentionally coarser. Grouping by name across unrelated workflows would merge steps
that merely share a name, so the global view trades detail for a view that spans everything.

### Repeated steps are listed, not drawn

A flow diagram cannot draw a loop. When callers go back to an earlier step — a menu re-prompt, a
retry after invalid input — that movement is removed from the diagram and reported beneath it as
**Repeated steps**, with a count per step.

So a step showing "×146" means callers returned to it 146 times in the range. Those calls are not
missing from the totals; they are just not drawable as an arrow.

### Top Paths

The most common whole-call routes, as a share of all runs in the range. Two caveats:

- These are the **top few** paths, not every path, so the percentages do not add up to 100%.
- A call running longer than an hour may have its earliest steps missing from its recorded path,
  so very long calls are under-represented here.

## When a page looks empty

An empty Insights page is usually accurate rather than broken:

- **Reporting history starts when reporting was switched on** for your account. There is no
  backfill, so calls from before then do not appear.
- **The range may genuinely have no conversations** — try a wider one.
- **A filter may exclude everything.** The workflow and channel filters only offer values that
  have data in the selected range, so widening the range can reveal more options.
- **A channel filter hides conversations with no recorded medium**, and a workflow filter hides
  conversations that ran no workflow. Clearing both is the quickest way to tell an empty range
  from an over-narrow one.

Ranges are limited to 90 days. A longer range is refused rather than silently truncated, so a
number you read is always the whole number for the window shown.
