On this page

In on our previous guide about [creating diagnostic services catalog](/content/docs/careplans/diagnostic-catalog/index.html), we described the importance of the [`ObservationDefinition`](/content/docs/api/fhir/resources/observationdefinition/index.html) resource for storing metadata about the [`Observations`](/content/docs/api/fhir/resources/observation/index.html) produced by the test. This metadata is not just for ensuring data correctness, but also a key component in assisting providers with data interpretation.

A core part of interpreting results of this metadata is the definition of **reference ranges**, sets of [`Observation`](/content/docs/api/fhir/resources/observation/index.html) values that share a **diagnostic interpretation**. While medical directors will always have the final say on any interpretation, incorporating reference ranges into your catalog can streamline their workflow.

In this guide, we'll take a closer look at how administrators can use the [`ObservationDefinition`](/content/docs/api/fhir/resources/observationdefinition/index.html) resource to define these ranges of interest. We'll cover the following key areas:

1. Defining a reference range.
2. Establishing age and gender-dependent ranges.
3. Understanding the types of ranges that FHIR supports.
4. Editing reference ranges in the medplum UI.
5. Defining ranges for non-numerical Observations.

## Defining a Reference Range  [​](/content/docs/careplans/reference-ranges#defining-a-reference-range "Direct link to Defining a Reference Range"/index.html)

A reference range is defined using the `ObservationDefinition.qualifiedInterval` element. This is an array field, which allows administrators to define multiple ranges of interest for a single [`Observation`](/content/docs/api/fhir/resources/observation/index.html).

A range is defined by the following properties:

| **Element** | Description | Example |
| --- | --- | --- |
| `qualifiedInterval.range.low` | Lower bound for the reference range, inclusive. <br>(Empty value denotes no lower bound) | 10 mg/dL |
| `qualifiedInterval.range.high` | Upper bound for the reference range, inclusive. <br>(Empty value denotes no upper bound) | 100 mg/dL |
| `qualifiedInterval.range.condition` | How to interpret observation values in this interval | "High" |

Example: 10 - 100 mg/dL

```ts
{

resourceType: 'ObservationDefinition',

code: {

coding: [\
\
      {\
\
        system: LOINC,\
\
        code: '38483-4',\
\
        display: 'Creatinine [Mass/volume] in Blood',\
\
      },\
\
    ],

},

qualifiedInterval: [\
\
    {\
\
      condition: 'Normal',\
\
      range: {\
\
        low: {\
\
          value: 10,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
        },\
\
        high: {\
\
          value: 100,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
        },\
\
      },\
\
    },\
\
  ],

}
```

Example: Less or equal to than 5 mg/dL

```ts
{

resourceType: 'ObservationDefinition',

code: {

coding: [\
\
      {\
\
        system: LOINC,\
\
        code: '38483-4',\
\
        display: 'Creatinine [Mass/volume] in Blood',\
\
      },\
\
    ],

},

qualifiedInterval: [\
\
    {\
\
      condition: 'Normal',\
\
      range: {\
\
        high: {\
\
          value: 5,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
        },\
\
      },\
\
    },\
\
  ],

}
```

Example: Greater than or equal to 20 mg/dL

```ts
{

resourceType: 'ObservationDefinition',

code: {

coding: [\
\
      {\
\
        system: LOINC,\
\
        code: '38483-4',\
\
        display: 'Creatinine [Mass/volume] in Blood',\
\
      },\
\
    ],

},

qualifiedInterval: [\
\
    {\
\
      condition: 'Normal',\
\
      range: {\
\
        low: {\
\
          value: 20,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
        },\
\
      },\
\
    },\
\
  ],

}
```

In practice, multiple an [`ObservationDefinition`](/content/docs/api/fhir/resources/observationdefinition/index.html) will define multiple reference ranges for a given patient population, to provide interpretations for each value of the [`Observation`](/content/docs/api/fhir/resources/observation/index.html).

Details

Example: Multiple Ranges
The example below defines three reference ranges, to be interpreted as "Low", "Normal", and "High".

