---
title: Metadata Extensions | Developer Documentation
description: Advanced extraction features including citations and confidence scores for enhanced data extraction workflows.
---

LlamaExtract offers several advanced features that provide additional metadata and insights alongside your extracted data. These extensions are available under `Advanced Settings` in the UI and return schema-level metadata in the `extract_metadata` field of the response.

## Citations

Citations provide the source information for every extracted field, allowing you to trace back exactly where each piece of data came from in the original document.

**How it works**: For every leaf-level field in your schema, citations return:

- The page number where the information was found
- The verbatim text that was used to extract the field value
- Bounding box coordinates (`x`, `y`, `w`, `h`) indicating the exact location of the cited text on the page
- Page dimensions (`width`, `height`) to help you render the bounding boxes accurately

Citations appear in the API response under `extract_metadata.field_metadata.document_metadata` and in the LlamaCloud UI. See [Extract response format](../response-format/) for the field reference.

**Example API response structure (scalar fields):**

```
"extract_metadata": {
  "field_metadata": {
    "document_metadata": {
      "phone": {
        "citation": [
          {
            "page": 1,
            "matching_text": "(555) 123-4567",
            "bounding_boxes": [
              {
                "x": 177,
                "y": 82,
                "w": 318,
                "h": 43
              }
            ],
            "page_dimensions": {
              "width": 612,
              "height": 792
            }
          }
        ]
      }
    }
  }
}
```

**Array fields:** Citations attach at the **leaf sub-field level**, not the array item level. The `field_metadata` tree mirrors the structure of your extracted data, with each leaf value replaced by its citation metadata.

For a schema like `key_facts: list[KeyFact]` where `KeyFact` has a `fact: str` field, the metadata structure is:

```
"extract_metadata": {
  "field_metadata": {
    "document_metadata": {
      "key_facts": [
        {
          "fact": {
            "citation": [
              {
                "page": 3,
                "matching_text": "Revenue grew 114% year-over-year",
                "bounding_boxes": [{ "x": 50, "y": 200, "w": 400, "h": 20 }],
                "page_dimensions": { "width": 612, "height": 792 }
              }
            ]
          }
        },
        {
          "fact": {
            "citation": [
              {
                "page": 7,
                "matching_text": "Operating expenses increased to $3.2B",
                "bounding_boxes": [{ "x": 50, "y": 310, "w": 380, "h": 20 }],
                "page_dimensions": { "width": 612, "height": 792 }
              }
            ]
          }
        }
      ]
    }
  }
}
```

Note: the citation path is `field_metadata.document_metadata.key_facts[i].fact.citation`, **not** `field_metadata.document_metadata.key_facts[i].citation`. Each array element in the metadata corresponds positionally to the same element in the extracted data.

**Usage**: Set `cite_sources: true` in the configuration to enable this feature.

**Use cases**:

- Compliance and audit requirements
- Fact-checking and verification workflows
- Understanding extraction quality and accuracy
- Building custom highlighting/annotation features using bounding box coordinates

## Confidence Scores

`confidence` is the overall score for a field value, from 0 to 1. Higher scores indicate greater confidence that the value is correct. Each field has its own score, so you can send uncertain values to human review while accepting the rest of a document. A high score is still an estimate, not a guarantee of correctness.

### Enabling and reading scores

