HL7 & FHIR Lab Messages
Paste a laboratory message to see what every field means and what is wrong with it, or make realistic mock messages for testing. HL7 v2 (2.3 to 2.5.1) and FHIR R4.
Private by design. Everything happens in your browser. Messages you paste or open are not uploaded, saved or sent anywhere, and they are gone when you reload or leave the page. Real messages contain patient details, so follow your organisation’s information governance rules, and use Make a safe copy before you share one.
Pasting reads the message straight away. Ctrl+Enter (⌘+Enter on a Mac) analyses again after you edit it. Several messages, batches and MLLP framing are all fine.
Make realistic laboratory messages for testing an interface, a parser or a training system. Every patient, number and clinician is made up. NHS numbers start 999, a range kept for testing that is never given to real patients; postcodes start ZZ99 and the hospital and laboratory are fictional.
A collection is a set of resources to read. A transaction can be posted to a FHIR test server to store everything at once.
More settings
Reference ranges are typical UK adult ranges, and the HH and LL flags use example alert limits: every laboratory sets its own. Mock messages are for testing and teaching only; never load them into a live patient system.
Most UK laboratory systems send results to GP systems and hospital records as HL7 version 2 messages. Newer national services use FHIR. Both carry the same things: who the patient is, what was requested, and each result with its units, range and flag.
HL7 v2 in one minute
An HL7 v2 message is plain text. Each line is a segment, named by its first three letters and ended by a carriage return (CR). Segments are split into fields by |, fields into components by ^, repeated values by ~ and sub-components by &. The \ starts an escape, such as \F\ for a | inside text or \.br\ for a line break.
MSH|^~\&|LIMS|PATHOLOGY|EPR|HOSPITAL|20261102101500+0000||ORU^R01^ORU_R01|OC1234|T|2.5.1 PID|1||9990000018^^^NHS^NH~RX1234567^^^HOSP^MR||TEST^PATIENT^^^MR||19700101|M OBR|1|PL123^EPR|26H000123^LIMS|FBC^Full blood count^L|||20261102083000+0000|...|HM|F OBX|1|NM|718-7^Haemoglobin^LN||142|g/L|130-180|||F OBX|2|NM|777-3^Platelet count^LN||95|10*9/L|150-400|L||F
Fields are counted from the segment name, so OBX-5 is the fifth field of OBX (the value). MSH is the exception: the first | is itself MSH-1, so MSH-9 (the message type) is the eighth piece of text after “MSH”.
The shape of a results message (ORU^R01)
MSH message header: who, to whom, when, which version PID patient (NHS number, hospital number, name, date of birth, sex) PD1 registered GP (optional) PV1 visit: inpatient, outpatient or emergency; ward or clinic ORC common order: RE = results follow; order numbers OBR the request: test set, collection time, result status NTE comments on the request OBX one result: code, value, units, range, flag, status NTE comments on that result SPM the specimen (version 2.5 and later)
A message can carry several OBRs, each with its own OBX results. An order message (ORM^O01, or OML^O21 from version 2.5) has the same shape without the results. The receiving system replies with an ACK: MSA|AA|<message ID> when it accepted the message, AE when it found an error, AR when it rejected it.
Flags and statuses you will see
| Field | Code | Meaning |
|---|---|---|
| OBX-8 flag | L, H | Below or above the reference range. |
| OBX-8 flag | LL, HH | Beyond the laboratory’s alert (critical) limits: usually telephoned. |
| OBX-8 flag | A, AA, N | Abnormal, very abnormal, normal (often used for coded results). |
| OBX-8 flag | <, > | Off the analyser’s measuring range. |
| OBX-11 status | F, P, C | Final, preliminary, corrected (replaces a final result). |
| OBX-11 status | X, W, D | Cannot be obtained; sent for the wrong patient; delete. |
| OBR-25 status | F, P, A, I | Final; preliminary; some results available; specimen received, no results yet. |
| OBX-2 type | NM, SN, ST, FT, CWE | Number; structured number such as >^90; text; formatted text; coded value. |
A value outside its range with no flag is a common interface fault: the receiving system will not highlight it. This tool checks every numeric result against its own range.
FHIR in one minute
FHIR (Fast Healthcare Interoperability Resources) sends the same information as resources, usually in JSON. A laboratory report is a DiagnosticReport that points to one Observation per result, the Patient, the Specimen and the ServiceRequest it answers. They travel together in a Bundle, where each entry has a fullUrl that the others refer to.
{ "resourceType": "Observation", "status": "final",
"code": { "coding": [{ "system": "http://loinc.org", "code": "718-7", "display": "Haemoglobin" }] },
"subject": { "reference": "urn:uuid:…patient…" },
"effectiveDateTime": "2026-11-02T08:30:00+00:00",
"valueQuantity": { "value": 142, "unit": "g/L", "system": "http://unitsofmeasure.org", "code": "g/L" },
"interpretation": [{ "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation", "code": "N" }] }],
"referenceRange": [{ "low": { "value": 130, "unit": "g/L" }, "high": { "value": 180, "unit": "g/L" } }] }
In England, UK Core profiles say how FHIR is used here; the NHS number goes in Patient.identifier with the system https://fhir.nhs.uk/Id/nhs-number. Units should be UCUM codes (for example 10*9/L, umol/L, mL/min/{1.73_m2}).
HL7 v2 and FHIR side by side
| HL7 v2 | FHIR R4 |
|---|---|
| PID-3 identifiers (NH, MR) | Patient.identifier |
| PID-5 name, PID-7 birth date, PID-8 sex | Patient.name, birthDate, gender |
| ORC/OBR-2 placer order number | ServiceRequest.identifier |
| OBR-4 test set | DiagnosticReport.code |
| OBR-7 collection time | Specimen.collection.collectedDateTime and Observation.effectiveDateTime |
| OBR-22 reported time | DiagnosticReport.issued, Observation.issued |
| OBR-25 result status | DiagnosticReport.status |
| OBX-3 test code | Observation.code |
| OBX-5 value and OBX-6 units | Observation.valueQuantity (or valueString, valueCodeableConcept) |
| OBX-7 reference range | Observation.referenceRange |
| OBX-8 abnormal flag | Observation.interpretation |
| OBX-11 result status | Observation.status |
| NTE comment | Observation.note, DiagnosticReport.conclusion |
| SPM specimen | Specimen |
Common faults this tool looks for
- Lines that do not start with a segment name: often text that has wrapped in an email.
- Required fields left empty, such as the message ID (MSH-10), the patient identifiers (PID-3) or the result status (OBX-11).
- Dates that do not exist, missing time zones, and times in the wrong order (reported before collected).
- Numbers with units missing, decimal commas, or “<5” sent as a plain number instead of a structured number.
- Results outside their range with no flag, or flagged the wrong way.
- Codes that are not in the HL7 tables, such as HIGH instead of H.
- NHS numbers that fail the check digit, and identifiers with no type.
- In FHIR: missing statuses and codes, references to resources that are not in the bundle, numbers in quotes, units without UCUM codes.
The tool checks against HL7 version 2.5.1 field definitions and notes where older versions differ. It does not replace testing against the interface specification agreed between your systems.
Patient data and this tool
Real messages hold patient-identifiable information. This page never sends what you paste anywhere: it has no upload and it does not save messages, so they are gone when you leave. Spelling checkers are switched off in the box, because some browsers send text to an online spelling service. Hide patient details on screen covers names, numbers, dates of birth and addresses while you work. Make a safe copy replaces them with made-up values (keeping the results and times) so that you can share a message to report a fault; check comments and free text yourself, or remove them.
References
- Health Level Seven International. HL7 Version 2.5.1 messaging standard: chapter 2 (control), chapter 3 (patient administration), chapter 4 (order entry) and chapter 7 (observation reporting), with the HL7 tables cited by number in the tool.
- Health Level Seven International. FHIR Release 4 (4.0.1): DiagnosticReport, Observation, Specimen, ServiceRequest, Patient and Bundle resources; ObservationInterpretation code system.
- HL7 UK. UK Core FHIR implementation guide (UKCore-Patient and the NHS number identifier).
- NHS England. The NHS number: format and modulus 11 check digit; the 999 range used for test patients.
- Regenstrief Institute. LOINC codes used in the mock messages. The Unified Code for Units of Measure (UCUM).
- Pathology Harmony. Harmonised adult reference ranges (used for many of the example ranges).