Skip to content
All essays
ArchitectureMarch 27, 202510 min

WebRTC: Real-Time Communication in the Browser

Master WebRTC for peer-to-peer real-time communication. Build video chat, file sharing, and more.

Ü
Ümit Uz
Mobile & Full Stack Developer

What is WebRTC?

WebRTC (Web Real-Time Communication) enables peer-to-peer audio, video, and data sharing directly between browsers without plugins or third-party software.

typescript
const configuration = {
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' }
  ]
};

const peerConnection = new RTCPeerConnection(configuration);

Core Concepts

Media Streams

typescript
// Get user media
async function getUserMedia() {
  const stream = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
  });
  
  const videoElement = document.getElementById('local-video') as HTMLVideoElement;
  videoElement.srcObject = stream;
  
  return stream;
}

RTCPeerConnection

typescript
class WebRTCClient {
  private pc: RTCPeerConnection;
  private localStream: MediaStream | null = null;
  
  constructor() {
    this.pc = new RTCPeerConnection({
      iceServers: [
        { urls: 'stun:stun.l.google.com:19302' },
        { urls: 'turn:turn.example.com:3478', username: 'user', credential: 'pass' }
      ]
    });
    
    this.setupEventHandlers();
  }
  
  private setupEventHandlers() {
    this.pc.onicecandidate = (event) => {
      if (event.candidate) {
        this.sendSignal({ type: 'ice-candidate', candidate: event.candidate });
      }
    };
    
    this.pc.ontrack = (event) => {
      const remoteVideo = document.getElementById('remote-video');
      remoteVideo.srcObject = event.streams[0];
    };
  }
  
  async addLocalStream(stream: MediaStream) {
    this.localStream = stream;
    stream.getTracks().forEach(track => {
      this.pc.addTrack(track, stream);
    });
  }
}

Signaling

Offer/Answer Pattern

typescript
// Caller creates offer
async function createOffer() {
  const offer = await peerConnection.createOffer();
  await peerConnection.setLocalDescription(offer);
  
  // Send offer via signaling server
  signalingServer.send({ type: 'offer', sdp: offer });
}

// Callee creates answer
async function handleOffer(offer: RTCSessionDescriptionInit) {
  await peerConnection.setRemoteDescription(offer);
  
  const answer = await peerConnection.createAnswer();
  await peerConnection.setLocalDescription(answer);
  
  // Send answer via signaling server
  signalingServer.send({ type: 'answer', sdp: answer });
}

// Caller handles answer
async function handleAnswer(answer: RTCSessionDescriptionInit) {
  await peerConnection.setRemoteDescription(answer);
}

ICE Candidates

typescript
peerConnection.onicecandidate = (event) => {
  if (event.candidate) {
    // Send candidate to peer
    signalingServer.send({
      type: 'ice-candidate',
      candidate: event.candidate
    });
  }
};

// Handle received candidate
async function handleIceCandidate(candidate: RTCIceCandidateInit) {
  await peerConnection.addIceCandidate(candidate);
}

Data Channels

P2P Data Transfer

typescript
// Create data channel
const dataChannel = peerConnection.createDataChannel('chat', {
  ordered: false  // UDP-like
});

dataChannel.onopen = () => {
  console.log('Data channel opened');
  dataChannel.send('Hello!');
};

dataChannel.onmessage = (event) => {
  console.log('Received:', event.data);
};

// Receive data channel (callee)
peerConnection.ondatachannel = (event) => {
  const dataChannel = event.channel;
  dataChannel.onmessage = (event) => {
    console.log('Received:', event.data);
  };
};

File Sharing

typescript
async function sendFile(file: File) {
  const dataChannel = peerConnection.createDataChannel('file-transfer');
  
  dataChannel.onopen = async () => {
    const arrayBuffer = await file.arrayBuffer();
    const chunkSize = 16384;  // 16KB chunks
    
    for (let i = 0; i < arrayBuffer.byteLength; i += chunkSize) {
      const chunk = arrayBuffer.slice(i, i + chunkSize);
      dataChannel.send(chunk);
    }
    
    dataChannel.send(JSON.stringify({ type: 'end', name: file.name }));
  };
}

Screen Sharing

typescript
async function shareScreen() {
  const stream = await navigator.mediaDevices.getDisplayMedia({
    video: { cursor: "always" },
    audio: false
  });
  
  stream.getTracks().forEach(track => {
    peerConnection.addTrack(track, stream);
  });
  
  return stream;
}

Best Practices

  1. 1Handle ICE failures gracefully
  2. 2Implement proper error handling
  3. 3Use TURN servers for firewall traversal
  4. 4Monitor connection quality
  5. 5Clean up resources properly

Conclusion

WebRTC enables real-time communication in browsers. Use it for video chat, screen sharing, file transfer, and more.

Build real-time apps with WebRTC!

Enjoyed this essay? Share it.

Related essays

Next essay
Repository Pattern: Abstract Data Access Logic