The Dangerous Part Is Not Extraction. It Is Trusting Everything.
Most n8n document workflows start with a clean demo: a PDF arrives, a document node extracts fields, and a spreadsheet or database node writes the result.
That is fine until the workflow starts handling real documents. A supplier invoice has a smudged total. A receipt uses a currency symbol the parser is not fully sure about. A contract date appears twice, once in the header and once in a clause. The workflow still writes a row because every extracted value was treated as equally trustworthy.
The fix is not to send every document to a human. That kills the value of automation.
The better pattern is to let high-confidence fields continue automatically and route only uncertain fields to a review branch. n8n is a good fit for this because the canvas can make the decision path explicit: extract, inspect confidence, branch, review, resume.
Model Review as a Branch, Not a Failure
Low confidence is not the same as an error.
An error means the workflow could not complete the step: unsupported file type, unreadable document, invalid schema, failed API call, missing binary data. Low confidence means the workflow completed extraction, but one or more values should not be trusted without a person checking them.
Those two cases deserve different paths in n8n:
- Error path: stop the workflow, notify an operator, and record why the document could not be processed.
- Review path: create a human task with the extracted value, confidence score, source context, and approve/correct actions.
If low-confidence fields go through the error path, operators get noisy failure alerts for documents that are actually recoverable. If errors go through the review path, reviewers waste time on documents the workflow cannot process anyway.
Keep the branch separate. It makes the workflow easier to operate.
Start With Field-Level Thresholds
One global threshold is usually too blunt.
An invoice number and a payment amount do not carry the same risk. A wrong invoice number might create a duplicate lookup problem. A wrong payment amount can trigger the wrong payment. A customer name might be acceptable at 0.88 confidence if it is used only for search, while a bank account number should require a much higher threshold.
Start with a simple threshold object in an n8n Code node after extraction:
{
"invoice_number": 0.90,
"vendor_name": 0.88,
"invoice_date": 0.90,
"due_date": 0.90,
"total_amount": 0.95,
"currency": 0.95
}The exact numbers are not universal. They should reflect the cost of getting the field wrong. For financial workflows, keep money fields conservative. For internal search or triage workflows, lower thresholds may be acceptable.
The goal is not perfect math. The goal is a visible policy the workflow can execute.
The n8n Workflow Shape
A practical review-routing workflow has seven stages:
- Intake receives a document from email, upload, webhook, or cloud storage.
- Validation checks file type, file size, sender, document class, and required metadata.
- Document Extraction returns typed fields with confidence scores and citations.
- A Code node compares each field against its threshold.
- An IF node branches on whether any required field needs review.
- The review branch creates a task in Slack, Linear, Airtable, Google Sheets, or an internal tool.
- The approved data resumes the output path: spreadsheet row, generated PDF, ERP update, or webhook.
The important part is where the IF node sits. It should come after extraction and before any irreversible downstream action.
Do not write low-confidence totals into accounting and then ask someone to check them. Do not generate a customer-facing PDF and then send a Slack message saying the data might be wrong. Review comes before the workflow commits the result.
Build a Review Payload, Not Just a Notification
A common mistake is to send a Slack message like this:
Invoice INV-2026-0417 has low confidence. Please check it.
That creates work, but it does not create a review system. The reviewer has to find the source document, find the field, understand what the workflow extracted, and decide where to enter the correction.
A better Slack message is specific enough to act on immediately:
Invoice review needed: invoice-2026-0417.pdf
Reason: 2 fields are below confidence threshold.
1. Total amount
Extracted: 1847.80
Confidence: 0.81
Required: 0.95
Source: "Total EUR 1,847.80"
2. Due date
Extracted: 2026-06-02
Confidence: 0.84
Required: 0.90
Source: "Payment due 02/06/2026"
Actions: Approve, Correct, Reject
If you build this with Slack Block Kit, the same message can include buttons for approval and correction. The button callback can call an n8n webhook with the field name, approved value, reviewer, and workflow run ID.
A useful review payload should include enough context for a human to act without digging through n8n execution logs:
{
"document_id": "invoice-2026-0417.pdf",
"workflow_run_id": "run_01JZ8K9M4C2E7X5P0NQ3A1B6D9",
"review_reason": "low_confidence_fields",
"fields": [
{
"name": "total_amount",
"label": "Total amount",
"extracted_value": "1847.80",
"confidence": 0.81,
"threshold": 0.95,
"citation": "Total EUR 1,847.80"
},
{
"name": "due_date",
"label": "Due date",
"extracted_value": "2026-06-02",
"confidence": 0.84,
"threshold": 0.90,
"citation": "Payment due 02/06/2026"
}
]
}This payload can become a Slack Block Kit message, an Airtable record, a Google Sheets row, a ticket, or a request to an internal review app. The storage target matters less than the shape of the task.
The task should tell the reviewer four things:
- Which document needs attention
- Which field is uncertain
- What value was extracted
- Where the value came from in the source document
If the reviewer has to reopen the PDF and hunt manually for every value, the automation did not save enough time.
Keep Approved Values Separate From Extracted Values
Review should not mutate the extraction result in place.
Keep two records:
- Extracted value: what the document extraction step returned, including confidence and citation.
- Approved value: what the workflow is allowed to send downstream after automatic acceptance or human review.
That distinction matters for auditability. If a reviewer changes 1847.80 to 1847.88, you need to know that the original extraction was different. If a client later asks why a payment amount changed, the workflow should show the extracted value, the corrected value, the reviewer, and the timestamp.
In n8n, this can be as simple as building a normalized object before the output branch:
{
"invoice_number": {
"extracted_value": "INV-2026-0417",
"approved_value": "INV-2026-0417",
"status": "auto_accepted"
},
"total_amount": {
"extracted_value": "1847.80",
"approved_value": "1847.88",
"status": "human_corrected",
"reviewed_by": "ap-ops@example.com"
}
}
Downstream nodes should read from approved_value, not directly from the raw extraction output.
That small boundary prevents a common class of workflow bugs: one node uses corrected data, while another node accidentally uses the original extracted value.
Decide How the Workflow Resumes
The review branch needs a return path.
If a reviewer approves a value, what happens next? The answer should be explicit before the workflow goes live.
There are three common patterns:
- Manual continuation: the reviewer updates a row or task, then clicks an n8n webhook URL to resume the workflow.
- Polling continuation: the workflow checks a review table on a schedule and continues approved records.
- External review app: an internal tool stores corrections and calls an n8n webhook when review is complete.
Manual continuation is the fastest to build. Polling works well for simple operations teams that already live in spreadsheets. An external review app is better when you need permissions, audit history, source document previews, or many reviewers.
Avoid leaving reviewed data in a dead-end table. If the workflow cannot resume automatically from review, operators will copy corrected values by hand into the downstream system. That is exactly the manual step the automation was supposed to remove.
Route the Document, the Field, or the Batch
Not every review path should have the same granularity.
Field-level review is best when most of the document is reliable and only one or two values are uncertain. An invoice with a clear vendor, invoice number, and date but an uncertain total should not force a full-document review.
Document-level review is better when the document class is ambiguous, the file is low quality, or the extraction has too many uncertain fields. At that point, asking a person to check each field separately creates more work than reviewing the document as a whole.
Batch-level review is useful when one upstream source sends many similar failures. If 30 supplier invoices all have low confidence on the same field, the problem may be a schema issue or a supplier format change. That should trigger process improvement, not 30 isolated tasks.
In n8n, this usually means your Code node should output both fields_requiring_review and a higher-level review_mode:
{
"review_mode": "field",
"fields_requiring_review": [
"total_amount",
"due_date"
],
"should_review_document": false,
"should_escalate_batch": false
}
The IF node can route on should_review_document, while a Switch node can route review_mode to different task templates.
Do Not Skip Validation Because Confidence Exists
Confidence scores are not validation rules.
A value can be high confidence and still violate business logic. An invoice total can be extracted clearly but not match the sum of line items. A due date can be read correctly but fall before the invoice date. A currency can be clear but not allowed for that vendor.
Run validation after extraction and before review routing:
- Required fields must exist.
- Currency must be allowed for the supplier or project.
- Dates must be in a plausible range.
- Totals should match line items where possible.
- Duplicate invoice numbers should be caught before payment.
Validation failures can use the same review branch, but they should be labeled differently from low confidence. A reviewer needs to know whether they are checking an uncertain extraction or resolving a business-rule conflict.
That distinction improves the task message and helps you measure where the workflow needs improvement.
What Iteration Layer Handles in This Pattern
Iteration Layer gives the n8n workflow the structured extraction output needed to make confidence routing possible.
The n8n community node exposes Document Extraction directly inside n8n. The extraction result includes typed values, confidence scores, citations, and source references. Those fields are what your IF node and review branch act on.
The same workflow can continue after review without switching vendors. Approved invoice data can feed Sheet Generation for an XLSX tracker or Document Generation for a PDF approval summary. That keeps the workflow under one credential, one credit pool, and one API style.
For the broader architecture, read Document Automation in n8n: Build the Workflow, Not Just the OCR Step. For the deeper confidence-score model, read Human in the Loop: Using Confidence Scores to Build Reliable Document Extraction. For concrete extract-to-output examples, start with the extract invoices to spreadsheet recipe or the invoice-to-PDF report recipe.
The Review Branch Checklist
Before shipping the workflow, check the branch against the failure modes that show up in production:
- Are thresholds defined per important field?
- Does the IF node run before any irreversible downstream write?
- Does the review task include extracted value, confidence, threshold, citation, and source document?
- Are extracted values and approved values stored separately?
- Can the workflow resume after review without manual copy-paste?
- Are validation failures labeled separately from low-confidence fields?
- Does the workflow track who approved or corrected each value?
- Is there an escalation path when a whole batch has the same review reason?
If those answers are clear, low confidence stops being a hidden risk. It becomes a normal branch in the workflow.
That is the point of human review in n8n: not to slow automation down, but to put human attention exactly where the workflow cannot safely decide on its own.