Skip to navigation

Extraction

An Extract Fields step reads named, typed values out of text and up to four images. You list the fields you want. Each field comes back as a value of its declared type, or as null when the input doesn’t contain it. Every answer also carries the evidence a Flow needs to act on it: a confidence, the source span for text, and a calibrated range for an estimate.

An extraction model is not a chat model. There is no prompt, it generates no tokens, and it can’t return a value of the wrong type. Use it when a message, email, form, CSV, or photographed receipt holds values that a Record, a branch, or a later step needs.

Choose extraction, a judgment, or a prompt step

The three model-backed steps answer different kinds of question. Pick by the shape of the output you need:

You needUseWhat comes back
A value that the input states or implies: an order ID, a date, an amount, a list of items, a number rangeExtract Fields stepOne typed value per field, or null, with confidence and source spans
A decision among options you list: refund or repair, which queue, a rubric scoreA judgment through a Tool Call stepA probability, a selected label, or a score
Prose, open-ended JSON whose keys you can’t fix in advance, or work that needs toolsA prompt stepGenerated text or JSON

Extraction returns the value. A judgment makes the decision. A prompt step writes the words. The three compose in that order: extract the facts, judge what to do, then write the reply. Only the rows that need a large model reach one.

A prompt step with Response Format set to JSON can also pull fields out of text. It is slower, it is billed on output tokens, and it doesn’t tell you whether a value was in the input or how sure the model is. Use an extract step when the field list is fixed.

What an extraction model can do

One extract step can mix four kinds of field. Each kind answers a different question about the input.

  • Extract a value that is written down. A text field returns the exact characters from the input, with their position as a span. A date field returns an ISO date even when the input writes “Sept 28”.
  • Compute a value that is not written down. A number field with the instruction “Item price plus tax” returns the sum. A duration field returns the days between two dates. Keep each computation to one or two operations. Do longer arithmetic in a Run Code step.
  • Estimate a value with a range. An estimate field returns a point value and the 10th and 90th percentiles, for example a sale price from a table of comparable sales. The range is the signal: a wide range means thin evidence.
  • Forecast a series. A forecast field returns one estimate per future period, for a horizon of 1 to 64 periods, from the history in the input.

When the input doesn’t determine a field, the answer is null, not a guess. A list with no matches comes back as an empty array.

Worked example: read a support email

A customer sends this email to a Flow, which receives it as message:

message
Hi, order A-88412 arrived on Sept 28, 2026 with a cracked screen and a dented
corner. I paid $649.00 plus $52.10 tax. It's now Oct 9, 2026 and I'd like this
fixed or refunded. Thanks, Dana

The following extract step asks for six fields:

Extract step
{
"type": "extract",
"name": "Read the claim",
"config": {
"state": "{{message}}",
"fields": {
"order_id": { "type": "text", "instructions": "The order number" },
"delivered_on": { "type": "date" },
"amount_paid": {
"type": "number",
"decimals": 2,
"unit": "USD",
"instructions": "Total paid including tax"
},
"days_since_delivery": { "type": "duration", "unit": "days", "integer": true },
"damage": {
"type": "list",
"items": "text",
"instructions": "Each kind of damage described"
},
"tracking_number": { "type": "text" }
},
"outputVariable": "claim",
"errorHandling": { "onError": "fail" }
}
}

Each field shows a different behavior:

  • order_id and delivered_on are read from the text.
  • amount_paid is computed: 649.00 plus 52.10 is 701.10. The instruction asks for the computation.
  • days_since_delivery is computed from two dates in the email: 11 days.
  • damage is a list of two spans of the text.
  • tracking_number is null, because the email has none.

The step writes one object to claim. The following output shows its shape. The confidence and span values are illustrative:

claim
{
"model": "@cf/cloudflare/clairic",
"values": {
"order_id": "A-88412",
"delivered_on": "2026-09-28",
"amount_paid": 701.1,
"days_since_delivery": 11,
"damage": ["cracked screen", "dented corner"],
"tracking_number": null
},
"answers": {
"order_id": {
"type": "text",
"value": "A-88412",
"confidence": 0.99,
"pNull": 0.01,
"span": [10, 17]
},
"damage": {
"type": "list",
"value": ["cracked screen", "dented corner"],
"spans": [[50, 64], [71, 84]]
},
"tracking_number": { "type": "text", "value": null, "pNull": 0.99 }
},
"usage": { "inputTokens": 180, "outputTokens": 0, "passes": 1 },
"truncated": false
}

The output has two halves:

  • values is a flat map with one entry per field. It is the object that a Record stores.
  • answers keeps the evidence for each field. A branch reads it. The sample shows three of the six answers.

Route on null and confidence, then store

Decide what to do with uncertain rows before you write anything. Store a claim only when its key fields are present and confident. Send the others to a person.

The following steps follow the extract step. The conditional sends a claim to review when its order ID is missing or its amount is not confident. Otherwise, the Flow stores the claim:

Conditional and Upsert Record steps
{
"type": "conditional",
"name": "Route uncertain claims",
"config": {
"condition": "claim.values.order_id === null || !(claim.answers.amount_paid.confidence >= 0.9)",
"trueSteps": [
{
"type": "send-stream",
"name": "Needs review",
"config": { "message": "A person will review this claim." }
}
],
"falseSteps": [
{
"type": "upsert-record",
"name": "Store the claim",
"config": {
"recordType": "claim",
"recordName": "{{claim.values.order_id}}",
"sourceVariable": "claim.values",
"outputVariable": "stored"
}
}
]
}
}

Four details in this pattern matter:

  • Write conditions with bare variable paths, such as claim.answers.tracking_number.value === null. A {{...}} reference is replaced with text before the condition runs, so it can’t compare against null.
  • Write !(confidence >= 0.9), not confidence < 0.9. An answer can omit confidence. The negated form sends a missing confidence to review. The < 0.9 form lets it through.
  • Set sourceVariable to the path claim.values, not {{claim.values}}. Upsert Record reads the source as a variable path and doesn’t substitute templates. Validation reports a template there as UPSERT_SOURCE_TEMPLATE.
  • Key the Record on a value you routed on. Without a recordName, each run creates a Record. A null order ID would give the Record an unusable name, which is why the condition checks it first.

The default Merge strategy writes every top-level key in values, including null ones. A null therefore replaces a value that an earlier run stored. To keep stored values, add a Run Code step that drops the null entries, and point sourceVariable at its output. For more about merge strategies, see Using record steps.

To choose between refund and repair, add a judgment in the store branch and pass it the extracted values as its state. Then add a prompt step that writes the reply from the decision and the facts.

The 0.9 threshold is a placeholder. Measure confidence against labeled examples from your own data before a threshold acts without review. The action policy stays in the Flow, not in the model.

Add an extract step in the dashboard

To add an extract step, follow these steps:

  1. Open the Flow and add an Extract Fields step.
  2. In Text to read, reference the text, for example {{message}}. Text answers are spans of this text, so pass the whole message or document, not a summary.
  3. Under Fields, click Add field for each field. Enter a name, pick a type, and add instructions when the name alone is ambiguous or you want a computation.
  4. In Writes to, enter the output variable. Later steps read the result from it.
  5. Optional: Pick a different model in the step settings, or expand Images, reference date to add images or set the date that “today” means.

The field name is sent to the model, so a descriptive name such as order_id is a complete field. A one- or two-character name with no instructions tells the model nothing, and validation recommends a better one.

Field types

The following table lists each type, what it returns, and the options it accepts:

TypeReturnsOptions
textA span of the input text, with character offsets in spanNone
numberA read or computed numberinteger, decimals (0 to 6), unit
date, time, datetimeAn ISO valueNone
durationA length of timeunit (seconds, minutes, hours, days, weeks, months, or years), integer, decimals
listThe matching items in input order, with spans for text itemsitems (text, number, or date; required), decimals
estimateA distribution: value, mean, median, p10, and p90min and max (required), step, scale (linear or log), unit, decimals
forecastOne estimate per future period, in stepsmin, max, horizon (1 to 64), and interval (all required), step, scale, unit, decimals

Every field also accepts instructions and nullThreshold. nullThreshold is a number greater than 0 and at most 1, with a default of 0.5. A scalar whose pNull is above it comes back as null.

Validation rejects an option that a type doesn’t take, such as decimals on a text field.

Estimate and forecast options

An estimate needs evidence in the input text, such as comparable sales or past values. Its range can be too narrow on data unlike what the model has seen.

  • min and max bound the answer. They are numbers, or ISO dates for a date estimate.
  • step is the resolution: a positive number, a number of days for a date estimate, or month or year.
  • scale: "log" suits values that span orders of magnitude, such as prices.
  • interval is the forecast’s period: step, minute, hour, day, week, month, quarter, or year.

The following fields ask for an estimate and a six-month forecast:

Estimate and forecast fields
{
"sale_price": {
"type": "estimate",
"min": 50000,
"max": 2000000,
"scale": "log",
"step": 1000,
"unit": "USD",
"instructions": "Likely sale price of the subject property"
},
"monthly_orders": {
"type": "forecast",
"min": 0,
"max": 100000,
"horizon": 6,
"interval": "month",
"instructions": "Orders per month, from the monthly history in the text"
}
}

In values, an estimate is its point value, and a forecast is an array with one point value per period. A forecast extends the history in the text. It is not a time-series model, so check its ranges against outcomes before a Flow acts on them.

Configuration reference

The following table lists the fields of an extract step’s config:

FieldRequiredDescription
stateYesA template for the text to read, for example {{message}}.
fieldsYesA map of field name to field spec, with at least one field. A name starts with a letter or _, uses letters, digits, _, ., or -, and has at most 64 characters.
outputVariableYesThe variable that receives the result.
modelNoAn extraction model ID. Defaults to @cf/cloudflare/clairic.
imagesNoUp to four images. Each is a data URL, or a {{variable}} that resolves to a data URL or a { "contentType": "...", "base64": "..." } object.
referenceDateNoAn ISO date that anchors dates written without a year. Accepts templates. Defaults to the date that the run started.
errorHandlingNo{ "onError": "fail" } or { "onError": "continue" }.
defaultValueNoThe value written to outputVariable when the step continues after an error.

The output object has the following fields:

FieldDescription
modelThe model that answered.
valuesOne entry per field: the value, null, an array for a list, the point value for an estimate, or an array of point values for a forecast.
answersOne answer per field. Each has type and value. Depending on the type, it also has confidence, pNull, span or spans, the estimate fields (mean, median, p10, p90, pBelow, pAbove), or steps for a forecast.
usageinputTokens, outputTokens (always 0), and passes.
truncatedtrue when the text did not fit the model’s context and was cut.

Images

An extract step reads images together with the text. The model accepts PNG, JPEG, and WebP.

  • Pass at most four images. Each can be 4 MiB decoded, and all images together 8 MiB.
  • Pass each image as a data URL, or as a variable that holds a data URL or a { contentType, base64 } object.
  • The step refuses remote image URLs and asset IDs. To read an image from a URL, fetch it in an earlier step and pass the data.

Models, limits, and cost

GET /v1/extraction-models lists the supported extraction models, their limits, their pricing, and their credential requirements. The MCP tool list_extraction_models takes no arguments and returns the same list. Code Mode exposes it as runtype.listExtractionModels(). The catalog describes supported models. It doesn’t check whether your account can pay for a call.

The following table lists the facts for the default model:

Fact@cf/cloudflare/clairic
RouteCloudflare Workers AI, through the Runtype platform binding
Context65,536 tokens. Each pass holds 8,192 tokens.
ImagesFour, 4 MiB each, 8 MiB in total
Listed price$0.10 per million input tokens. No output charge.
CredentialsRuntype platform funding only. You can’t use your own provider key.

Fields that don’t fit beside the text in one pass are split across parallel passes, and every pass reads the whole text. usage.passes reports how many ran. If the text is longer than the context, the step cuts it, sets truncated to true, and still succeeds with a warning on the step result.

Runtype bills a platform-funded extraction at the model’s listed rate plus the platform margin. If your account’s platform funding is blocked or exhausted, the step fails with a spend-limit error, and the step’s errorHandling applies. An organization that requires strict zero data retention can’t use this route, and its extract steps fail.

Clairic is a Cloudflare preview model. Cloudflare reports that it returns the same answers for the same input. Test it on your own documents before a Flow depends on it.

Design rules

Follow these rules to get reliable answers:

  • Put the whole document in state. Text answers are spans of that string. A summary from a prompt step loses the source and the spans.
  • Say what to compute. Add instructions such as “Item price plus tax” for a value that isn’t written down.
  • Compute in code beyond one or two operations. A sum of two amounts or a day count is reliable. A total across many rows is not. Extract the rows as a list and add them in a Run Code step.
  • Set referenceDate when “today” matters. Relative dates and dates without a year are anchored on it. It defaults to the run’s start date.
  • Don’t ask the model to invent missing values. Branch on null instead.
  • Give estimates evidence. Include comparable items or history in the text.

Errors and validation

Saving a Flow reports these codes for an extract step:

CodeLevelMeaning
EXTRACT_FIELDS_INVALIDErrorA field’s name, type, or options are wrong. Validation reports one message for each broken rule.
EXTRACT_MODEL_UNKNOWNErrormodel is not an extraction model. A chat or decision model can’t run the step.
EXTRACT_IMAGES_TOO_MANYErrorThe step lists more images than the model reads.
EXTRACT_STATE_EMPTYWarningstate is empty and the step has no images.
EXTRACT_FIELD_UNDESCRIBEDRecommendationA field has a one- or two-character name and no instructions.

At run time, the step treats two kinds of failure differently:

  • Input problems are an empty resolved text with no images, an image that is too large or not a data URL, an unknown model, or a malformed field map. With errorHandling unset, the step reports a failure and writes no output. With continue, it writes defaultValue. With fail, it stops the Flow.
  • Model and funding failures follow errorHandling. With errorHandling unset, the step continues and writes defaultValue, or null when you set none.

A later step that reads claim.values fails when claim is null. Set errorHandling to { "onError": "fail" } on the extract step, or check for null before you read the output.

Self-hosted runtimes

A self-hosted @runtypelabs/runtime answers the step through its ExtractionProvider. The key mode picks the provider:

  • own: The runtime calls the Workers AI AI binding of your deployment.
  • platform: The runtime calls POST /v1/runtime/extractions with a Self-hosted Runtime key. Runtype funds and bills the call.
  • hybrid: The runtime tries the AI binding first. It calls Runtype only when no binding is configured.

For setup, see Self-hosting.

Next steps

Continue with one of these guides: