# Building Scalable Telehealth Platforms with Next.js and Node.js for the European Market

> A Next.js and Node.js architecture guide for telehealth: WebRTC, EHR interfaces, authorization, recovery and jurisdiction-specific requirements.

Author: Ala Ben Aicha

Canonical page: https://alabenaicha.me/insights/building-telehealth-platforms-nextjs-nodejs

Updated: 2026-10-05

## Introduction

The European telehealth market has matured significantly since the pandemic-driven surge of 2020. What started as a quick fix for lockdown-era healthcare has become a permanent part of the care delivery landscape. But building a telehealth platform for the European market is fundamentally different from building one for the US — the regulatory environment, data protection requirements, and integration landscape demand specific architectural decisions.

This guide describes implementation patterns for a telehealth architecture. The examples are illustrative; they do not demonstrate a certified or legally compliant deployment.

## Architecture Overview

A production telehealth platform for the European market needs these core components:

```
┌─────────────────────────────────────────────────────────┐
│                    Client Layer                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │   Next.js    │  │  React Native│  │   Patient    │  │
│  │   Web App    │  │  Mobile App  │  │   Portal     │  │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘  │
└─────────┼──────────────────┼─────────────────┼──────────┘
          │                  │                 │
          ▼                  ▼                 ▼
┌─────────────────────────────────────────────────────────┐
│                    API Gateway                           │
│            (Authentication + Rate Limiting)              │
└────────┬──────────┬──────────┬──────────┬───────────────┘
         │          │          │          │
         ▼          ▼          ▼          ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│ Consult  │ │ Schedule │ │ Clinical │ │  Signaling   │
│ Service  │ │ Service  │ │  Notes   │ │  Server      │
│ (Node.js)│ │ (Node.js)│ │ (Node.js)│ │  (WebSocket) │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘
     │            │            │               │
     ▼            ▼            ▼               ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│PostgreSQL│ │PostgreSQL│ │  FHIR    │ │    TURN      │
│          │ │          │ │  Server  │ │    Server    │
└──────────┘ └──────────┘ └──────────┘ └──────────────┘
                              │
                              ▼
                    ┌──────────────────┐
                    │   EHR Systems    │
                    │ (Epic, Cerner,   │
                    │  local systems)  │
                    └──────────────────┘
```

## Video Consultation with WebRTC

### Why WebRTC

WebRTC is the standard for browser-based real-time communication. For telehealth, it offers:

