Skip to main content
Observations capture clinical measurements: vital signs, lab results, physical exam findings, and social history. The FHIR R4 Observation resource uses LOINC codes to identify what was measured and structured value types to store the result. Observations are typically linked to both a patient and an encounter.

Create a vital sign

const { data: heartRate } = await clinik.observations.create({
  status: 'final',
  code: { system: 'http://loinc.org', code: '8867-4', display: 'Heart rate' },
  patientId: 'pt_abc123',
  encounterId: 'enc_xyz789',
  category: 'vital-signs',
  effectiveDateTime: '2025-01-15T09:15:00Z',
  valueQuantity: {
    value: 72,
    unit: 'beats/minute',
    system: 'http://unitsofmeasure.org',
    code: '/min',
  },
  interpretation: 'N', // Normal
});

Blood pressure (multi-component)

Blood pressure uses the component field to store systolic and diastolic values as separate sub-observations within one resource:
const { data: bp } = await clinik.observations.create({
  status: 'final',
  code: { system: 'http://loinc.org', code: '85354-9', display: 'Blood pressure panel' },
  patientId: 'pt_abc123',
  category: 'vital-signs',
  effectiveDateTime: '2025-01-15T09:15:00Z',
  component: [
    {
      code: { system: 'http://loinc.org', code: '8480-6', display: 'Systolic blood pressure' },
      valueQuantity: { value: 120, unit: 'mmHg' },
    },
    {
      code: { system: 'http://loinc.org', code: '8462-4', display: 'Diastolic blood pressure' },
      valueQuantity: { value: 80, unit: 'mmHg' },
    },
  ],
});

Create a lab result

Lab result observations use the laboratory category and should include a referenceRange so clinicians can interpret the value in context:
const { data: glucose } = await clinik.observations.create({
  status: 'final',
  code: {
    system: 'http://loinc.org',
    code: '2339-0',
    display: 'Glucose [Mass/volume] in Blood',
  },
  patientId: 'pt_abc123',
  category: 'laboratory',
  effectiveDateTime: '2025-01-15T10:00:00Z',
  valueQuantity: { value: 95, unit: 'mg/dL' },
  interpretation: 'N',
  referenceRange: {
    low: { value: 70, unit: 'mg/dL' },
    high: { value: 100, unit: 'mg/dL' },
    text: '70-100 mg/dL',
  },
});

Categories

CategoryDescriptionExamples
vital-signsVital sign measurementsHeart rate, BP, temperature, SpO2
laboratoryLab test resultsGlucose, CBC, metabolic panel
social-historySocial and behavioral dataSmoking status, alcohol use
examPhysical exam findingsLung sounds, reflexes

Interpretation codes

CodeMeaning
NNormal
HHigh
LLow
AAbnormal
HHCritically high
LLCritically low

Update an observation

const { data: amended } = await clinik.observations.update('obs_abc123', {
  status: 'amended',
  valueQuantity: { value: 74, unit: 'beats/minute' },
});

Delete an observation

await clinik.observations.delete('obs_abc123');

Search observations

const { data: vitals } = await clinik.observations.search({
  patientId: 'pt_abc123',
  status: 'final',
  dateFrom: '2025-01-01',
  sort: '-date',
  count: 50,
});
To group lab observations into a diagnostic report (e.g. a CMP panel), create each observation individually and then reference their IDs in a clinik.labs.create call. See the Labs guide for details.