Skip to content
AF
Fitness APIs

Getting Wearable Data into Health Records with FHIR Observation

Last verified October 17, 2026 · 7 min read

Sources checked (4) · October 17, 2026
In FHIR R4 a wearable reading goes into an Observation resource, which must carry a status and a code, and HL7's specification says implementations that record vital signs as structured data SHALL conform to the FHIR Vital Signs profile. That profile requires a status, a 'vital-signs' category, a LOINC code for what was measured, a patient, a time, and a numeric value with a UCUM unit, or a reason when there is no value. Heart rate, for example, is LOINC 8867-4 in /min, and blood pressure is one panel observation, LOINC 85354-9, with systolic and diastolic components. HL7's R4 pages note that FHIR 5.0.0 supersedes R4, so confirm the version and profiles the receiving system expects.

If a provider or health system wants wearable readings in its record and accepts FHIR, each reading becomes an Observation resource. This page covers what the FHIR R4 specification itself requires of that resource and of its Vital Signs profile, read from HL7's Observation and Vital Signs profile pages on October 17, 2026. R4 is version 4.0.1, a "Mixed Normative and STU" release, and HL7's R4 pages say "The current version which supercedes this version is 5.0.0", so ask the receiving system which version and which profiles it accepts.

Why Observation#

HL7 defines Observation as "Measurements and simple assertions made about a patient, device or other subject." Its listed uses include "Vital signs such as body weight, blood pressure, and temperature" and "Device measurements such as EKG data or Pulse Oximetry data". The Vital Signs profile names the wearable case directly: a single vocabulary is needed "Particularly with the use of wearables by patients where they want to/need to share information from those devices."

In R4 the Observation resource is "Normative (from v4.0.0)", while the Vital Signs profile page gives its standards status as Informative.

What every Observation must carry#

HL7 notes that "At its simplest, a resource instance can consist of only a code and a value, and status flag." In R4's element table, status and code are the two mandatory elements:

ElementCardinalityWhat it holds
status1..1registered, preliminary, final, amended and further codes, from a required code list
code1..1What was measured; LOINC is the example binding
subject0..1A Patient, Group, Device or Location
effective[x]0..1The clinically relevant time or period, as a dateTime, Period, Timing or instant
issued0..1When this version was made available
value[x]0..1The result, as a Quantity, CodeableConcept, string, boolean, integer, Range, Ratio, SampledData, time, dateTime or Period
dataAbsentReason0..1Why the result is missing
device0..1The measuring Device or DeviceMetric
component0..*Results read together, such as systolic and diastolic pressure
derivedFrom and hasMember0..*The observations a value was made from, or the members a panel groups

Two rules apply to every Observation. Rule obs-6 says "dataAbsentReason SHALL only be present if Observation.value[x] is not present", and rule obs-7 says that if Observation.code matches a component's code, the value for that code "SHALL NOT be present".

For timing, effectiveDateTime or effectivePeriod "is the time that the observation is most relevant as an observation of the subject", which for a person is "the physiologically relevant time of the observation"; for an observation obtained directly from the subject, such as blood pressure, it is the start and end of the observation process. In our reading, that is when the watch or cuff measured, not when your server received the reading; issued is the element for when a version was made available.

The Vital Signs profile#

The Observation page says that if implementations use the resource to express the profile's concepts as structured data, "they SHALL conform to the following profiles", naming Vital signs. The profile page puts it this way: "When a FHIR implementation supports any of the vital signs listed below, the implementation SHALL conform to this profile for the vital sign observation." Each vital-signs Observation must have:

  • a status;
  • a category code of 'vital-signs';
  • a LOINC code for what is measured, which the profile calls the "magic value";
  • a patient;
  • a time indicating when the measurement was taken;
  • a numeric result value with a standard UCUM unit or, when there is no numeric result, a reason.

The profile's minimum set of codes and units:

Vital signLOINC codeUCUM unit
Vital signs panel85353-1none; member observations linked with hasMember
Respiratory rate9279-1/min
Heart rate8867-4/min
Oxygen saturation2708-6%
Body temperature8310-5Cel or [degF]
Body height8302-2cm or [in_i]
Head circumference9843-4cm or [in_i]
Body weight29463-7g, kg or [lb_av]
Body mass index39156-5kg/m2
Blood pressure panel85354-9none; systolic and diastolic go in components
Systolic blood pressure8480-6mm[Hg]
Diastolic blood pressure8462-4mm[Hg]

For blood pressure, "you must have both a systolic and a diastolic component, though one or both may have dataAbsentReason instead of a value." The bindings are extensible: if you also record a more specific code, "implementers must support both the values (LOINC) listed below and the translated code". The table is a floor, and the profile says "The table above is the minimum set, additional vital signs are allowed."

How a server is searched#