* **Encrypted transport** — WebRTC protects media transport; end-to-end protection across media servers requires a specific design. See [RFC 8827](https://www.rfc-editor.org/rfc/rfc8827.html).
* **No plugin required** — works in modern browsers
* **Adaptive bitrate** — adjusts quality based on network conditions
* **Low latency** — essential for clinical conversations

### Signaling Server Architecture

WebRTC requires a signaling server to coordinate peer connections. I build this with **Socket.io** on Node.js:

```typescript
// Signaling server — handles WebRTC session negotiation
import { Server } from 'socket.io';

interface ConsultationRoom {
  clinicianId: string;
  patientId: string;
  startedAt: Date;
  recordingConsent: boolean;
}

const rooms = new Map<string, ConsultationRoom>();

io.on('connection', (socket) => {
  socket.on('join-consultation', async ({ roomId, role, userId }) => {
    // Verify user is authorized for this consultation
    const authorized = await verifyConsultationAccess(roomId, userId, role);
    if (!authorized) {
      socket.emit('error', { code: 'UNAUTHORIZED' });
      return;
    }

    socket.join(roomId);

    // Notify the other participant
    socket.to(roomId).emit('participant-joined', { role, userId });
  });

  socket.on('offer', ({ roomId, sdp }) => {
    socket.to(roomId).emit('offer', { sdp });
  });

  socket.on('answer', ({ roomId, sdp }) => {
    socket.to(roomId).emit('answer', { sdp });
  });

  socket.on('ice-candidate', ({ roomId, candidate }) => {
    socket.to(roomId).emit('ice-candidate', { candidate });
  });
});
```

### TURN Server for NAT Traversal

In real-world deployments, many hospital networks use strict firewalls that block peer-to-peer WebRTC connections. A **TURN (Traversal Using Relays around NAT)** server is essential:

* Choose TURN locations and processors against the approved hosting and transfer requirements. GDPR does not impose a universal EU-only hosting rule; international transfers need their applicable safeguards.
* Use **coturn** — the industry-standard open-source TURN server
* Configure **TLS on TURN** (TURNS) for encrypted relay traffic
* Plan for bandwidth — TURN relay traffic can be significant at scale

### Recording and Consent

Before enabling recording, establish the lawful basis, applicable health-data condition, notice, authorization and retention rules with the responsible organization. Record the required permissions and provide a clear recording indicator. Encrypt stored recordings and control access. Erasure requests must be assessed against applicable retention obligations; deletion is not unconditional. See [GDPR](https://eur-lex.europa.eu/eli/reg/2016/679/oj), Articles 6, 9, 17 and Chapter V.

## Scheduling and Appointment Management

### Calendar Integration

A telehealth scheduling system needs to handle:

* **Clinician availability** — recurring schedules with exception handling
* **Time zones** — critical for cross-border consultations in Europe
* **Buffer time** — gaps between appointments for documentation
* **Waitlist management** — filling cancellation slots automatically

I use **date-fns** with **date-fns-tz** for time zone handling in Node.js:

```typescript
import { zonedTimeToUtc, utcToZonedTime, format } from 'date-fns-tz';

function getAvailableSlots(clinicianId: string, date: Date, patientTimezone: string): TimeSlot[] {
  // Fetch clinician's schedule in their timezone
  const clinicianTz = 'Europe/Zurich';
  const schedule = getClinicianSchedule(clinicianId, date);

  return schedule.availableSlots.map((slot) => ({
    // Store in UTC, display in patient's timezone
    startUtc: zonedTimeToUtc(slot.start, clinicianTz),
    endUtc: zonedTimeToUtc(slot.end, clinicianTz),
    displayTime: format(
      utcToZonedTime(zonedTimeToUtc(slot.start, clinicianTz), patientTimezone),
      'HH:mm',
      { timeZone: patientTimezone }
    )
  }));
}
```

### Pre-Consultation Workflow

European telehealth platforms should include a pre-consultation workflow:

1. **Patient intake form** — symptoms, reason for visit, medication changes
2. **Document upload** — lab results, referral letters, imaging reports
3. **Insurance verification** — validate coverage for telehealth services (varies by country)
4. **Technical check** — camera, microphone, and network quality test before the appointment
5. **Waiting room** — virtual waiting area with estimated wait time

## EHR Integration

### FHIR-Based Clinical Data Exchange

The telehealth platform must integrate with the patient's EHR for clinical context. I use FHIR APIs for this:

```typescript
// Fetch patient context before consultation
async function getPatientContext(patientFhirId: string): Promise<PatientContext> {
  const [conditions, medications, allergies] = await Promise.all([
    fhirClient.search('Condition', {
      patient: patientFhirId,
      'clinical-status': 'active'
    }),
    fhirClient.search('MedicationStatement', {
      patient: patientFhirId,
      status: 'active'
    }),
    fhirClient.search('AllergyIntolerance', {
      patient: patientFhirId,
      'clinical-status': 'active'
    })
  ]);

  return { conditions, medications, allergies };
}
```

### Clinical Documentation

After the consultation, the clinician generates a clinical note. This should be structured as a FHIR `Encounter` resource linked to:

* `Condition` resources for new or updated diagnoses
* `MedicationRequest` for new prescriptions
* `ServiceRequest` for referrals or lab orders
* `DocumentReference` for the clinical note itself

## European Regulatory Considerations

### GDPR Compliance for Telehealth

Specific GDPR considerations for telehealth platforms:

* **Lawful processing** — identify an Article 6 basis and an applicable Article 9 condition; Article 9(2)(h) is not a standalone authorization for every telehealth service.
* **Video data** — encryption is one security control; assess authorization, media-server trust boundaries, signalling metadata and operational procedures as well.
* **Session metadata** — who called whom, when, and for how long is personal data and must be protected accordingly
* **Cross-border consultations** — if a clinician in one EU country consults with a patient in another, data processing occurs in both jurisdictions

### National Telehealth Regulations

Confirm professional practice rules, reimbursement conditions, patient information, hosting and record-retention requirements for each target country. Do not assume that teleconsultation is fully reimbursed or that a single EU configuration covers every national setting. Make billing, consent and documentation policies configurable against the approved requirements.

### Medical Device Classification

If your telehealth platform includes clinical decision support, AI-based triage, or diagnostic tools, it may qualify as a **medical device** under the EU MDR. Pure video consultation platforms typically do not, but the line blurs quickly when you add clinical functionality.

## Performance and Reliability

### Network Resilience

Healthcare video consultations cannot tolerate the same failure rates as consumer video calls. Build for resilience:

* **Automatic reconnection** — if a connection drops, reconnect within seconds without losing the consultation context
* **Bandwidth adaptation** — gracefully degrade video quality before dropping to audio-only
* **Fallback to phone** — if WebRTC fails entirely, offer a click-to-call option as a last resort
* **Connection quality indicators** — show both participants the current connection quality

### Monitoring

Monitor these metrics in production:

* **Connection success rate** — percentage of consultations that establish a video connection successfully
* **Average setup time** — time from "Join" click to video being visible
* **Dropped connection rate** — percentage of consultations interrupted by network issues
* **Audio/video quality scores** — WebRTC provides statistics for packet loss, jitter, and round-trip time

## Conclusion

Building a telehealth platform for the European market requires more than just a video call feature. It demands careful attention to GDPR compliance, EHR integration through FHIR APIs, country-specific regulatory requirements, and the kind of reliability that clinical workflows demand. The Next.js + Node.js stack provides the flexibility and performance needed, but the architecture decisions — particularly around data residency, encryption, and clinical integration — are what make or break a European telehealth product.

If you are building a telehealth platform for the European market and need architecture guidance or implementation support, I would be happy to discuss your requirements.
