Skip to main content
Version: 1.x.x

Telehealth - React

Telehealth lets a clinician consult a patient over a one-to-one video call. The patient joins from a phone or a browser, the clinician reviews results and gives instructions, and the consultation can be recorded and transcribed for the patient's record.

This guide also covers video medical examinations for insurance underwriting. Follow the consultation flow as written, then see Video Medical Examination for Insurers for the steps a medical examination report (MER) adds.

If you are new to VideoSDK, start with Concept and Architecture and Integrate React SDK, and check Supported Browsers.

Architecture of a telehealth deployment on VideoSDK. The patient's phone and the clinician's console get tokens from your backend and exchange encrypted audio, video and data with VideoSDK. Your backend holds tokens, appointments and the patient record and uses REST APIs and webhooks. The clinician's traffic passes your firewall and an optional proxy. VideoSDK provides a waiting lobby, meeting rooms, chat, transcription, file sharing and the Realtime Store, recordings in your cloud storage and session-wide security controls.

note

VideoSDK runs the live video, audio, chat, recording and transcription for the consultation. Your application owns the appointment schedule, the clinician assignment and the patient record.

Set Up the Telehealth Session​

Prepare the room and generate participant tokens on your backend before the consultation begins.

  • Schedule appointments in your backend: VideoSDK does not schedule appointments or assign clinicians, so keep the appointment schedule and clinician assignment in your scheduling system. Create the room for the appointment, issue the tokens when it is due, and move the patient to the pre-call screen when the clinician is ready.
  • Create a room: Use the Create a Room API to create a room for each consultation. Use the returned roomId to associate the session with the appointment in your scheduling system.
  • Validate the room: Before issuing the patient's token, use the Validate a Room API to ensure the room is valid and available for the session. If validation fails, do not issue the token, and report the failure to your scheduling system.
  • Configure participant permissions: Set allow_join and allow_mod in the clinician's token to let the clinician join directly and request access to the patient's camera or microphone. Set ask_join in the patient's token so they wait in the lobby until the clinician admits them. Include roomId and participantId in both token payloads, with version set to 2. See Authentication and Tokens.
  • Gate controls by role: Features such as recording, screen sharing and file sharing are available to all participants by default. Show these controls only in the clinician's console to keep consultation actions under the clinician's control.

Configure the Patient's Devices and Network​

Patients join consultations from a phone or browser, often over a mobile or home network, and need a setup that works without technical help. Prepare their devices and assess network quality before the call.

Check Devices and Network Before the Call​

The patient's pre-call screen and the checks behind it. On the left, a phone shows a camera preview, camera and microphone selectors, a microphone test with a level meter, a speaker test with a play button, a connection line reading good connection, ready for video, and a join the call button. On the right, four cards list the checks: permissions granted, devices listed and refreshed when a headset is connected, microphone and speaker tested, and network measured with a quality score and factors, followed by a card saying the choices are carried into the meeting

  • Check permissions and devices: Provide a pre-call screen where patients can grant camera and microphone permissions, preview their camera, and test their microphone and speaker. Use checkPermissions() and requestPermission() from the useMediaDevice hook to manage permissions. Use getCameras() and getMicrophones() to list available devices, and onDeviceChanged to refresh the list when devices are connected or disconnected. See Precall Setup.
  • Assess network quality: Use runPreCallTest() to evaluate uplink and downlink quality on a scale from 1 (BAD) to 5 (EXCELLENT), along with the factors affecting each score. Use the results to select an appropriate starting media configuration and inform the patient about potential quality limitations. See Precall Setup.
  • Apply the verified setup: Pass the selected camera and microphone devices, their enabled states, and the chosen media configuration to MeetingProvider so the meeting starts with the setup the patient verified. Refer to the Precall Setup guide for recommended configurations based on the test results. The configuration can include a custom camera track created with createCameraVideoTrack(). See Optimize Video Tracks.
  • Join after pre-call checks: Set joinWithoutUserInteraction to true on MeetingProvider if your application has already collected the patient's consent to join during the pre-call flow. See Join Meeting.

Configure the Clinician's Console​

The clinician conducts the consultation from a console, reviewing results with the patient and sharing notes and files. The console should provide controls for admitting the patient, sharing content, and controlling the call.

