# Post-Call Analysis (/docs/agents/voice-agents/post-call-analysis)

> 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.

When a call with a voice agent ends, Tandem can read the transcript back and pull structured
values out of it: how the caller sounded, whether the call achieved what it was for, a short
summary, and any fields you define yourself.

This is a **separate pass**, not something the agent does during the call. It runs after the
caller hangs up, so it never slows a conversation down, it sees the whole call rather than the
part that had happened so far, and it can be as careful as it likes.

## Turning it on

Step to **Post-call** in the agent editor's stepper, then switch on **Analyze finished
calls** on the **Post-Call Analysis** card. Nothing is analyzed until you do.

<Callout type="info">
    Whether a transcript is kept is a separate setting — **Store conversation transcripts**, on the
    agent's Safety card — and it's on by default. Turning analysis on stores a transcript regardless
    of that setting, since analysis needs one to run against. See [Transcript
    retention](/docs/agents/voice-agents/safety#transcript-retention) for what's stored, how long,
    and when the default flips to off.
</Callout>

## The built-in fields

Three fields come with the feature. Each is a switch, and each is off until you turn it on.

| Field                | What you get                                                      |
| -------------------- | ----------------------------------------------------------------- |
| **Caller sentiment** | `positive`, `neutral`, or `negative` — how the caller came across |
| **Call outcome**     | `success` or `failure` — whether the call did what it was for     |
| **Call summary**     | A few sentences describing what happened on the call              |

Sentiment and outcome both also come back as `unknown` when the transcript doesn't support a
call either way — a caller who said three words leaves nothing to read.

**Call outcome** is the one worth configuring. Left alone, it judges success the way a reasonable
person would from the transcript alone — the caller got an answer and didn't leave frustrated. That
is rarely what _your_ line means by success. Switch it on and a **What counts as a successful
call** box appears; describe the bar in your own words:

```
The call is a success only if the caller confirmed an appointment date and time.
A caller who was transferred to a human is not a success, even if they were satisfied.
```

<Callout type="warn">
    Write the rule as a test the transcript can answer. "The caller was happy" is a judgment the
    model has to guess at; "the caller confirmed an appointment date and time" is something it can
    check. Vague bars are the main reason outcomes come back as `unknown`.
</Callout>

## Your own fields

Custom fields cover anything you would otherwise have a person listen for. Click **Analysis
Fields** on the card to open the editor, then **Add Field**.

Each field is five things:

- **Name** — how the value is labeled everywhere it appears. Letters, numbers, and underscores
  only, starting with a letter — `account_number`, `product_asked_about`.
- **Type** — the shape of the answer (below).
- **Allowed values** — for a **Choice** field, the complete list of answers it may give.
- **Prompt** — what to look for, in plain English. Up to 1,000 characters.
- **Required** — whether a call is only fully analyzed once this field comes back.

### Types

| Type         | Comes back as              | Use it for                                             |
| ------------ | -------------------------- | ------------------------------------------------------ |
| **Text**     | A string                   | Names, order numbers, free-form answers                |
| **Number**   | A number                   | Quantities, amounts, counts                            |
| **Yes / No** | `Yes` or `No`              | "Did the caller agree to a callback?"                  |
| **Choice**   | One of your allowed values | Anything you want to group or count later — a category |

Prefer **Choice** over **Text** whenever you already know the answers. A text field that comes
back "billing", "Billing question", and "about my bill" over three calls is three different
answers to the same question, and nothing can count it.

```
Name:           call_reason
Type:           Choice
Allowed values: billing, technical_support, sales, other
Prompt:         The main reason the caller phoned in. Pick the one that best fits what
                they spent most of the call on. Use `other` only if none of the rest apply.
Required:       on
```

An agent can have up to **20 custom fields**, and up to **32 allowed values** on a Choice field.

### Writing a prompt that works

The prompt is read alongside the transcript, so write it as an instruction to someone who has just
read the call and nothing else.

- **Say what to do when it isn't there.** "If the caller never gave an account number, leave this
  empty" beats letting the model invent something plausible.
- **Name the units.** "The dollar amount the caller disputed, as a number without a currency
  symbol."
- **Ask one thing per field.** A field that asks for the reason _and_ the resolution gets you one
  sentence containing both, which you then can't filter on. Two fields get you two values.

## Reading the results

Click **Recent Calls** at the top of the agent's editor. Each call lists the caller, when it
started, how long it ran, and its analysis status; expanding one shows the extracted values and
the transcript.

| Status                   | What it means                                                                       |
| ------------------------ | ----------------------------------------------------------------------------------- |
| **Analyzing**            | The call just ended and the pass hasn't finished. Usually seconds.                  |
| **Analyzed**             | Every field came back usable.                                                       |
| **Partly analyzed**      | Some fields came back, some didn't. The ones that failed are listed with why.       |
| **Not analyzed**         | Nothing to analyze: usually the call ran with analysis off, or nobody spoke on it.  |
| **Analysis failed**      | The pass couldn't complete. The values aren't available for this call.              |
| **Analysis unavailable** | The pass never came back. Nothing was extracted, but the transcript is still there. |

**Partly analyzed** is usually a prompt problem, not a fault: a Choice field whose allowed values
don't cover what actually happens on your calls, or a Number field asked for something nobody says
out loud. The reason is shown next to the field name, and changing the field affects the next
call — analysis isn't re-run against calls that already happened.

<Callout type="info">
    A stored transcript has a size ceiling, and a call that hit it says so when you expand it — only
    the part that was kept was analyzed. No ordinary conversation comes close, so seeing this means
    something on the call repeated itself: a tool returning far more text than it should, or a loop
    between the agent and the caller. Read the transcript rather than trimming your fields.
</Callout>

### What the agent did on the call

The transcript carries the agent's tool calls as well as what was said. Each one is a collapsed
row, in the place it happened, giving the tool, how it turned out — **Succeeded**, **Failed**, or
**No result** when the call ended before the tool answered — and how long it took. Expand a row
for the arguments the agent sent, the tool's own name as your configuration spells it, and, when
it failed, the reason the tool gave.

**No result is not a failure.** The tool may have answered after the caller hung up, with nobody
left to record it. **Running** never appears on a finished call, only on a conversation that is
still going.

An integration tool's row also shows the HTTP status its endpoint answered with, and admins can
open tabs with the request, the response, and what the agent saw. See [Request and response
details](/docs/agents/live-conversations#request-and-response-details). A `404` still reads
**Succeeded**, because the tool got an answer. See [What the agent
did](/docs/agents/live-conversations#what-the-agent-did) for the outcomes in full and for why a
duration is sometimes missing. Tool rows and their details are part of the transcript rather than
a record of their own, so they are kept for the same 90 days and erased with it. There is no
separate retention setting.

## What changing the configuration does

Analysis settings apply to a call **when the call ends**. Adding a field affects calls that end
after you save; it does not go back and fill the field in on calls already analyzed. Removing a
field stops it being collected, and leaves the values already collected on the calls that have
them.
