Schema Care

Lab Report Data Extraction: A Step-by-Step Guide

By Schema CarePublished Updated

Lab report data extraction takes a received report file and turns it into an approved record in five steps: identify the document, read its text, find the fields, check them, and have a person approve anything uncertain. Each result keeps its test name, value, unit, range, flag and dates, plus a link back to the page it came from.

The lab report data extraction pipeline in five steps

The lab report data extraction pipeline is the fixed sequence a report passes through between arriving and being saved: intake, reading, field finding, checking and approval. Splitting the work this way means each step has one job, one output and one place to look when something goes wrong.

Here is the pipeline applied to one fictional comprehensive metabolic panel (CMP) report. The patient, lab, accession number and every value are invented for the example.

  1. Intake and identify. The file arrives by fax, upload or portal download. The step records where it came from, assigns a document ID and labels it as a lab report rather than a referral or a bill. Output: document_id = DOC-2026-10-0441, source = fax, document_type = lab_report, pages = 2.
  2. Read the page. If the PDF has a text layer, the step reads the text and the position of each word directly. If the pages are images, optical character recognition (OCR) produces the text and positions. Output: lines of text with page numbers and coordinates, such as "Glucose 92 mg/dL 70-99" at page 1, near the top third.
  3. Find the fields. A parser groups the text into header fields and result rows. Output: patient_name = "Avery Quinn (fictional)", accession = "A26-0310557", collected_at = 2026-10-05 08:10, reported_at = 2026-10-05 15:42, report_status = final, and one row per test: Glucose | 92 | mg/dL | 70-99 | (no flag), Sodium | 141 | mmol/L | 136-145, Potassium | 4.2 | mmol/L | 3.5-5.1, Creatinine | 0.88 | mg/dL | 0.57-1.00.
  4. Check the fields. Rules compare each row with what the report says about itself: is the unit one this test is reported in, is the value a number where a number is expected, does the printed flag agree with the printed range, are all the panel's rows present. Output: each field marked passed or failed, with a reason for each failure.
  5. Review and approve. Fields that failed a check or scored below the confidence threshold go to a person, who sees the value next to the page and approves or corrects it. Output: an approved record with approved_by, approved_at and any corrections logged.

Steps 2 and 3 are the ones people most often blur together. Reading text and finding fields are separate jobs with separate failure modes. The guide to lab report OCR and what it reads covers step 2, and the post on lab report parsers: templates, rules or models covers step 3.

Step 4 checks the data, not the patient. Rules here catch extraction errors such as a lost decimal point or a unit pasted onto the wrong row. The list of lab value checks that catch extraction errors, not clinical problems sets out the rules in detail.

Which lab results extraction fields are required, and which are optional?

The minimum record for one lab result, the smallest set of lab results extraction fields worth saving, is the patient identity, the test name, the result as printed, the unit when one is printed, the collection date and the performing lab. Without any one of those, the result cannot be filed, compared or traced.

Federal rules point at the same core: the CLIA test report rule lists the items every lab report must show, which the guide to lab report header fields and the CLIA report elements walks through. If a report is missing one of these, the gap is worth flagging to a person rather than filling.

A working split for one result looks like this:

FieldRequiredExample value (fictional)Why
patient_name, patient_dobYesAvery Quinn, 1979-06-22Files the result to the right person
test_name_printedYesCreatinineThe lab's own label, kept verbatim
value_textYes0.88The result exactly as printed
unit_printedYes when printedmg/dLA number without its unit is ambiguous
collected_atYes2026-10-05 08:10The date the result belongs to
performing_labYesExample Reference LabWhere the test was done
reported_atYes2026-10-05 15:42Tells versions of the report apart
reference_range_printedOptional, recommended0.57-1.00Kept for context, never recalculated
flag_printedOptional, recommended(none)Recorded as printed
accession_numberOptional, recommendedA26-0310557The lab's key for the specimen
ordering_providerOptionalDr. Sam Patel (fictional)Routes the result
test_codeOptional(added later)A standard code mapped after extraction
comment_textOptional(none)Notes printed under a row

Header fields are shared by every row on the report, so a single error there spreads. If the collection date is misread, every result on the report moves to the wrong day. Check header fields once per report and copy them onto the rows only after they pass.

Optional does not mean unimportant. The reference range and flag are optional only because a record can be filed without them. Most teams capture both every time, because a reader of the record expects to see what the lab printed.

