Blood Test Results Tracker — compare your lab results over time
Drop in the lab reports your doctor sends you — PDF, scan or phone photo. The text layer or OCR reads every test, value, unit and reference range, then you see each marker as a trend against the lab's own limits, a heatmap of every report, and a side-by-side comparison of any two dates. An optional AI model runs inside your browser to read lines OCR missed and to explain the trends in plain English. Not medical advice — discuss results with your doctor.
Overlay tests — position inside each reference range
Different units, one scale: 0% = lower limit, 100% = upper limit of the lab range on that date. Pick up to four tests.
Guide — from a pile of lab PDFs to one timeline
Drag the PDF your doctor or lab sent you onto the drop zone, or a scan or phone photo. Several files at once is fine; Ctrl+V pastes a screenshot.
A PDF with a text layer is read directly. A scan or photo goes through OCR in your browser — pick the report's language first for the best result.
Hover a row and the line lights up on the page. Yellow rows were corrected or guessed. Fix the date, untick what you don't want, then save.
The Dashboard shows every test against its range, Trends one test over the years, the Heatmap all reports at once and Compare two dates side by side.
Results stay on this device. Download a JSON backup now and then, or a CSV for a spreadsheet. Optional: let the in-browser AI explain the trends.
What each view answers
- question
- What is out of range in my latest report, and what moved?
- filters
- category · out of range now · near a limit · ever out of range · moved a lot
- question
- Is my LDL, TSH or ferritin slowly creeping towards a limit?
- compare with
- previous · first · average · any earlier date
- overlay
- up to four tests on one 0–100% range scale
- question
- Which tests keep coming back high or low over the years?
- colour by
- position in the range, or change since the previous report
- question
- What changed between this check-up and the last one — or the one before my treatment?
- sorted by
- category · biggest change · status changes
How to track and compare blood test results over time
A single blood test is a snapshot. What usually matters more is the direction: a cholesterol value that climbs a little every year, a ferritin that keeps sliding, a TSH that drifts towards the upper limit. Labs print every report on its own, often with slightly different reference ranges or units, so comparing them by hand means flipping between PDFs. This tracker puts every report on one timeline. For each test it keeps the value, the unit, the flag and the reference range printed by the lab on that date, and draws them together.
How do I read a reference range?
The range next to each result (for example 4,35 – 5,61, ≤ 190 or ≥ 40) is the interval in which most healthy people of a reference group fall. For most tests it is the middle 95% of that group, which means that 1 healthy person in 20 lands outside it on any one test. With 20 tests that were unrelated, the chance that at least one is flagged would be 1 − 0.9520 ≈ 64%. That is why a single value just outside the range is often not a problem on its own, and why the trend and the doctor's view of the whole picture matter.
Some ranges have only one side. A ≤ limit (LDL cholesterol, CRP, liver enzymes) is an upper limit; a ≥ limit (HDL cholesterol, vitamin B12, eGFR) is a lower limit. Lipid limits are often targets that depend on your cardiovascular risk rather than statistical ranges — the report may list several, and the tracker keeps the one on the result line.
Why every report keeps its own range
Ranges differ between labs, analysers and sometimes by age and sex, and a lab can change its method. A value of 4,21 mU/L TSH is "high" against 0,27 – 4,20 and normal against a range ending at 4,50. So the trend chart draws the range as a band that steps with each report, and every status (in range, near a limit, high, low) is judged against the range printed on that day. If a result has no range, the tracker borrows the most recent one for the same test and marks it with an asterisk.
Statuses and colours
| Status | Rule used by the tracker |
|---|---|
| in range | inside the lab range and not in its outer 10% |
| near limit | inside the range but within 10% of its width from a limit (for a one-sided range: above 90% of a ≤ limit, or below 110% of a ≥ limit) |
| high / low | outside the range |
| far high / far low | outside the range by more than 25% of its width |
Changes are coloured by whether the value moved further inside the range (green) or towards or past a limit (orange) — not by whether the number went up or down, because up is good for HDL and bad for LDL.
Comparing two results: when is a change real?
Two measurements of the same healthy person are never identical. Part of the difference is the lab (analytical variation), part is the body itself from day to day (within-person biological variation). Clinical chemists combine them in the reference change value: RCV = √2 × 1.96 × √(CVa² + CVi²). For a test with 3% analytical and 5% biological variation that is √2 × 1.96 × √(9 + 25) ≈ 16%: smaller changes between two results can be noise. The tracker shows every change as an absolute value, a percentage and a share of the reference range width, and the Trends tab fits a straight line through all values (with R²) so one noisy result weighs less than a steady drift. The trend card only mentions when a limit would be reached if the fit is reasonable (R² ≥ 0.5) and the limit is less than ten years away — it is a description of the past, not a prediction.
Things that change a result without anything being wrong
- Fasting: glucose and triglycerides are higher after a meal; compare fasting with fasting.
- Time of day: iron and cortisol follow a daily rhythm.
- Season: vitamin D is usually lowest at the end of winter.
- Exercise: hard training can raise CK and AST for days.
- Infection or inflammation: CRP and white cells rise, ferritin can rise too.
- A different lab or method: check whether the unit and range changed — the tracker's Compare tab shows both.
Units: mg/dL, mmol/L and the rest
When reports use different units, the tracker converts them so they land on one chart. Mass ↔ molar conversions use the molar mass of the substance; counts are converted by their power of ten. Some examples, as calculated by this page:
| Test | Conventional | SI | Factor |
|---|---|---|---|
| Glucose | 100 mg/dL | 5.55 mmol/L | ÷ 18.016 |
| Cholesterol (total, LDL, HDL) | 200 mg/dL | 5.17 mmol/L | ÷ 38.67 |
| Triglycerides | 150 mg/dL | 1.69 mmol/L | ÷ 88.57 |
| Creatinine | 0.86 mg/dL | 76 µmol/L | × 88.4 |
| Vitamin D (25-OH) | 30 ng/mL | 74.9 nmol/L | × 2.496 |
| Vitamin B12 | 301 ng/L | 222 pmol/L | ÷ 1.355 |
| HbA1c | 5.7 % | 39 mmol/mol | (% − 2.15) × 10.929 |
| White blood cells | 5,040 /µL | 5.04 × 10⁹/L | ÷ 1,000 |
Pick the unit per test in the Trends tab. Lipoprotein(a) is an exception: mg/dL and nmol/L measure different things and cannot be converted, so values in another unit are hidden from that chart and the page says so.
How the OCR and parser work
For a PDF with a text layer, pdf.js returns every word with its position; the tracker rebuilds the lines. A scanned page, a photo or a PDF without text goes through Tesseract OCR (tesseract.js 4.1.1) at roughly 300 dpi. Each line is then split into test name, flag (+, H, L, *), value (with < or >), unit and range, and the name is matched against a dictionary of about 80 common tests in Dutch, French, German and English — Erytrocyten, Leukocyten, IJzer, Foliumzuur, Urinezuur, Natrium, Kalium, Gamma-GT and so on. Neutrophils and the other white-cell types appear twice on most reports; the unit (% or a count) decides which one a line is.
OCR makes typical mistakes, and the parser repairs the common ones and marks them in yellow: ≥197 read as 2197, ≤ read as s or =, % read as 4, /µL read as /L, mmol read as mmo1, and a lost decimal comma (49 for 4,9) when the lab flags out-of-range values and this one was not flagged. Lines that look like results but match no known test can be added by hand or read by the AI. Reports with history columns (several dates side by side) are split into one report per date.
Tip for photos: shoot straight from above in good light, fill the frame with the table, and avoid shadows. A PDF from your lab or the patient portal is always better than a photo of a printout. HEIC photos from an iPhone can be converted first with the HEIC to JPG converter.
The optional AI: what it does and doesn't do
The AI explain tab loads a small open model (Qwen 2.5, Llama 3.2 or Phi 3.5) with WebLLM. It runs on your graphics card through WebGPU, so it needs a recent Chrome or Edge on a computer (or another browser with WebGPU), and downloads 0.9–2 GB once. It gets a compact table of your numbers — test, value, unit, lab range, status, previous values and trend — never your name or the scanned page. It can read lines the parser missed (it returns JSON that lands in the review table, marked yellow) and write a plain-language overview with questions to ask your doctor. Small models do make mistakes; the page never lets the AI change saved values on its own. copy as prompt gives you the same text to paste into another assistant — but then your numbers leave this device, which is your choice.
Privacy: where your data goes
Your reports are read in the browser and saved in this browser's IndexedDB; nothing is uploaded and there is no account. The page downloads only code and data files: pdf.js from cdnjs, tesseract.js from cdnjs and jsDelivr, the OCR language files from tessdata.projectnaptha.com, and — only if you load the AI — the WebLLM runtime from jsDelivr and the model weights from Hugging Face. Privacy-friendly Simple Analytics counts page views without cookies. Clearing your browser's site data deletes your results, so keep the JSON backup somewhere safe. Want to share a report with someone? Black out your name and national number first with the PII redaction tool — it runs in the browser too.
Not medical advice
This is a tool to organise and visualise your own results. It does not diagnose anything, and "in range" does not mean healthy any more than "high" means ill. Discuss your results — and any trend you notice here — with your GP or specialist.
More private tools
Ask questions about documents with the free browser-based AI, black out personal data with the PII redaction tool, or browse all free tools.