```ts
{

resourceType: 'ObservationDefinition',

code: {

coding: [\
\
      {\
\
        system: LOINC,\
\
        code: '38483-4',\
\
        display: 'Creatinine [Mass/volume] in Blood',\
\
      },\
\
    ],

},

qualifiedInterval: [\
\
    {\
\
      context: {\
\
        text: 'Low',\
\
      },\
\
      range: {\
\
        high: {\
\
          value: 9,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
          code: 'mg/dL',\
\
        },\
\
      },\
\
    },\
\
    {\
\
      context: {\
\
        text: 'Normal',\
\
      },\
\
      range: {\
\
        low: {\
\
          value: 10,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
          code: 'mg/dL',\
\
        },\
\
        high: {\
\
          value: 99,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
          code: 'mg/dL',\
\
        },\
\
      },\
\
    },\
\
    {\
\
      context: {\
\
        text: 'High',\
\
      },\
\
      range: {\
\
        low: {\
\
          value: 100,\
\
          unit: 'mg/dL',\
\
          system: UCUM,\
\
          code: 'mg/dL',\
\
        },\
\
      },\
\
    },\
\
  ],

}
```

## Patient-dependent reference ranges  [​](/content/docs/careplans/reference-ranges#patient-dependent-reference-ranges "Direct link to Patient-dependent reference ranges"/index.html)

Patient demographics can influence the interpretation of some diagnostic test results.

To handle this, the [`ObservationDefinition`](/content/docs/api/fhir/resources/observationdefinition/index.html) resource allows for defining reference ranges that can be either tailored to specific patient demographics or universally applied.

The table below describes which patient attributes can be used to target reference ranges:

| **Attribute** | Element | **Type** | Code System | Example |
| --- | --- | --- | --- | --- |
| Age | `qualifiedInterval.age` | Range |  |  |
| Gender | `qualifiedInterval.gender` | code | [AdministrativeGender](https://hl7.org/fhir/R4/valueset-administrative-gender.html) | female |
| Gestational Age | `qualifiedInterval.gestationalAge` | Range |  |  |
| Racial/Ethnic Group | `qualifiedInterval.appliesTo` | CodeableConcept | _(Example)_ [OMB Race Categories](https://build.fhir.org/ig/HL7/US-Core/ValueSet-omb-race-category.html) | Asian |

Details

Example: Age and gender dependent reference ranges
The example below demonstrates how to represent different normal ranges for a testosterone test, for both adults and children.

```ts
{

resourceType: 'ObservationDefinition',

code: {

coding: [\
\
      {\
\
        system: LOINC,\
\
        code: '2990-0',\
\
        display: 'Testosterone.free+weakly bound [Mass/volume] in Serum or Plasma',\
\
      },\
\
    ],

text: 'Testosterone',

},

qualifiedInterval: [\
\
    {\
\
      gender: 'male',\
\
      age: {\
\
        low: {\
\
          value: 11,\
\
          unit: 'years',\
\
        },\
\
        high: {\
\
          value: 29,\
\
          unit: 'years',\
\
        },\
\
      },\
\
      condition: 'Normal',\
\
      range: {\
\
        low: {\
\
          value: 200,\
\
          unit: 'ng/dL',\
\
        },\
\
        high: {\
\
          value: 900,\
\
          unit: 'ng/dL',\
\
        },\
\
      },\
\
    },\
\
    {\
\
      gender: 'male',\
\
      age: {\
\
        low: {\
\
          value: 30,\
\
          unit: 'years',\
\
        },\
\
      },\
\
      condition: 'High',\
\
      range: {\
\
        low: {\
\
          value: 300,\
\
          unit: 'ng/dL',\
\
        },\
\
        high: {\
\
          value: 1000,\
\
          unit: 'ng/dL',\
\
        },\
\
      },\
\
    },\
\
    {\
\
      gender: 'female',\
\
      age: {\
\
        low: {\
\
          value: 11,\
\
          unit: 'years',\
\
        },\
\
        high: {\
\
          value: 14,\
\
          unit: 'years',\
\
        },\
\
      },\
\
      condition: 'Normal',\
\
      range: {\
\
        low: {\
\
          value: 15,\
\
          unit: 'ng/dL',\
\
        },\
\
        high: {\
\
          value: 70,\
\
          unit: 'ng/dL',\
\
        },\
\
      },\
\
    },\
\
    {\
\
      gender: 'female',\
\
      age: {\
\
        low: {\
\
          value: 15,\
\
          unit: 'years',\
\
        },\
\
      },\
\
      condition: 'High',\
\
      range: {\
\
        low: {\
\
          value: 30,\
\
          unit: 'ng/dL',\
\
        },\
\
        high: {\
\
          value: 95,\
\
          unit: 'ng/dL',\
\
        },\
\
      },\
\
    },\
\
  ],

}
```

note

For any range, if these demographic qualifiers are left unspecified, the system interprets it as a universal range applicable to all patients.

Matching [`Patients`](/content/docs/api/fhir/resources/patient/index.html) to reference ranges

The Medplum SDK provides helper functions, [`findObservationInterval`](/content/docs/sdk/core.findobservationinterval), [`findObservationReferenceRange`](/content/docs/sdk/core.findobservationreferencerange), and [`matchesRange`](/content/docs/sdk/core.matchesrange) to find reference ranges that match a particular patient.

Example

```ts
const jane: Patient = {

resourceType: 'Patient',

name: [{ given: ['Jane'], family: 'Doe' }],

gender: 'female',

birthDate: '1970-01-01',

};

const janeTestosterone: Observation = {

resourceType: 'Observation',

status: 'final',

code: {

coding: [\
\
      {\
\
        system: LOINC,\
\
        code: '2990-0',\
\
        display: 'Testosterone.free+weakly bound [Mass/volume] in Serum or Plasma',\
\
      },\
\
    ],

text: 'Testosterone',

},

subject: createReference(jane),

valueQuantity: {

value: 32,

unit: 'ng/dL',

},

};

findObservationInterval(testosteroneDefinition, jane, janeTestosterone.valueQuantity?.value as number);

// Returns

// {
//   gender: 'female',
//   age: {
//     low: {
//       value: 15,
//       unit: 'years',
//     },
//   },
//   condition: 'High',
//   range: {
//     low: {
//       value: 30,
//       unit: 'ng/dL',
//     },
//     high: {
//       value: 95,
//       unit: 'ng/dL',
//     },
//   },
// }
}
```

## Types of reference ranges  [​](/content/docs/careplans/reference-ranges#types-of-reference-ranges "Direct link to Types of reference ranges"/index.html)

Reference ranges can be categorized into three different types:

| Field | Description |
| --- | --- |
| `reference` | Defines the **normal** ranges for a given observation type. |
| `critical` | Defines the **critical** values for the observation, also known as "panic" values. Observing values in these ranges often require special handling to notify patients. |
| `absolute` | The absolute allowable range for this value (i.e. the measurable range). Values outside of this range are not possible / sensible. |

The type of reference range is specified in the `qualifiedInterval.category` field.

Example

```ts
{

resourceType: 'ObservationDefinition',

code: {

coding: [\
\
      {\
\
        system: LOINC,\
\
        code: '2093-3',\
\
        display: 'Cholesterol in HDL [Mass/volume] in Serum or Plasma',\
\
      },\
\
    ],

text: 'HDL Cholesterol',

},

qualifiedInterval: [\
\
    // Reference ranges\
\
    {\
\
      category: 'reference',\
\
      range: {\
\
        low: {\
\
          value: 21,\
\
          unit: 'mg/dL',\
\
        },\
\
        high: {\
\
          value: 39,\
\
          unit: 'mg/dL',\
\
        },\
\
      },\
\
      condition: 'Low',\
\
    },\
\
    {\
\
      category: 'reference',\
\
      range: {\
\
        low: {\
\
          value: 40,\
\
          unit: 'mg/dL',\
\
        },\
\
        high: {\
\
          value: 60,\
\
          unit: 'mg/dL',\
\
        },\
\
      },\
\
      condition: 'Normal',\
\
    },\
\
    {\
\
      category: 'reference',\
\
      range: {\
\
        low: {\
\
          value: 61,\
\
          unit: 'mg/dL',\
\
        },\
\
        high: {\
\
          value: 99,\
\
          unit: 'mg/dL',\
\
        },\
\
      },\
\
      condition: 'High',\
\
    },\
\
    // Critical Ranges\
\
    {\
\
      category: 'critical',\
\
      range: {\
\
        high: {\
\
          value: 20,\
\
          unit: 'mg/dL',\
\
        },\
\
      },\
\
      condition: 'Critical Low',\
\
    },\
\
    {\
\
      category: 'critical',\
\
      range: {\
\
        low: {\
\
          value: 100,\
\
          unit: 'mg/dL',\
\
        },\
\
      },\
\
      condition: 'Critical High',\
\
    },\
\
    // Absolute Range\
\
    {\
\
      category: 'absolute',\
\
      range: {\
\
        low: {\
\
          value: 0,\
\
          unit: 'mg/dL',\
\
        },\
\
        high: {\
\
          value: 120,\
\
          unit: 'mg/dL',\
\
        },\
\
      },\
\
      condition: 'Absolute Range',\
\
    },\
\
  ],

}
```

## Editing reference ranges in the Medplum App  [​](/content/docs/careplans/reference-ranges#editing-reference-ranges-in-the-medplum-app "Direct link to Editing reference ranges in the Medplum App"/index.html)

Medplum has developed user interface tools to simplify the process of editing [`ObservationDefinition`](/content/docs/api/fhir/resources/observationdefinition/index.html) reference ranges.
The [ReferenceRangeEditor](https://storybook.medplum.com/?path=/story/medplum-referencerangeeditor--empty) component enables you to define groups of reference ranges for each set of patient attributes.

You can integrate this component into your custom application, or you can use it directly within the Medplum App.

To edit reference ranges in the Medplum App:

1. Navigate to the Medplum App's ObservationDefinition page at [https://app.medplum.com/ObservationDefinition](https://app.medplum.com/ObservationDefinition).
2. Select the specific [`ObservationDefinition`](/content/docs/api/fhir/resources/observationdefinition/index.html) resource you wish to edit.
3. Click on the "Ranges" tab.

### Examples  [​](/content/docs/careplans/reference-ranges#examples "Direct link to Examples"/index.html)

- [HDL Reference Ranges](https://storybook.medplum.com/?path=/story/medplum-referencerangeeditor--hdl) \- no dependence on patient attributes.
- [Testosterone Reference Ranges](https://storybook.medplum.com/?path=/story/medplum-referencerangeeditor--testosterone) \- dependent on patient gender and age.

## Non-numeric reference ranges  [​](/content/docs/careplans/reference-ranges#non-numeric-reference-ranges "Direct link to Non-numeric reference ranges"/index.html)

For qualitative observations, defining interpretations in the [`ObservationDefinition`](/content/docs/api/fhir/resources/observationdefinition/index.html) is slightly different. Rather than defining numerical ranges, the administrator defines [`ValueSet`](/content/docs/api/fhir/resources/valueset/index.html) resources that enumerate sets of codes.

The `validCodedValueSet`, `normalCodedValueSet`, `abnormalCodedValueSet`, and `criticalCodedValueSet` fields mirror the functionality of `absolute`, `reference`, and `critical` reference ranges, are used to define the interpretation of a qualitative observation.

Each one of these fields refers to a [`ValueSet`](/content/docs/api/fhir/resources/valueset/index.html) resource, which enumerates the codes assigned to each category of interpretation:

| Field Name | Similar to | Description |
| --- | --- | --- |
| `validCodedValueSet` | `absolute` | Enumerates of _all_ valid qualitative values for this Observation type. |
| `normalCodedValueSet` | `reference` | Enumerates all codes that signify a _normal_ result for this Observation. It should be a subset of the `validCodedValueSet`. |
| `abnormalCodedValueSet` | `reference` | Enumerates all of codes that signify an _abnormal_ result for this Observation. It should be a subset of the `validCodedValueSet`. |
| `criticalCodedValueSet` | `critical` | Enumerates all the qualitative values that are considered _critical_ or cause for "panic". Typically a subset of the `abnormalCodedValueSet`. |

## See Also  [​](/content/docs/careplans/reference-ranges#see-also "Direct link to See Also"/index.html)

- [LOINC Guide](/content/docs/careplans/loinc/index.html)
- [Diagnostic Catalog](/content/docs/careplans/diagnostic-catalog/index.html)

- [Defining a Reference Range](/content/docs/careplans/reference-ranges#defining-a-reference-range/index.html)
- [Patient-dependent reference ranges](/content/docs/careplans/reference-ranges#patient-dependent-reference-ranges/index.html)
- [Types of reference ranges](/content/docs/careplans/reference-ranges#types-of-reference-ranges/index.html)
- [Editing reference ranges in the Medplum App](/content/docs/careplans/reference-ranges#editing-reference-ranges-in-the-medplum-app/index.html)
  - [Examples](/content/docs/careplans/reference-ranges#examples/index.html)
- [Non-numeric reference ranges](/content/docs/careplans/reference-ranges#non-numeric-reference-ranges/index.html)
- [See Also](/content/docs/careplans/reference-ranges#see-also/index.html)