The profile's quick start lists searches servers must support: a patient's vital signs by category, by category and date, and by one or more of the LOINC codes, for example GET [base]/Observation?patient=[id]&category=vital-signs. Blood pressure has a trap: the code parameter "searches only Observation.code", so searching for the systolic or diastolic component code "will not return the resource", and the profile points to the combo-code search parameter to search both. The profile also has the server ensure "that every API request includes a valid Authorization token" and reject unauthorized requests "by returning an HTTP 401 Unauthorized response code".

Mapping a wearable reading (our worked example)#

From the wearableInto the ObservationSpec basis
The metric type, such as heart ratecode with LOINC 8867-4Vital Signs code table
The number and its unitvalueQuantity with the UCUM unit /minVital Signs mandatory elements
When the device measuredeffectiveDateTime, or effectivePeriod for an intervalObservation timing note
When your system made it availableissuedObservation element table
The usersubject, a PatientVital Signs mandatory elements
The watch or sensordevice, a Device or DeviceMetricObservation element table
A missed readingdataAbsentReason, with no valueRule obs-6 and the profile's reason rule
A waveform, such as ECG samplesvalueSampledDataObservation value types
A metric computed from other readingsderivedFrom, pointing at the source observationsObservation grouping notes

A heart-rate reading's code and value, in the shape HL7's own examples use for LOINC codes and UCUM quantities:

"code": {
  "coding": [{ "system": "http://loinc.org", "code": "8867-4" }]
},
"valueQuantity": {
  "value": 72,
  "unit": "/min",
  "system": "http://unitsofmeasure.org",
  "code": "/min"
}

The full resource also needs its status, the vital-signs category, the patient and the time.

Metrics outside the vital-signs table, such as step counts, are still Observations, but R4 binds Observation.code to LOINC only as an example, so the receiving system's own profile decides which code it expects. HL7's grouping notes add that "Profiling will normally be necessary for implementation." HL7 also publishes a Personal Health Device FHIR implementation guide, version 2.0.0 (STU 2), based on R4; we have not reviewed its contents.

Before you build (our recommendation)#

  • Ask for the contract. Find out which FHIR version the receiving system accepts and which Observation profiles it enforces; the base resource and the Vital Signs profile are the floor, not the whole agreement.
  • Keep independent readings separate. HL7 says a body mass index Observation "should not contain components for height and weight because they are clinically relevant observations on their own", and asks for separate Observations linked with derivedFrom instead.
  • Keep your raw data apart from the FHIR projection, so a profile change means re-mapping rather than re-collecting; see normalizing wearable data across providers.
  • Expect HIPAA when you send data for a provider. The FTC's health-app tool says a developer operating an app on behalf of a HIPAA covered entity likely is a business associate; see does my fitness app need HIPAA. For the opposite direction, reading clinical records on the phone, see HealthKit clinical records and Health Connect medical records.

Frequently asked questions

Which FHIR resource carries readings from a wearable?
Observation. HL7 defines it as measurements and simple assertions made about a patient, device or other subject, lists device measurements such as EKG and pulse oximetry data among its uses, and its Vital Signs profile names patients sharing data from wearables as a reason a common vocabulary is needed. In R4, status and code are the only mandatory elements.
What LOINC code and unit does FHIR use for heart rate?
The R4 Vital Signs profile uses LOINC 8867-4 with the UCUM unit /min. The profile adds that 8887-2, heart rate device type, may be included as an additional observation. The Observation also needs a status, the vital-signs category, the patient and the time the measurement was taken.
How does FHIR represent a home blood pressure reading?
As one blood pressure panel Observation, LOINC 85354-9, with no top-level value and systolic (8480-6) and diastolic (8462-4) components in mm[Hg]. The profile requires both components, though either may carry a dataAbsentReason instead of a value. A search by the component codes alone will not return it; the profile points to the combo-code parameter.
How should a missing wearable reading be sent in FHIR?
Leave the value out and fill dataAbsentReason. Rule obs-6 says dataAbsentReason SHALL only be present when Observation.value[x] is not present, and the Vital Signs profile says that if there is no numeric result you have to supply a reason. When the reading failed with an error, HL7's Observation notes say to use dataAbsentReason with the value error or NaN.
Should a wearable integration send FHIR R4 or R5?
Whichever the receiving system accepts. HL7's R4 pages say the current version, 5.0.0, supersedes R4, while R4 stays at its permanent address. The Observation resource and the Vital Signs profile described here are R4's, so confirm the version and any further profiles with the system you send to before you build.

All 84 questions in Fitness APIs →

Keep reading

Elsewhere on the site

Pages that share this one’s concepts and sources, from other sections.

Next steps

Was this page useful?

Independent comparison, last reviewed October 17, 2026. Pricing, rate limits, and feature availability change often — confirm current details in each provider’s official documentation before you commit. Product and company names are trademarks of their respective owners; AIFitnessAPI is not affiliated with, endorsed by, or sponsored by any product listed here.

← All fitness apis · by AIFitnessAPI