Two screens side by side. On the left, the patient's phone shows the clinician's video, a small self view, a chat message from the clinician with a dosage spelling, a recording indicator, and microphone, camera and device buttons. On the right, the clinician's console shows the patient's video tile with a recording badge, a shared lab result on screen, buttons for share screen, send file, capture image and end call, a chat panel, and a consultation notes panel reading transcript and summary after the call

Prepare the Clinician's Environment Before the Call​

  • Check devices and network: Have the clinician complete the pre-call checks, including runPreCallTest(), before admitting the patient. This helps identify device or connectivity issues before the consultation begins. See Precall Setup.
  • Apply a virtual background: Use the Virtual Background plugin to blur the clinician's background or replace it with an image, such as a clinic backdrop, so patients see a professional view whether the clinician is in an open clinic or at home. Virtual backgrounds are supported on desktop browsers.
  • Suppress background noise: Use the Noise Suppression plugin on the clinician's microphone to reduce background noise and help the patient hear instructions clearly, even from a busy ward.

Admit the Patient from the Lobby​

note

The waiting lobby only holds the patient until the clinician admits them. Your system is responsible for appointment scheduling, as described in Set Up the Telehealth Session.

  • Admit the patient: When the patient joins with an ask_join token, they wait in the lobby until the clinician admits them. Handle onEntryRequested in the clinician's console to receive the patient's participantId and name, then call allow() to admit them. Both participants receive onEntryResponded with the admission decision. See Waiting Lobby.
  • Handle a denied request: If the clinician denies the request, display an appropriate message to the patient. Call leave() in the patient's application to disconnect them, since they remain connected until your application does so, then offer another appointment. See Leave or End Meeting.

Share Results, Notes and Files​

During a consultation, clinicians may need to review test results or care plans with patients, send reports or prescriptions, and share medication instructions or follow-up steps.

  • Share results on screen: Use enableScreenShare() from the useMeeting hook to share scans, test results, or care plans with the patient. The patient's application receives the shared content through screenShareStream. See Screen Share.
  • Send reports and prescriptions as files: Use uploadBase64File() from the useFile hook to upload reports or prescriptions to VideoSDK's temporary storage. Share the returned fileUrl with the patient by publishing it with publish() over PubSub, and use fetchBase64File() to retrieve the file on the patient's side. Temporary files are deleted when the meeting ends. See File Sharing.
  • Capture an image during the examination: When the clinician needs a clear image of a rash, a wound or a medication label, use captureImage() from the useParticipant hook on the patient's local participant. The image then comes from the patient's own camera rather than the video received over the network. Send the Base64 image to the clinician with publish() over PubSub, in chunks for a larger image, or upload it with file sharing, and store it in the patient's record. See Image Capturer.
  • Share instructions in chat: Use PubSub for in-meeting chat to share links, medication instructions, and follow-up steps. Set persist to true if messages should remain in the session's message history. Persisted messages can be downloaded as CSV from the VideoSDK session dashboard for the patient's record. See Chat using PubSub.

Control the Call​

Configure the Call Screen on Both Sides​

These components are built into both the patient's application and the clinician's console.

Display the Consultation​

  • Render each participant's video: Use the VideoPlayer component to render each participant's video. It requests the video quality that matches the tile size, so the patient appears large and clear on the clinician's screen and the clinician fills the patient's phone, and it mirrors the local preview. See Display Audio and Video.
  • Keep the call visible with Picture-in-Picture: Use Picture-in-Picture to keep the call visible in a floating window when either side moves to another screen, such as the patient opening a result or the clinician opening the patient's chart. See Picture-in-Picture Mode.

Control Your Own Media and Devices​

Show Participant Status​

  • Track participant joins and leaves: Use onParticipantJoined and onParticipantLeft from the useMeeting hook to update each screen when the other participant joins or disconnects. See Participant Events.
  • Show microphone and camera status: Use micOn and webcamOn from the useParticipant hook to indicate whether the other participant's microphone and camera are enabled. See Display Audio and Video.
  • Monitor the incoming video stream: Use onStreamStateChanged from the useStream hook to detect when the other participant's video stream becomes active, stuck, or frozen, so each side can ask the other to check their connection before continuing. See Monitoring Remote Streams.

Keep the Session Reliable​

These controls apply to both the patient's application and the clinician's console.

Handle Network Changes During the Consultation​

