methodology · dictionary & mapping

LOINC is the international language of lab tests — and we're the bridge between it and your PDF.

Every lab test in the world has a LOINC code. "Glucose in serum, molar, mmol/L" = 14749-6, whether it was measured in Warsaw, Chicago, or Tokyo. LabCard's job is to map each of your results to the right code — because without it, Apple Health doesn't know what to plot on the same trend line.

The rule everything hinges on

Discovered empirically after testing many variants: Apple Health merges results into a single trend line only when the PAIR matches:

(LOINC code) + (display name) — both fields identical

If glucose from 2023 has the name "Glucose [Moles/volume] in Serum or Plasma", and glucose from 2024 gets "Glucose in blood" (with the same code!) — Apple Health will create two separate entries, each with a single point, no shared history.

That's why the display name in our dictionary isn't just a "label" but a product half-key. Chosen once, locked for years. Any spelling edit = broken trend history for existing users.

Three dictionary layers

Layer 1 — the seed dictionary (what you see today)

About 55 most common tests (CBC, biochemistry, lipid panel, thyroid, electrolytes, hormones, coagulation, cardiology). Manually curated. Uses LOINC LONG_COMMON_NAME as the canonical English display — no intermediate translation needed for English-speaking users.

Unit choice drives the code choice. Example: glucose. Molar variant = 14749-6 (mmol/L), mass variant = 2345-7 (mg/dL). Non-US labs often report mmol/L → we pick 14749-6. In the US, labs report mg/dL → 2345-7 is the right pick. This is why the same seed dictionary needs per-region tuning; today's seed is molar-oriented (Polish laboratory convention).

Layer 2 — build-time pipeline (PHP)

In the loinc-dictionary/ folder we have PHP scripts that take the official LOINC table (~90,000 concepts) and our "target list" of expected tests with OCR aliases, and produce a ready slownik_startowy.json. Run once every six months when LOINC releases a new version (February and August).

Matching score weights the English component, material (serum/blood), quantity type (molar/mass — SCnc picks the molar variant), and expected UCUM unit. Entries below the threshold go to do_weryfikacji.csv — resolved manually via search.loinc.org.

Layer 3 — canonical translations (per-region)

For English, the layer 3 is the LOINC LONG_COMMON_NAME field — no extra translation needed. For Polish, the Ministry of Health commissioned the Medical University of Łódź (with PTDL) to translate ~20,000 LOINC concepts. Completed July 2023, deposited in the official LOINC database — free (after registration), commercially usable. That's the target source for Polish display names.

A related project is SSIDL (Poland's Lab Diagnostics Standardization System, Medical University of Łódź) — will be open source with an HL7/FHIR API, providing direct local name → LOINC mappings. When it lands, integrating with it is our next big work.

OCR path — why only Diagnostyka for now

Polish lab PDFs share one technical quirk: they often use embedded subset fonts without ToUnicode maps. That means a standard text extractor (PDF.js, pdfplumber) gets (cid:53)(cid:24)… instead of "Hemoglobin". Digits extract fine, names don't.

Our workaround: render the page to an image and OCR it with Tesseract, like a human would. Advantage: works regardless of the font the lab embedded. Cost: slower (tens of seconds per page; first run loads a ~15 MB language model).

Right now the OCR pipeline is tested only on clean PDFs exported from the Polish Diagnostyka patient portal. Other labs (ALAB, Synevo, LabCorp, Quest) and scans — a universal OCR is a planned future phase. In the meantime, for any other source, use the AI parser path — it's document-layout-agnostic.

What if a test isn't in the dictionary?

Today: we skip it (in OCR and AI parser paths) or don't offer it in the tree (manual path). We deliberately don't allow entering a custom LOINC code by hand — because a user typo in the code or name would silently split the trend history in Apple Health.

If you're missing a test — let us know, we'll add it in the next dictionary release. Long-term, we'll pull the full catalog from layer 3 sources automatically.