Set `confidence_scores: true` in the configuration to include scores in `extract_metadata.field_metadata`. When retrieving a job, request `expand=extract_metadata` to include that metadata in the response. See [Extract response format](../response-format/#expanding-the-response).

The metadata follows the same nested structure as your schema. For example, a document with a `total` field and an `items` array could return:

```
{
  "extract_metadata": {
    "field_metadata": {
      "document_metadata": {
        "total": {"confidence": 0.97},
        "items": [
          {"amount": {"confidence": 0.62}}
        ]
      }
    }
  }
}
```

The score for the first item’s amount is at `extract_metadata.field_metadata.document_metadata.items[0].amount.confidence`. With a review threshold of 0.8, your application would send that amount to review and accept the total. The threshold is your application’s decision.

### Choosing a review threshold

Choose a review threshold using a sample of your own documents with known correct values. Start with a candidate threshold, then check both the fields sent to review and those accepted automatically. Count how many errors the threshold catches, how many incorrect values pass through, and how much review it creates. Raise the threshold to review more fields, or lower it to reduce review volume.

Use stricter thresholds for fields where an incorrect value is costly. Long free-text fields, such as summaries and descriptions, can score lower than short factual fields. Evaluate them separately rather than assuming one cutoff works for every field type.

### Interpreting the score

Calibration describes how closely scores match observed correctness. Calibration varies by tier and version, so a score of 0.8 does not always mean an 80% probability of correctness. Validate your cutoff on the tier and version you use, and check it again when you change versions or start processing different kinds of documents.

## Reasoning Metadata

Reasoning metadata is available for Extract versions through `2026-03-31`. Newer versions do not return per-field reasoning strings.

If your application depends on reasoning strings in `extract_metadata.field_metadata`, pin `configuration.version` to `2026-03-31`. For newer versions, use citations and confidence scores when you need provenance or review signals.

### Performance Considerations

**⚠️ Important**: Citations and confidence scores will significantly slow down extraction processing time. Enable these features only when the additional metadata is essential for your use case.

### Configuration and Usage

For complete examples of how to configure and use these extensions with both the Python SDK and REST API, see the **[Configuring Extract](/llamaparse/extract/guides/configuring-extract/#setting-configuration-options/index.md)** page.

The configuration section includes:

- Complete Python SDK examples with extension settings
- REST API curl command examples
- Configuration reference table with all available options

**Quick reference for extensions:**

Download a sample resume as `document.pdf`:

Terminal window

```
curl -fL -o document.pdf https://raw.githubusercontent.com/run-llama/llama_cloud_services/main/examples/extract/data/resumes/software_architect.pdf
```

- [Python](#tab-panel-580)
- [TypeScript](#tab-panel-581)
- [Go](#tab-panel-582)
- [Java](#tab-panel-583)
- [CLI](#tab-panel-584)

```
import time
from llama_cloud import LlamaCloud


client = LlamaCloud()  # reads LLAMA_CLOUD_API_KEY from the environment


file_obj = client.files.create(file="document.pdf", purpose="extract")
file_id = file_obj.id


job = client.extract.create(
    file_input=file_id,
    configuration={
        "data_schema": {"type": "object", "properties": {}},  # your extraction schema
        "tier": "agentic",
        "cite_sources": True,
        "confidence_scores": True,
    },
)


# Poll for completion
while job.status not in ("COMPLETED", "FAILED", "CANCELLED"):
    time.sleep(2)
    job = client.extract.get(job.id)
```

```
import fs from 'fs';
import LlamaCloud from '@llamaindex/llama-cloud';


const client = new LlamaCloud(); // reads LLAMA_CLOUD_API_KEY from the environment


const fileObj = await client.files.create({
  file: fs.createReadStream('document.pdf'),
  purpose: 'extract',
});


let job = await client.extract.create({
  file_input: fileObj.id,
  configuration: {
      data_schema: { /* your extraction schema */ },
      tier: 'agentic',
      cite_sources: true,
      confidence_scores: true,
    },
});


// Poll for completion
while (!['COMPLETED', 'FAILED', 'CANCELLED'].includes(job.status)) {
  await new Promise((r) => setTimeout(r, 2000));
  job = await client.extract.get(job.id);
}
```

```
package main


import (
    "context"
    "log"
    "os"
    "time"


    llamacloud "github.com/run-llama/llama-parse-go"
)


func main() {
    ctx := context.Background()
    client := llamacloud.NewClient()


    // Your extraction schema
    dataSchema := map[string]*llamacloud.ExtractConfigurationDataSchemaUnionParam{
        "type":       {OfString: llamacloud.String("object")},
        "properties": {OfAnyMap: map[string]any{}},
    }


    // Upload a file to extract from
    f, err := os.Open("document.pdf")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()


    fileObj, err := client.Files.New(ctx, llamacloud.FileNewParams{
        File:    f,
        Purpose: "extract",
    })
    if err != nil {
        log.Fatal(err)
    }


    job, err := client.Extract.New(ctx, llamacloud.ExtractNewParams{
        ExtractV2JobCreate: llamacloud.ExtractV2JobCreateParam{
            FileInput: fileObj.ID,
            Configuration: llamacloud.ExtractConfigurationParam{
                DataSchema:       dataSchema,
                Tier:             llamacloud.ExtractConfigurationTierAgentic,
                CiteSources:      llamacloud.Bool(true),
                ConfidenceScores: llamacloud.Bool(true),
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }


    // Poll for completion
    for job.Status != "COMPLETED" && job.Status != "FAILED" && job.Status != "CANCELLED" {
        time.Sleep(2 * time.Second)
        job, err = client.Extract.Get(ctx, job.ID, llamacloud.ExtractGetParams{})
        if err != nil {
            log.Fatal(err)
        }
    }
}
```

```
import ai.llamaindex.llamacloud.client.LlamaCloudClient;
import ai.llamaindex.llamacloud.client.okhttp.LlamaCloudOkHttpClient;
import ai.llamaindex.llamacloud.core.JsonValue;
import ai.llamaindex.llamacloud.models.extract.ExtractConfiguration;
import ai.llamaindex.llamacloud.models.extract.ExtractCreateParams;
import ai.llamaindex.llamacloud.models.extract.ExtractGetParams;
import ai.llamaindex.llamacloud.models.extract.ExtractV2Job;
import ai.llamaindex.llamacloud.models.extract.ExtractV2JobCreate;
import ai.llamaindex.llamacloud.models.files.FileCreateParams;
import ai.llamaindex.llamacloud.models.files.FileCreateResponse;
import java.nio.file.Paths;
import java.util.HashMap;


LlamaCloudClient client = LlamaCloudOkHttpClient.fromEnv();


// Your extraction schema
ExtractConfiguration.DataSchema dataSchema = ExtractConfiguration.DataSchema.builder()
        .putAdditionalProperty("type", JsonValue.from("object"))
        .putAdditionalProperty("properties", JsonValue.from(new HashMap<String, Object>()))
        .build();


FileCreateResponse fileObj = client.files().create(
        FileCreateParams.builder()
                .file(Paths.get("document.pdf"))
                .purpose("extract")
                .build());


ExtractV2Job job = client.extract().create(
        ExtractCreateParams.builder()
                .extractV2JobCreate(
                        ExtractV2JobCreate.builder()
                                .fileInput(fileObj.id())
                                .configuration(
                                        ExtractConfiguration.builder()
                                                .dataSchema(dataSchema)
                                                .tier(ExtractConfiguration.Tier.AGENTIC)
                                                .citeSources(true)
                                                .confidenceScores(true)
                                                .build())
                                .build())
                .build());


// Poll for completion
while (!job.status().equals("COMPLETED")
        && !job.status().equals("FAILED")
        && !job.status().equals("CANCELLED")) {
    Thread.sleep(2000);
    job = client.extract().get(ExtractGetParams.builder().jobId(job.id()).build());
}
```

Terminal window

```
# Your extraction schema
DATA_SCHEMA='{"type": "object", "properties": {}}'


FILE_ID=$(llp files create --file document.pdf --purpose extract | jq -r '.id')


JOB_ID=$(llp extract create \
  --file-input "$FILE_ID" \
  --configuration "{\"data_schema\": $DATA_SCHEMA, \"tier\": \"agentic\", \"cite_sources\": true, \"confidence_scores\": true}" \
  | jq -r '.id')


# Poll for completion
while true; do
  STATUS=$(llp extract get --job-id "$JOB_ID" | jq -er '.status') || break
  case "$STATUS" in COMPLETED|FAILED|CANCELLED) break ;; esac
  sleep 2
done
```