Network conditions can change during a consultation. Patients may use mobile or home networks, while clinicians may connect through hospital or clinic networks. VideoSDK adapts video quality to available bandwidth and provides network and media events that help your application respond to changing conditions.

  • Keep both sides informed: Use the relevant quality events to notify the patient and the clinician when network conditions affect call quality and when conditions improve. See Monitoring Network Quality for available events and Optimize for Low Bandwidth Networks for recommendations before and during the call.
  • Show the connection state: Use onMeetingStateChanged from the useMeeting hook to follow the meeting connection through CONNECTING, CONNECTED, RECONNECTING and DISCONNECTED. Show a reconnecting indicator on both screens while the state is RECONNECTING, so the patient and the clinician know the consultation is recovering rather than over, and return to your scheduling screen when it reaches DISCONNECTED. See Meeting Connection State Events.

Detect a Silent Microphone​

  • Warn when the microphone stops capturing audio: A patient's microphone can go silent while it is still on, for example when they answer a phone call in a mobile browser or another application takes over the microphone. Use onAudioInputSilence from the useMeeting hook to detect this on the patient's device and show them a warning to check their microphone. Since the event is only raised on the patient's own device, publish() the detected and resolved states to the clinician over PubSub so the console can indicate that the patient cannot be heard. Remove the warning when the event reports resolved or the patient turns the microphone off. See Audio Input Silence Events.

Handle Errors and Follow Best Practices​

  • Handle SDK errors: Use onError from the useMeeting hook to receive error information when a meeting operation fails. Display actionable feedback in the patient's application and the clinician's console, and send relevant diagnostic details to your monitoring service so failures across consultations stay visible to your team. Avoid including patient data in logs. See Error Events.
  • Follow integration guidelines: Review the User Experience Guidelines and Developer Experience Guidelines to build a reliable, accessible consultation experience.

Recording​

Configure recording, storage delivery, and encryption based on your consultation requirements. You can start recording when the patient is admitted and configure transcription alongside it. If recording is mandatory, verify that it has started before proceeding with the consultation. The recording's delivery destination and encryption depend on your configured storage and encryption settings.

Choose the Recording Type​

VideoSDK offers three types of recording. Choose the one that matches what your consultation record needs. See Recording Overview.

  • Meeting recording: Records the entire consultation, both participants and shared content, into one file with a composed layout. Set mode to audio in the recording config when the consultation record is the transcript and notes rather than the video, so the file is smaller and stores no video of the patient. See Start and Stop.
  • Participant recording: Records one participant's audio and video into a single file, such as the patient alone. Start it with the Start Participant Recording API, and use the matching participant recording API to stop it. See Participant Recording (Individual).
  • Participant track recording: Records a single audio or video track of one participant as its own file. Start it with the Start Track Recording API, and use the matching track recording API to stop it. See Participant Track Recording.
note

Geo tagging uses a custom recording template, which only the meeting (composite) recording supports. Use the meeting recording when you need the location watermark.

Record the Consultation​

  • Start recording automatically: If the consultation must be recorded from the beginning, show both the clinician and the patient a consent notice before the call, then add a recording entry to autoStartConfig when creating the room with the Create a Room API. Use this entry to configure transcription and the recording config as needed. See Create a Room.
  • Wait for recording confirmation: Show a loader on both screens until the recording starts. The backend receives the recording-started webhook, while the applications receive onRecordingStateChanged with RECORDING_STARTED. If the clinician starts recording manually using startRecording() from the useMeeting hook, show the same loader until the started status arrives. See Start and Stop and Webhook and Events.
  • Handle recording failures: VideoSDK sends the recording-failed webhook if recording fails while starting, during the consultation, or while stopping. If recording fails at the start and recording is mandatory, do not proceed with the consultation. If recording is optional, you can continue without it. If recording fails during the consultation, you can retry or end the session. To close the room automatically when recording fails, configure the onFailure option as described below. See Recording Failed Webhook.
  • Close the room automatically: If recording is mandatory, configure VideoSDK to close the room when recording fails. Add an onFailure entry to the recording section of autoStartConfig, or include it in the request body when starting recording from your backend. Set action to close-room and configure waitTime in seconds. We recommend 30 seconds. See the onFailure parameter and example request body in Create a Room and Start Recording.
  • Stop the recording and store the file: The recording stops automatically when the session ends. To stop it earlier, call stopRecording() from the useMeeting hook or the Stop Recording API from your backend. Your backend receives the recording-stopped webhook with the fileUrl, filePath and sessionId, so it can attach the file to the patient's record. To look the file up later, use the Fetch Recordings API to list the recordings of a room or the Fetch a Recording API to retrieve one by its id. See Webhook and Events.

