LevelChatLevelChat
Use cases/Telehealth
Telehealth

Private clinical visits with an audit trail.

Run HIPAA-eligible video visits with a waiting room, audit-friendly event logs, and end-to-end media encryption — or self-host the entire stack inside your VPC.

A clean modern hospital room with a bed positioned next to a large window, bathed in natural daylight.

The problem

Telehealth visits need a waiting room, audit-friendly event logs, encrypted media in transit, and a HIPAA BAA before a single visit can be billed. Most consumer video tools either refuse to sign a BAA or charge per provider — neither works when you ship telehealth as a feature inside a larger product.

How LevelChat fits

Self-host LevelChat behind your VPC (Helm chart on your existing k8s cluster) OR run on our Scale tier with a signed BAA. PHI is never logged; recordings (when used) are encrypted at rest with a customer-managed KMS key on Enterprise. Insertable-streams E2EE means the SFU forwards opaque payloads it cannot decode.

What we use under the hood

  • BAA available on Scale and Enterprise tiersDocs
  • Self-host or EU-region cloud (default Frankfurt)Docs
  • Insertable-streams E2EE on every trackDocs
  • Audit-trail webhooks for every join/leave eventDocs

Reference architecture

Provider browser            Patient browser
       │                              │
       └──────────┬───────────────────┘
                  │  E2EE (SFrame, insertable-streams)
                  ▼
            LevelChat SFU
        (your VPC OR our Scale cloud)
                  │
                  ▼
   audit webhook → your EMR
   recording (encrypted) → S3 + customer KMS

Integration snippet

Real code against published packages — no phantom imports.

app/visit/[appointment]/page.tsx
'use client';
import { LevelChatProvider, useRoom } from '@levelchat/web-react';
import { hkdfSha256 } from '@/lib/kdf';

export default function Visit({ token, sharedSecret }: { token: string; sharedSecret: string }) {
  // E2EE key derived from a per-visit secret the EMR mints alongside
  // the room token. The SFU never sees this key — frames are encrypted
  // at the publisher, decrypted at every other participant.
  return (
    <LevelChatProvider
      token={token}
      onRoomReady={async (room) => {
        const key = await hkdfSha256(sharedSecret, 'lc-visit-e2ee');
        await room.setEncryptionKey(key);
      }}
    >
      <VisitSurface />
    </LevelChatProvider>
  );
}

function VisitSurface() {
  const { participants } = useRoom();
  // ... your provider/patient grid
  return <ProviderView remotes={participants} />;
}

Common questions for this vertical

  • Is the BAA available on self-host?

    Yes — every self-host install is implicitly BAA-eligible because PHI never leaves your perimeter. The BAA covers the relationship between you and LevelChat for the cloud-managed control plane (license heartbeat, etc.) and is signed at Scale and Enterprise tiers.

  • How does recording work with E2EE?

    Recording requires the server to be able to decode media — it is structurally incompatible with E2EE. The supported pattern is: enable E2EE on the live call AND record only the participants who have consented to a separate clear-text recording stream (the SDK supports this via per-track encryption flags).

  • What region does the SFU run in?

    Default is eu-fsn (Frankfurt). Set region: "eu-hel" (Helsinki) or contact-sales for us-ash / us-sjc / ap-sg / ap-tok. Per-project overrides ride on the project itself; per-room overrides ride on the token.

Building something in this space?
We answer architecture questions on the same day. Sketch what you're working on and we'll send back a one-page LevelChat fit-check.
Telehealth — Private clinical visits with an audit trail · LevelChat