Keeping each extracted lab value traceable to its source page

Traceability means every extracted lab value carries a pointer to where it was printed: the document, the page and the position on that page. A reviewer who doubts a value can open the original at that spot in one step, instead of paging through a fax to find the row.

The pointer is simple data. Store document_id, page and a bounding box (left, top, width, height) for each field. OCR engines already produce positions. The Tesseract command-line documentation shows its hOCR and TSV outputs carrying a bounding box and a confidence value for each word. PDFs with a text layer give positions too: the pdfplumber project README describes extract_words as returning "word-looking things and their bounding boxes."

For the fictional CMP, the potassium row might be stored as:

{
  "test_name_printed": "Potassium",
  "value_text": "4.2",
  "unit_printed": "mmol/L",
  "source": { "document_id": "DOC-2026-10-0441", "page": 1, "box": [72, 318, 410, 12] }
}

Keep the source link through every later step. Teams often keep it during extraction and then drop it when the data is copied into a results table or another system. The value then looks just as trustworthy as a hand-checked one, and nobody can tell which page it came from.

Traceability also covers changes. When a reviewer corrects a value, log the old value, the new one, who changed it and when. Schema Care works this way: each field it returns links to its place on the page, and each approval or correction is recorded with the reviewer and the time, which the human review section of the homepage walks through.

How do you extract data from lab reports that arrive as scans, PDFs and portal printouts?

To extract data from lab reports that arrive as scans, digital PDFs and portal printouts, you run the same five steps, but step 2 changes. A digital PDF already has text to read, a scan needs OCR first, and a portal printout may be either one, depending on how the patient saved it.

The practical difference is how much you can trust the reading step:

  • Digital PDFs from the lab. The text layer holds the exact characters the lab's system printed. Reading it avoids OCR misreads, though tables can still come out in the wrong order. The pdfplumber README notes that it "works best on machine-generated, rather than scanned, PDFs" and does not perform OCR.
  • Scans and faxes. Every character is recognized from an image, so small print, faint fax lines and skewed pages lower the quality of the text. The Tesseract guide to improving quality says the engine "works best on images which have a DPI of at least 300 dpi" and that line segmentation suffers when a page is too skewed.
  • Portal printouts. A patient who saves a portal page as a PDF usually gets a text layer. A patient who prints it and has it scanned gives you an image. Portal layouts also differ from the lab's own report and may leave out the lab's address or the collection time.

Your pipeline should detect which case it has rather than guess from the file name. The comparison of how to tell a scanned lab report from a digital one gives the tests to run.

One more source is not a PDF at all. Results can also travel between labs and care sites as structured electronic transactions; the NLM page on LOINC notes that HL7 named LOINC a preferred code set for laboratory test names in exactly those transactions. When such a feed exists for a lab, it skips reading entirely, and extraction is for the reports that arrive outside it.

When lab report data extraction should stop and ask a person

Lab report data extraction should stop and send a report to a person whenever a wrong value would be saved without anyone noticing: the patient cannot be matched with certainty, a check fails, a field scores below the threshold, or the report is a correction, a preliminary or a partial copy.

Cases that should never be saved automatically:

  • Patient identity in doubt. The name or date of birth does not match an existing record, or matches two. Saving a result to the wrong chart is the worst outcome of any extraction, and no confidence score should override a failed match.
  • A failed check. A unit that is not used for that test, a flag that contradicts the printed range, or a value in the wrong format. A failed check is a reason to look, not a finding about the patient.
  • Low confidence. Any field scored under the threshold the team chose. The setting of thresholds and the design of review queues are covered across the human review category.
  • Corrected or amended reports. The CLIA rule requires labs to issue corrected reports when errors are found and to keep both versions. A corrected report needs a person to link it to the original and confirm which values changed.
  • Preliminary reports. A preliminary result may be replaced. Hold it, or save it clearly marked, and expect a final version.
  • Missing pages or rows. A page count that does not match, or a panel with fewer rows than the same lab usually prints. The missing part often holds comments that qualify a result.
  • Handwriting. A handwritten value or a hand-marked correction on a printed report always deserves a human look.

A person reviewing these cases checks the data against the page. They do not judge whether a result is good or bad for the patient, which stays with the clinicians who receive it. For more on the reading step and its common failures, see the medical OCR basics category.

All posts in Lab Reports