Store Recordings in Your Own Storage​

  • Configure your own storage: Use Configure Recording Storage in the dashboard to deliver recordings to your own AWS S3, Azure Blob or GCP bucket. It is set per API key and includes a test step.
  • Upload with a presigned URL: When stored credentials are not allowed, generate a presigned URL on your backend and pass it to the Start Recording API, so the recording is uploaded to one object for a limited time.
note

VideoSDK uploads recordings to your storage with the credentials you set up. If your storage only accepts uploads from approved IP addresses, you will need to approve VideoSDK's static IP addresses. Contact us to request them.

Encrypt and Decrypt Recordings​

  • Encrypt recordings at rest: Turn on Recording Encryption for the API key in the dashboard, under Cloud Storage Configuration, and provide an RSA public key. Each recording is encrypted with its own AES key before upload. AES-256-GCM is recommended.
  • Decrypt with your private key: Each recording arrives as three files: the encrypted recording, the wrapped AES key and a metadata file. Decrypt them on your side with your private key. The guide includes a Node.js example.
note

Recording Encryption and transcription cannot be enabled together on one API key, since transcription runs on unencrypted recordings. Decide per API key which your patient record needs before configuring either.

Transcription​

Live captions help patients who are hard of hearing or consulting in a second language, while post-call transcripts and summaries become the consultation notes. Transcription is not available for an API key with Recording Encryption enabled.

Show Live Captions​

Generate the Transcript and Summary​

  • Generate a post-consultation transcript and summary: Pass a transcription configuration to startRecording(), set enabled to true, and provide a summary.prompt that specifies the sections your clinicians need, such as complaint, findings and plan. Retrieve the transcript and summary using the Fetch Post Transcriptions & Summary API or the webhook URL provided to startRecording(). See Post Transcription & Summary.

Choose the Language​

  • Set the spoken language: Pass the appropriate language code to startTranscription(). The default is en. See Supported Languages for available codes, including regional variants such as en-IN, hi, and es-419.
  • Translate captions when needed: If the clinician and patient speak different languages, use Realtime Translation to help both sides follow the conversation.

Video Medical Examination for Insurers​

A video medical examination uses the same flow as a consultation. The applicant takes the patient's place and the examiner takes the clinician's, and every section above applies as written. Add the following steps to produce the examination report.

  • Verify the applicant's identity: Confirm that the person on camera is the applicant before the examination starts, since the report is filed under their name. Capture the applicant's face and check it against their identity document or the photo on file with Face Match, and run Face Spoof Detection on the capture. Follow the KYC guide to capture the document and face and verify the captured images. Skip this step if identity was verified at the proposal stage.
  • Run the health questionnaire: Ask the applicant a fixed set of questions and record each answer in your system. Keep the current question in the Realtime Store with setValue(), getValue() and onValueChanged from the useRealtimeStore hook, so both screens stay on the same question. After a reconnect, listen to onMeetingStateChanged and read the current question again with getValue() when the state returns to CONNECTED.
  • Capture examination images: Use Capture an image during the examination for the body areas and documents the underwriter needs to see, and store each image with the applicant's answers.
  • Record the examination: Recording is mandatory for an MER, so start it with the session as described in Record the Consultation. Add the applicant's location with the geo tag template when your insurer requires it.
  • Generate the report: In Generate the Transcript and Summary, set summary.prompt to the sections your underwriters need, such as medical history, examination findings, declarations and examiner's remarks, so the post-call summary is the first draft of the report.
  • Meet insurance requirements: Apply the controls in Meet Compliance Requirements along with your insurance regulator's rules for identification, recording and record retention, such as IRDAI in India.

Meet Compliance Requirements​

Configure these session-wide controls to align your consultation workflow with your organization's data protection policies and regional requirements.

