Real-time video looks solved until you embed it in your own product. A demo connects two browsers in an afternoon; production adds hotel Wi-Fi, mid-call camera switches, tab refreshes, and participants joining from three time zones. This tutorial is a developer's walkthrough of the decisions that matter when you add video calling to a web application, and of how to connect those calls to AI workflows once the basics are stable.
The focus throughout is on choices you can defend later: which media layer to adopt, how to shape signaling, what to store, and how to keep call quality measurable after launch.
Every architectural mistake in video calling starts with a vague product statement like "add video chat." Before comparing libraries, write down what the call is actually for. The answers narrow the stack faster than any benchmark.
Most applications fall into one of three shapes, and each has different requirements.
One-to-one calls are the simplest: two peers, short sessions, and a strong preference for peer-to-peer connections that avoid server bandwidth entirely. Think consultations, interviews, or support escalation.
Group rooms typically start at three to twelve participants. Peer-to-peer mesh networks degrade quickly past four people because each client uploads one stream per peer, so an SFU (Selective Forwarding Unit) becomes necessary. This is where managed media platforms usually earn their cost.
Broadcast and webinar shapes are asymmetric: one or a few publishers, many viewers, and hard requirements around latency, recording, and moderation. These need a different topology again, often with a CDN-style delivery layer.
A single answer to the first question can move your bandwidth estimate by an order of magnitude, so get it in writing before writing code.
WebRTC is the browser-native standard for real-time media. It handles capture, encoding, network traversal, and congestion control. What it deliberately does not handle is everything around the call: signaling, presence, recording, scaling, and analytics.
Choose a managed platform when group size exceeds four participants, when you need recording and composition out of the box, or when your team has no one who can own media infrastructure. Choose raw WebRTC when calls are mostly one-to-one, when data residency makes third-party media routing unacceptable, or when cost predictability at low volume matters more than feature velocity.
A hybrid is common and often correct: WebRTC for one-to-one sessions, a managed SFU for large rooms, with the same signaling contract in front of both. Designing that interface early prevents a rewrite later.
Signaling is the control plane of a call. It carries no media, which makes people underestimate it. In practice, signaling bugs cause more support tickets than encoding problems.
Model every call as an explicit state machine: created, ringing, connected, reconnecting, and ended. Persist transitions with timestamps. When a user reports a dropped call, you want to answer "what state was the room in?" in seconds rather than hours.
Define a small, versioned message schema and validate it on the server. A workable minimal set looks like this:
join and leave with room and participant identifiersoffer, answer, and ice-candidate payloads forwarded verbatimtrack-state updates for mute, camera off, and screen shareheartbeat to detect half-open socketsKeep media negotiation payloads opaque. Parsing SDP on your server is a maintenance trap unless you are building an SFU.
WebSocket connections are stateful and long-lived, which makes horizontal scaling non-trivial. Two patterns dominate. With sticky sessions, a load balancer pins each client to one node and you accept uneven load. With a pub/sub backplane, every node subscribes to room channels and forwards messages for participants it does not own. The backplane approach is more flexible but requires message deduplication and careful ordering guarantees.
A framework like NestJS suits this well: gateways handle socket lifecycle, services hold room state, and dependency injection makes it straightforward to swap an in-memory room registry for a distributed one when traffic grows.
A relational database is a good default for call metadata. It gives you transactions, foreign keys, and the ability to run analytics without a separate pipeline. Managed Postgres offerings such as Supabase add row-level security, which is genuinely useful when clients subscribe to tables directly.
rooms: identifier, owner, room type, configured maximum participants, created and closed timestampsparticipants: room reference, user reference, role, join and leave timestamps, device summarycall_events: append-only log of state transitions, quality samples, and errorsrecordings: reference to the storage object, duration, and processing statusKeep the event table append-only. It grows quickly, but it is the single most valuable table you will have when debugging intermittent problems.
Row-level security should answer one question: can this user join this room right now? Encode it as a policy rather than scattering checks across handlers. Pair that with retention rules — raw quality samples rarely need to live longer than a few weeks, while room membership records often need to persist for billing or compliance.
The browser side is where most first attempts fail, usually because permissions and negotiation are treated as an afterthought.
Request audio and video together unless you have a reason not to; splitting the requests produces inconsistent permission prompts. Enumerate devices after the first grant, not before, because labels are hidden until then. Persist the user's preferred device identifiers so returning users do not have to reselect a webcam every session.
Always handle the failure path explicitly. A denied camera permission is not an error state; it is a product state that needs its own UI, including an audio-only fallback when that is acceptable.
The handshake itself is mechanical once you internalize the sequence:
connected confirms media is flowing.Two practical rules save time. First, queue remote ICE candidates that arrive before the remote description is set. Second, treat iceConnectionState and connectionState as different signals — one can recover while the other looks broken.
Swapping a track is more common than people expect. Use transceivers and replaceTrack rather than tearing down the connection. Muting should disable the track, not remove it, so renegotiation is unnecessary. For screen sharing, add a separate video transceiver so the camera stream can be restored without a full reconnect.
Data channels carry arbitrary messages over the same peer connection. They are the reason you rarely need a second transport for in-call interaction.
Data channels can be configured as reliable and ordered, unreliable and unordered, or something in between through retransmit settings. Chat messages and control commands need reliability. Cursor positions, reactions, and live annotations are better off unreliable: a dropped cursor update is invisible, while a delayed one is worse than none.
The strongest uses of data channels are adjacent to media rather than part of it: in-call chat, raise-hand signals, shared timers, collaborative document editing, and lightweight file transfer of small assets. Because they ride the same ICE path as audio and video, they inherit the same NAT traversal work you already paid for.
Once calls are stable, the interesting question becomes what the media can do next. Two pipelines matter, and they have very different engineering constraints.
Live analysis runs inside the call and must keep latency low. Frame sampling every few seconds, audio transcription with partial results, and lightweight classification models fit here. Anything heavy — generation, rendering, or multi-pass editing — belongs in post-call processing where you can batch and retry.
A clean split: the live path produces events and transcripts, the offline path consumes recordings and produces finished assets.
For video understanding, sample frames rather than streaming every one. One frame per second is usually enough for scene detection or presence checks; one every five to ten seconds is enough for summaries. For audio, stream to a transcription service in chunks and reconcile overlapping words at the boundaries.
Store the outputs as structured records keyed to timestamps. That turns a call recording from a blob into a searchable timeline, which is what any downstream feature actually needs.
Recorded calls are excellent raw material for generated video. A typical workflow looks like this:
The assembly step should be reproducible from a job specification. Store that specification, not just the output, so you can regenerate the same clip when a model improves or a format changes.
Most failures here are operational, not algorithmic: no clear ownership of long-running jobs, no retry policy for failed generations, and no schema tying a generated asset back to the call it came from. Treat generation as a queue with idempotent jobs, and the AI layer becomes just another worker in your system.
Calls fail in ways that unit tests never see. Plan for measurement from the first release.
Somewhere between 8 and 20 percent of users will be unable to connect directly and will need a relay. Run TURN servers with TLS on port 443 so they survive corporate firewalls, and monitor relay usage as a percentage of sessions. A sudden spike usually means certificate expiry or a misconfigured STUN list.
Sample these from getStats() on an interval and store aggregated values. Raw per-second samples are rarely worth the storage.
Test the happy path, then deliberately break it: deny camera permission, disable the network mid-call, switch from Wi-Fi to cellular, join the same room from two tabs, and reload during an active session. Add a synthetic load test with headless browsers so you know how many concurrent rooms a single node supports before you learn it from users.
Building signaling before defining room state. You end up with socket handlers that each know a little about rooms. Define the state machine and persistence first, then let sockets be a thin transport.
Ignoring the reconnection path. Mobile networks change constantly. Implement automatic rejoin, and decide whether a returning participant resumes their existing session or starts a new one.
Treating recording as a checkbox. Cloud recording has layout, storage, and processing implications. Decide the composited layout up front; you cannot re-derive it later from a single flattened file.
Skipping TURN in staging. Everything works on a corporate LAN. Test from a phone hotspot with a VPN enabled before you call the integration done.
Coupling AI processing to the call. A slow transcription job should never degrade call quality. Keep generation and analysis behind a queue, with backpressure limits.
Storing no events. Without an event log, intermittent bugs stay intermittent. The append-only table you added for debugging will pay for itself within a month.
Do I need a server at all for one-to-one calls? You still need signaling to exchange offers, answers, and candidates, plus TURN for restrictive networks. Everything else can stay peer-to-peer.
How many participants before peer-to-peer stops working? Practically, four. Beyond that, upstream bandwidth and encoding overhead grow linearly per peer, and quality drops for everyone.
Should I record locally or in the cloud? Local capture is cheap and private but depends on client reliability. Cloud composition is consistent and easier to process downstream. Many products use local capture as a fallback when cloud recording fails.
Can I run transcription during the call? Yes, with chunked streaming and partial results. Keep the model small, and never block media on an analysis response.
What is the minimum viable observability? Join success rate, time to first frame, and reconnection counts. Three numbers will catch the majority of real-world regressions.
How do I test for scale without a large audience? Headless browser fleets simulating rooms with synthetic media give you a rough ceiling per node. Treat it as an order-of-magnitude estimate, not a guarantee.
Ship the smallest version that includes signaling, TURN, and the event log. Those three pieces are what make the second month of a video calling feature calm instead of chaotic.

Alexander
Guida pratica al montaggio video rapido con AI: transizioni fluide, software, workflow, coerenza visiva, errori da evitare e FAQ operative.
A practical guide to planning, generating, editing, and finishing AI-assisted videos with consistent characters, clear shot lists, and reliable review loops.
Build a repeatable AI video post-production pipeline: organize assets, cut story-first, design transitions, refine audio, and review versions calmly.