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

# Custom Analytics

> Rebuild custom_extractions items as extractions, one per item, before Custom Analytics is retired on 18 September 2026.

<Warning>
  **`custom_extractions` → Rebuild, one per item — 18 September 2026.** `custom_extractions` returns `null`. The key stays in the payload.
</Warning>

One extraction per configured item. The item type determines the answer type you pick.

## Type mapping

| Custom Analytics type  | Becomes                                                                                                   |
| ---------------------- | --------------------------------------------------------------------------------------------------------- |
| `freeflow`             | Free text                                                                                                 |
| `numeric`              | Free text, expected format numeric. Return type changes and min/max clamping has no equivalent.           |
| `list`                 | Pre-defined, one option per list value, each with a condition                                             |
| `advanced_list`        | Several extractions in one category                                                                       |
| `eligibility_analysis` | One pre-defined extraction for the verdict, replacing `eligibility_key`, plus one per underlying question |

An extraction returns one value, not a nested structure. Pre-defined options accept `sub_options`, but these fold into the same flat set of allowed answers instead of nesting. That is why a multi-part item becomes several extractions in a shared category.

## What to do

<Steps>
  <Step title="List your configured items and their types" />

  <Step title="Create a category per logical group">
    For example `Loan Eligibility`.
  </Step>

  <Step title="Add one extraction per item">
    Use the mapping above. Set name to the existing key to keep result keys stable.
  </Step>

  <Step title="For eligibility_analysis, name the verdict">
    Give the verdict a real name instead of the fixed `eligibility_key`.
  </Step>

  <Step title="Test against a real past transcript">
    See [Verifying a migration](/docs/migrating-to-extractions/overview#verifying-a-migration).
  </Step>

  <Step title="Remove the Custom Analytics items from the agent" />
</Steps>

## Before and after

<CodeGroup>
  ```json Before: verdict under a fixed key theme={"system"}
  {
    "custom_extractions": {
      "loan_amount": 250000.0,
      "eligibility_key": "Eligible",
      "income_verified": "Yes",
      "employment_type": "Salaried"
    }
  }
  ```

  ```json After: verdict takes a name you choose theme={"system"}
  {
    "custom_extractions": null,
    "extracted_data": {
      "Loan Eligibility": {
        "loan_amount": {
          "subjective": "250000",
          "validation": {
            "is_valid": true,
            "expected_type": "numeric"
          }, …
        },
        "eligibility": {
          "objective": "Eligible", …
        },
        "income_verified": {
          "objective": "Yes", …
        },
        "employment_type": {
          "objective": "Salaried", …
        }
      }
    }
  }
  ```
</CodeGroup>

Note that `advanced_list` and eligibility items were flattened up to the same level as everything else, rather than nested. That structure is unchanged in principle: related fields now sit in a shared category instead.

<Warning>
  **Numbers become strings.** `loan_amount` was the JSON number `250000.0` and is now the string `"250000"`. This is the change most likely to break a downstream numeric field silently. `validation.is_valid` confirms the value parses as a number, but the parsing is yours. There is also no equivalent of the min/max clamping Custom Analytics applied, so out-of-range values now reach you unchanged.
</Warning>

## What changes in your code

| Before                                                | After                                                                         |
| ----------------------------------------------------- | ----------------------------------------------------------------------------- |
| `d["custom_extractions"]["loan_amount"]` → `250000.0` | `float(d["extracted_data"]["Loan Eligibility"]["loan_amount"]["subjective"])` |
| `d["custom_extractions"]["eligibility_key"]`          | `…["Loan Eligibility"]["eligibility"]["objective"]`                           |
| Values clamped to your min/max                        | No clamping, so range-check yourself                                          |

Full detail on the result object is in [What the payload looks like](/docs/migrating-to-extractions/overview#what-the-payload-looks-like).

## Other features

<CardGroup cols={3}>
  <Card title="Extraction" icon="list-check" href="/docs/migrating-to-extractions/extraction">
    `extracted_data` · flat keys
  </Card>

  <Card title="Agent Extraction" icon="robot" href="/docs/migrating-to-extractions/agent-extraction">
    `agent_extraction`
  </Card>

  <Card title="Call Summary" icon="file-lines" href="/docs/migrating-to-extractions/call-summary">
    `summary`
  </Card>
</CardGroup>

Email [support@bolna.ai](mailto:support@bolna.ai) to remove a legacy summarisation task, or with an `execution_id` for a payload that does not match this guide.

## Next Steps

<CardGroup cols={3}>
  <Card title="Using Extractions" icon="list-check" href="/docs/prompting/using-extractions">
    Configure extractions in the dashboard
  </Card>

  <Card title="Dispositions API" icon="code" href="/docs/api-reference/dispositions/overview">
    Manage extractions programmatically
  </Card>

  <Card title="Webhooks" icon="webhook" href="/docs/post-call/polling-call-status-webhooks">
    Receive extraction data in real-time
  </Card>
</CardGroup>