RequirementControl
Keep media within a regionUse Geo Fencing to restrict connections to VideoSDK servers in your specified regions, regardless of the patient's location. See Geo Fencing.
Allow or restrict access by locationUse Geo IP Restriction to allow or deny access based on the patient's IP address and your geographic rules. See Geo IP Restriction.
Encrypt media end to endUse E2EE to encrypt media on the sender's device and decrypt it only on the receiver's device, preventing intermediaries, including VideoSDK servers, from accessing the media. Your application is responsible for generating and distributing encryption keys. See E2EE Setup.
Meet regulatory requirementsVideoSDK offers a Business Associate Agreement for HIPAA to covered entities and business associates, and GDPR compliance with EU data residency and a Data Processing Agreement. SOC 2 Type II, ISO 27001 and CERT-IN are also available. The HIPAA features, the GDPR compliance and the Data Processing Agreement are available as add-ons.
note

If E2EE is enabled and you want to record or transcribe the session, use a custom recording template. See Customize Recording UI.

  • Recording: Build the template with the React or JavaScript SDK and enable E2EE in it using the same key provider and shared key as your application, so the template can decrypt the media for recording. Deliver the key securely from your backend to the template over HTTPS rather than including it in the templateUrl, then start the recording using the template's templateUrl.
  • Transcription: Use the same template recording for the post-call transcript and summary, since post transcription runs on the recording file. Realtime transcription is not available when E2EE is enabled.

Firewall and Debugging​

Clinicians often connect from hospital or clinic networks, and some patients may use restricted networks as well. Configure firewall rules before the first consultation to ensure the required VideoSDK services are reachable. If a session fails to connect, use the checks below to identify potential network restrictions.

Allow VideoSDK Traffic Through Your Firewall​

  • Allow VideoSDK domains: The simplest approach is to allow all subdomains of *.videosdk.live over TCP and UDP on all ports. This covers the API, signaling, media, and TURN servers. See Firewall Setup.

  • Allow specific hosts and ports: If your network policy requires explicit firewall rules, allow the following hosts and ports. VideoSDK can use the fallback transport when the primary connection is unavailable.

    ServerHostPrimaryFallback
    APIapi.videosdk.liveTCP 443—
    Signaling*.rm.videosdk.live, or the regional hosts listed in the Firewall Setup guideTCP 443—
    Mediamedia.videosdk.liveUDP 40000–60000TCP 40000–60000
    TURNturn.videosdk.liveUDP and TCP 3478TCP 443

    Also allow sdk.videosdk.live over TCP 443 if your console loads the SDK or the PubSub worker from the VideoSDK CDN. The full-access policy already covers it.

  • Allow the PubSub worker in your Content Security Policy: PubSub runs in a web worker created from a blob: URL. If the clinician console runs under a strict Content Security Policy, allow blob: in the worker-src directive, or pass pubsubWorkerUrl to MeetingProvider to load a pre-built worker from the VideoSDK CDN or your own domain. See CSP policy for PubSub.

  • Use Cloud Proxy for restricted networks: If the required ports cannot be opened, use Cloud Proxy to route media through the proxy servers you specify. Choose UDP over TCP (the default), Force UDP, or Force TCP according to your network restrictions.

Debug Connection Issues​

  • Test the network before the first session: Run runPreCallTest() from the clinic's network after configuring the firewall. The test checks whether a call can transmit media in both directions. If it fails despite internet access, review the required hosts and ports above. See Precall Setup.
  • Check UDP connectivity: Set preferredProtocol to TCP_ONLY in MeetingProvider and try connecting again. If the call succeeds over TCP but fails with the default UDP_OVER_TCP configuration, investigate whether UDP traffic is blocked on the media or TURN ports. You can also configure Cloud Proxy for the affected network.
  • Inspect connection errors: Use onError from the useMeeting hook to capture the error code and message when a connection fails. Use this information to investigate whether the failure occurred during the API, signaling, or media stage, and forward relevant diagnostics to your monitoring service to identify affected networks. See Error Events.
  • Verify media flow: Use getTransportStats() from the useParticipant hook to inspect transport statistics and check whether traffic is flowing in both directions. If one direction shows no bitrate, investigate the corresponding network path and firewall rules. See Monitoring Transport Stats.
  • Collect connection logs: Call setLogLevel() with Constants.LogLevel.DEBUG to collect detailed diagnostics while reproducing the issue. After troubleshooting, restore the log level to INFO or NONE as appropriate. See Log Level.

API Reference​

The API references for all the methods and events utilized in this guide are provided below.

Got a Question? Ask us on discord