{
    "componentChunkName": "component---src-pages-modes-mode-js",
    "path": "/modes/fhir-viewer",
    "result": {"data":{"modesJson":{"id":"fhir-viewer","title":"FHIR Viewer","shortDescription":"A workflow mode that connects OHIF to a FHIR R4 server, resolving imaging through ImagingStudy and DocumentReference resources with SMART on FHIR auth — so the viewer can launch in patient context from inside an EHR or RIS.","author":["Node on FHIR"],"repository":"https://github.com/node-on-fhir/ohif-fhir-viewer","npmPackageName":"@ohif/fhir-viewer","installationCommand":"View README for instructions","license":"MIT / Apache 2.0","builtIn":true}},"pageContext":{"id":"fhir-viewer","text":"## FHIR Viewer Mode for OHIF\n\nThe Open Health Imaging Foundation (OHIF) Viewer is an open-source, web-based platform for medical imaging. Most OHIF deployments reach their images over DICOMweb, talking directly to a PACS. The **FHIR Viewer** mode takes a different route: it treats a [FHIR](https://www.hl7.org/fhir/) server as the system of record, resolving imaging data through `ImagingStudy` and `DocumentReference` resources and authenticating with [SMART on FHIR](https://build.fhir.org/ig/HL7/smart-app-launch/).\n\nThe practical upshot is that OHIF can be launched from inside an EHR or RIS, in the context of a patient the clinician has already selected, with the same OAuth 2.0 session and scopes the rest of the clinical workspace uses.\n\n![FHIR Viewer mode running against a FHIR R4 server](https://github.com/user-attachments/assets/d36cf187-f401-4bab-b22e-ab8d8cbac517)\n\n### Table of Contents\n\n- [What is FHIR?](#what-is-fhir)\n- [What This Mode Does](#what-this-mode-does)\n- [Requirements](#requirements)\n- [Quick Start](#quick-start)\n- [SMART on FHIR Launch Context](#smart-on-fhir-launch-context)\n- [Configuring the Client ID](#configuring-the-client-id)\n- [ECG Waveform Support](#ecg-waveform-support)\n- [Module Reference](#module-reference)\n- [Connecting to a FHIR Server](#connecting-to-a-fhir-server)\n- [Installation Videos](#installation-videos)\n\n### What is FHIR?\n\n[Fast Healthcare Interoperability Resources](https://www.hl7.org/fhir/) (FHIR, pronounced \"fire\") is HL7's standard for exchanging healthcare data. Where DICOM models the image and its acquisition, FHIR models the surrounding clinical record — patients, encounters, orders, reports, and the studies that belong to them — as discrete resources served over a RESTful API with JSON payloads.\n\nThe two standards are complements rather than competitors, and the boundary between them is well-trodden:\n\n- **`ImagingStudy`** is FHIR's pointer to a DICOM study. It carries the study and series UIDs, modality, body site, and the endpoint where the pixel data actually lives.\n- **`DocumentReference`** can wrap or point at binary content, including DICOM instances held outside a conventional PACS.\n- **`ServiceRequest`** is the order that led to the exam; **`DiagnosticReport`** is the read that came out of it.\n- The [DICOM SR to FHIR implementation guide](https://build.fhir.org/ig/HL7/dicom-sr/en/) defines how DICOM Structured Reports — the measurements and findings OHIF produces — map onto FHIR `Observation` resources, so results captured in the viewer can travel back into the clinical record as first-class FHIR data.\n\nFor a radiology deployment, this means the worklist, the order, the patient context, and the report can all live in the same FHIR server that the viewer authenticates against.\n\n### What This Mode Does\n\nThe `fhir-viewer` mode bundles a FHIR data source with a standard OHIF layout and a handful of extras contributed by the accompanying `@ohif/fhir-viewer` extension:\n\n**FHIR data source** — a `webApi` data source that connects to FHIR R4 servers with SMART on FHIR auth, translating `ImagingStudy` and `DocumentReference` resources into OHIF-compatible study, series, and instance metadata. From the viewer's perspective the studies look ordinary; the retrieval path is what changes.\n\n**FHIR configuration panel** — a `fhirConfig` panel in the right panel group for setting the FHIR server URL, supplying auth details, and testing the connection without editing config files or rebuilding.\n\n**ECG waveform viewport** — renders DICOM ECG waveforms via `dcmjs-ecg`, registered alongside the default Cornerstone viewport.\n\n**DICOM ZIP export** — a `downloadDicomZip` command, wired into the right-click context menu, that exports the current study as a ZIP of DICOM Part 10 files. It tries WADO-RS, WADO-URI, and blob URL strategies in turn.\n\n**Developer tooling** — `nof.logViewportData` dumps full viewport state (camera, display sets, tools, measurements, performance) to the console; `nof.inspectViewportState` opens a modal with viewport properties, actors, and image data.\n\n**Hanging protocols and layout** — a `chestBodyPart` body-part-aware protocol for chest imaging, and a `minimalViewerLayout` template for a streamlined viewer.\n\nThe mode also extends the default tool group with a Text annotation tool and configures toolbar sections with the measurement tools and the log/inspect buttons.\n\nRoute: `/fhir-viewer`\n\n### Requirements\n\nThis mode **does not work standalone** — it is a client, and it needs a server to talk to. Specifically:\n\n- **A FHIR R4 server** exposing `ImagingStudy` and/or `DocumentReference` resources, plus a SMART configuration at `.well-known/smart-configuration` if you want the OAuth flow.\n- **CORS configured on that server** to permit the viewer's origin. The mode uses a CORS-direct model: the browser calls the FHIR endpoints at their absolute origin, with no dev proxy in between. If your server won't send the right `Access-Control-Allow-Origin` headers, nothing will load.\n- **A registered SMART client** — the server needs to know which app is asking for access, and the viewer needs the resulting client ID at runtime.\n- **Somewhere for the pixels to live.** FHIR resources are metadata and pointers; the imaging bytes still come from a DICOMweb endpoint or from binary content referenced by the FHIR resources.\n\nKnown-good backends are documented below: [Medplum](https://www.medplum.com/) and [Node on FHIR](https://github.com/node-on-fhir/core).\n\n### Quick Start\n\nClone the extension and OHIF **side by side**, install each, then link with the OHIF CLI:\n\n```bash\n# the extension — install its own dependencies\ngit clone https://github.com/node-on-fhir/ohif-fhir-viewer\ncd ohif-fhir-viewer\npnpm install --config.auto-install-peers=false\ncd ..\n\n# OHIF\ngit clone https://github.com/OHIF/Viewers\ncd Viewers\nbrew install pnpm   # if you don't already have pnpm\npnpm install\n\n# link the extension and its companion mode, then run\npnpm run cli link-extension ../ohif-fhir-viewer\npnpm run cli link-mode ../ohif-fhir-viewer/mode\npnpm dev\n```\n\nOpen `http://localhost:3000/fhir-viewer`.\n\nTwo things worth knowing:\n\n- `--config.auto-install-peers=false` matters. The extension's `peerDependencies` (e.g. `@ohif/core`) resolve from the OHIF build at bundle time and must not be installed into the extension's own `node_modules`.\n- The `link-*` commands write entries into OHIF's tracked `platform/app/pluginConfig.json`. That's fine for local development, but don't commit them — clones of Viewers don't contain this extension. `unlink-extension` and `unlink-mode` undo them.\n\n#### Alternative: environment variable injection\n\nRequires [OHIF/Viewers#6143](https://github.com/OHIF/Viewers/pull/6143). With that PR's branch, a single environment variable replaces both `link-*` commands and leaves the Viewers working tree untouched — the bundled `fhir-viewer` mode is auto-detected:\n\n```bash\n# out-of-tree checkout (use an absolute path for the directory override)\nEXTRA_EXTENSIONS=\"@ohif/fhir-viewer=$PWD/../ohif-fhir-viewer\" pnpm dev\n\n# or, if the extension is cloned inside extensions/, the name alone suffices\nEXTRA_EXTENSIONS=@ohif/fhir-viewer pnpm dev\n```\n\nMode auto-detection: when an `EXTRA_EXTENSIONS` package contains a `mode/` subdirectory with a `package.json`, that mode is registered automatically. Use `EXTRA_MODES` only to override or add other modes explicitly.\n\nSee [docs/INSTALL-COMPARISON.md](https://github.com/node-on-fhir/ohif-fhir-viewer/blob/main/docs/INSTALL-COMPARISON.md) for a full comparison of the installation patterns.\n\n### SMART on FHIR Launch Context\n\n[SMART App Launch](https://build.fhir.org/ig/HL7/smart-app-launch/) is the specification that lets a third-party application be launched from an EHR with the user's session and the current patient already established. Rather than making the radiologist find the patient a second time in a second application, the EHR hands the viewer a launch context and the viewer picks it up.\n\nThis mode supports the standard EHR launch. The sequence looks like this:\n\n1. The EHR (or RIS) redirects the browser to the viewer with `iss` and `launch` parameters — for example, `http://localhost:3200/fhir-viewer?iss=http://localhost:8103/fhir/R4&launch=<launch-id>`.\n2. The viewer detects both parameters and discovers the server's SMART configuration at `<iss>/.well-known/smart-configuration`.\n3. It redirects to the server's authorize endpoint. The user authenticates (or an existing session is reused) and grants consent.\n4. The server redirects back with `?code=…&state=…`. The viewer exchanges the code for a token at `/oauth2/token` and loads the patient's studies.\n\nA typical scope set for the registered client is `launch openid fhirUser patient/*.read`.\n\nThe viewer also accepts `iss` **without** `launch` — `?iss=http://localhost:8103/fhir/R4` sets the FHIR server without triggering an OAuth redirect, which is useful for standalone testing when you want to inject a token by hand.\n\n### Configuring the Client ID\n\nThere is **no build-time environment variable** for the SMART client ID in a deployed viewer. OHIF is a static SPA, so the client ID has to arrive at runtime. The viewer reads it from three browser-native surfaces, most-specific wins:\n\n1. **URL** — `?client_id=<uuid>` on the SMART launch. Per-launch; lets one deployment face multiple registrations.\n2. **SMART Preferences panel** — entered or registered in OHIF, saved to `localStorage`. Per-user.\n3. **`window.config`** — the `smartClientId` field in the data source `configuration` of the served `app-config.js`. Per-deployment.\n\nFor containerized deployments, the `app-config.js` value can be templated from an environment variable at container startup via the OHIF Docker entrypoint. Pure-static hosts edit the served config or use the Preferences panel.\n\nFor **local development against a source checkout**, the `smartClientId` in `config/default.js` can be overridden without editing that file by adding the following to `Viewers/platform/app/.env`:\n\n```bash\nSMART_CLIENT_ID=your-registered-client-id\n```\n\nThe `.env` value takes priority over the config file. Restart the dev server after changing it.\n\n### ECG Waveform Support\n\nThe ECG viewport handles seven SOP classes:\n\n| SOP Class | UID |\n| --- | --- |\n| 12-Lead ECG | `1.2.840.10008.5.1.4.1.1.9.1.1` |\n| General ECG | `1.2.840.10008.5.1.4.1.1.9.1.2` |\n| Ambulatory ECG | `1.2.840.10008.5.1.4.1.1.9.1.3` |\n| Hemodynamic Waveform | `1.2.840.10008.5.1.4.1.1.9.2.1` |\n| Basic Cardiac EP | `1.2.840.10008.5.1.4.1.1.9.3.1` |\n| Arterial Pulse Waveform | `1.2.840.10008.5.1.4.1.1.9.5.1` |\n| Respiratory Waveform | `1.2.840.10008.5.1.4.1.1.9.6.1` |\n\n### Module Reference\n\n| Module Type | OHIF ID | Description |\n| --- | --- | --- |\n| `commandsModule` | `nof.logViewportData`, `nof.inspectViewportState`, `nof.textCallback`, `downloadDicomZip` | Viewport logging, state inspector, text input, DICOM export |\n| `viewportModule` | `ecg-dicom` | ECG waveform viewport |\n| `sopClassHandlerModule` | `ecg-dicom` | Display set builder for ECG SOP classes |\n| `dataSourcesModule` | `fhir` | FHIR R4 data source |\n| `panelModule` | `fhirConfig` | FHIR configuration panel |\n| `hangingProtocolModule` | `chestBodyPart` | Chest body-part hanging protocol |\n| `layoutTemplateModule` | `minimalViewerLayout` | Minimal viewer layout |\n| `customizationModule` | `viewportContextMenu` | Right-click context menu |\n\n**Dependencies:** `jszip` `^3.10.1` for ZIP archive generation, `dcmjs-ecg` `^0.0.14` for ECG waveform parsing and rendering.\n\n### Connecting to a FHIR Server\n\nAny conformant FHIR R4 server with SMART support and permissive CORS should work. Two open-source backends have step-by-step guides:\n\n#### Medplum\n\n[Medplum](https://www.medplum.com/) is a good fit for the CORS-direct model — its development configuration ships with `allowedOrigins: \"*\"`, so the browser calls the FHIR and FHIRcast endpoints directly with no dev proxy required. The guide covers running Medplum's server, app, Redis, and PostgreSQL locally; registering a `ClientApplication` with the viewer's redirect and launch URIs; creating test `Patient`, `ServiceRequest`, `DiagnosticReport`, and `ImagingStudy` resources; triggering the SMART launch from the patient's **Apps** tab; and verifying FHIRcast subscription and event delivery.\n\n→ [Medplum Integration Guide](https://github.com/node-on-fhir/ohif-fhir-viewer/blob/main/MEDPLUM-INTEGRATION.md)\n\n#### Node on FHIR\n\n[Node on FHIR](https://github.com/node-on-fhir/core) can act as a full RIS backend for the viewer. The guide covers installing Meteor and the Honeycomb starter, adding the `radiology-workflow` package and companion workflow modules, registering an OAuth client (either through the `/oauth-clients` UI or by POSTing to `/oauth/register`), and completing a SMART launch from the RIS reading worklist.\n\n→ [Node on FHIR RIS Integration Guide](https://github.com/node-on-fhir/ohif-fhir-viewer/blob/main/NOF-RIS-INTEGRATION.md)\n\nIn both cases, the check that the CORS-direct path is working is the same: open DevTools → Network and confirm that FHIR requests go to the server's absolute origin with **no `/fhir-proxy`** in the path.\n\n### Installation Videos\n\nA playlist of installation walkthroughs is available on YouTube:\n\n→ [OHIF FHIR Viewer — Installation Videos](https://www.youtube.com/playlist?list=PL47Aa5onq8AiBxD5ebE0smTk7h3rcYEHa)\n\n### Further Reading\n\n- [HL7 FHIR](https://www.hl7.org/fhir/) — the base specification\n- [SMART App Launch](https://build.fhir.org/ig/HL7/smart-app-launch/) — the launch and authorization framework\n- [DICOM SR to FHIR](https://build.fhir.org/ig/HL7/dicom-sr/en/) — mapping structured reports onto FHIR resources\n- [ohif-fhir-viewer on GitHub](https://github.com/node-on-fhir/ohif-fhir-viewer) — source, issues, and full documentation\n"}},
    "staticQueryHashes": ["4202924991"]}