> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vocily.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Analysis

> Turn every finished conversation into structured, typed data you define — scores, budgets, lists, decisions.

The built-in summary and sentiment tell you how a conversation felt. **Custom Analysis** tells you
what it *meant for your business*: was this lead hot, warm or cold? What budget did they name?
Which products came up? Did they agree to a callback?

You describe the values you want in plain language, once. After every conversation Vocily reads the
transcript and returns them as real data — a number is a number, a list is a list — ready to filter
on, show in your call history, and send to your own systems over a webhook.

## Two levels: groups and analyses

<CardGroup cols={2}>
  <Card title="Group" icon="folder">
    A named set of related values — `Lead QA`, `Support Triage`. This is what an agent attaches,
    and everything inside it is extracted **together in one pass**.
  </Card>

  <Card title="Analysis" icon="tag">
    One named value inside a group — `Lead Temperature`, `Budget USD`. It has a result format and
    a description telling the model what to pull out.
  </Card>
</CardGroup>

A group is the unit of work. That is why the model choice and the run conditions belong to the
group rather than to each analysis — one pass cannot use two models.

## Definitions live in your workspace, not on the agent

You write a group **once**, in the library, and **attach** it to as many agents as you like.
Editing it there updates every agent running it, immediately. An agent never authors its own
analyses — it only chooses which groups to run.

| What you want to do               | Where you go                                      |
| --------------------------------- | ------------------------------------------------- |
| Create and edit groups            | **Observe → Custom Analysis**                     |
| Choose which groups an agent runs | **Agents → \[agent] → Outcome → Custom Analysis** |
| Stop all extraction for one agent | The master switch on that same screen             |
| See the results of a conversation | **Conversation → \[a call] → Extracted Data**     |
| Try it before going live          | **Test**, on the agent's Custom Analysis screen   |

## Result formats

Every analysis produces exactly one shape. Pick the one that matches the question:

| Format              | Use it for                              | You get back                               |
| ------------------- | --------------------------------------- | ------------------------------------------ |
| **True/false**      | Did something happen?                   | `true`                                     |
| **Text**            | A word, a phrase, an explanation        | `"hot"`                                    |
| **Number**          | Amounts, scores, anything with decimals | `50000.5`                                  |
| **Whole number**    | Counts, quantities, ratings             | `4`                                        |
| **List**            | Several answers to one question         | `["pricing", "integration"]`               |
| **Multiple fields** | One thing with several parts            | `{ "product": "Widget A", "quantity": 2 }` |

Choosing **List** asks you one extra question: is each item **a single value** or **multiple
fields**? It matters — the first gives you `["pricing", "integration"]`, the second gives you
`[{ "product": "Widget A", "quantity": 2 }]`. Vocily asks outright rather than leaving the shape
to chance.

### Allowed values

On a **Text** analysis, add **Allowed values** to restrict the answer to a fixed list — `hot`,
`warm`, `cold`. This is the single most reliable thing you can do to make results consistent,
because the model is *constrained* to those options rather than merely asked for them.

### Advanced constraints

Each format offers the limits that make sense for it, and only those: length, pattern and format
(email, date, URI…) for text; minimum, maximum and multiple-of for numbers.

<Note>
  Allowed values are enforced by the model itself. Every other constraint is sent as an
  instruction and then **re-checked by Vocily afterwards**. When a single value breaks a rule it is
  **kept and flagged** — a slightly-too-long sentence is still useful, and a blank tells you
  nothing. When an item in a **list** breaks a rule it is **dropped**, and the count is reported.
  A bad list entry is not a near-miss, it is noise.
</Note>

## Only run when it is worth it

Open **Advanced settings** on a group to set **Only run when…**. A group can require a minimum
number of messages, a minimum duration, or a specific way the call ended — pick from Completed,
Voicemail, No answer, Busy, Declined, Failed, Transfer completed, and Transfer failed. All the
conditions you set must pass.

Conditions are checked **before** any work happens, so a conversation that does not qualify costs
you nothing. It is marked **skipped**, never *failed*, so genuine failures stay easy to spot.

<Tip>
  A three-second wrong number has nothing to qualify. Setting a minimum of four messages on your
  sales group is the simplest way to stop paying to analyse hang-ups.
</Tip>

A minimum duration does not apply to text chats — a chat has no duration, so the rule is skipped
rather than silently disabling the group for every chat you ever have.

## Extract with a pattern instead of a model

Set **Extraction method** to **Regex** when the value has an exact, predictable shape — order IDs,
confirmation codes, ticket numbers. Vocily matches your pattern against the transcript directly:
faster, free, and it fails visibly instead of guessing. A capture group defines what gets pulled
out; a **List** collects every match, any other format takes the first.

Pattern and AI analyses mix freely inside one group, and a group made only of patterns never calls
a model at all.

## Test before you switch it on

Select **Test** on the agent's Custom Analysis screen. You can paste a transcript, or — better —
**pick a real past call**. Only a real call carries the duration and ending that your conditions
read, so it is the only way to see gating behave as it will in production.

The test shows each group's status, the model used, how long it took, and every value with the
model's one-line reasoning for it. Nothing is saved.

<Tip>
  Run the same test twice. The results should be identical — extraction is deliberately pinned to
  be repeatable, so drifting answers mean a prompt that is genuinely ambiguous.
</Tip>

## Reading your results

Results appear under **Extracted Data** on the conversation, grouped by group name, with types
preserved and each value's reasoning available. They also ride the `call.analysis.completed` and
`call.processing.completed` [webhooks](/developers/webhooks/events), addressed by the names you
typed:

```json theme={"dark"}
{
  "custom_analysis": {
    "Lead QA": {
      "Lead Temperature": "hot",
      "Budget USD": 50000,
      "Wants Demo": true,
      "Topics": ["pricing", "integration"]
    }
  }
}
```

<Warning>
  **The name is the address.** There is no hidden ID behind a group or an analysis. Renaming one
  changes what *later* conversations publish, so anything reading the old name stops finding it.
  Conversations already recorded keep the names they went out with — your history never rewrites
  itself.
</Warning>

A value can come back **Not found**. That is an answer, not a failure: the model read the
transcript and the value genuinely was not there. Asking how ready a caller is to buy, on a
delivery-tracking chat, *should* come back empty.

## Which model does the work

By default each group is analysed by **the agent's own model** — the one that held the
conversation. Override it per group under **Advanced settings** if you want a cheaper or stronger
model for that particular extraction. Any model in the catalogue works.

## Custom Analysis and versions

The groups an agent runs are part of its configuration, so the selection is saved with your draft
and travels with [versions](/building-agents/versions) like everything else. Rolling back restores
*which* groups ran.

The group definitions themselves are **not** versioned — they belong to the workspace. Editing a
group changes what every agent attaching it extracts, including agents on older published
versions. That is the point of a shared library, and worth remembering before you reword a
description that several agents depend on.

## Limits and permissions

|                             |                                |
| --------------------------- | ------------------------------ |
| Analyses per group          | 25                             |
| Groups per agent            | 10                             |
| Reading the library         | The analytics read permission  |
| Creating and editing groups | The analytics write permission |

Deleting a group never erases past results — conversations that already ran it keep everything
they extracted. See [Roles and permissions](/account-workspace/roles-permissions).
