Skip to main content
Realtime endpoints use WebSockets for bidirectional communication over a persistent connection. Once a client connects, it can send multiple inputs and receive results without the overhead of establishing new connections for each request. This makes them ideal for interactive applications like real-time image editing, live camera filters, or game-like experiences where latency between requests needs to be minimal. You define a realtime endpoint using the @fal.realtime("/realtime") decorator, which uses fal’s binary msgpack protocol for efficient serialization. Callers connect using the realtime() method in the fal client SDKs. For one-way progressive output from a single request (like showing diffusion steps), use Streaming Endpoints instead — they use SSE and are simpler when you don’t need bidirectional communication.
WebSocket endpoints are not currently testable on the fal Playground. You can monitor your WebSocket endpoint activity through the Logs page in the fal dashboard.

How Realtime Works

Under a fal.App, the @fal.realtime() decorator makes your endpoint compatible with fal’s real-time clients. It uses fal’s binary msgpack protocol for efficient serialization and eliminates connection establishing overhead for repeated requests.
Important: The fal_client.realtime() method connects to the /realtime path on your app by default. Use @fal.realtime("/realtime") so that clients connect without extra configuration. If your endpoint uses a different path, pass that path to the client with the path option. See Custom WebSocket Path.
For power users who want to build stateful applications with their own real-time protocol, a @fal.endpoint can be initialized with is_websocket=True flag and the underlying function will receive the raw WebSocket connection and can choose to use it however it wants.

Server-Side Implementation

Here’s an example of a fal app with both a regular HTTP endpoint and a WebSocket endpoint:

Buffering and dropped inputs

A realtime client can send inputs faster than the app processes them. Examples are webcam frames and slider updates. Use the buffering parameter to control the input buffer:
  • A unary endpoint receives one input and returns one output, like generate_rt above. It keeps at most buffering unprocessed inputs for each connection. When the input buffer is full, a new input replaces the oldest input. The app always works on recent inputs. Without buffering, the app keeps every input and processes the inputs in order.
  • All realtime endpoints use an outgoing queue that holds twice the buffering value, or 2 when you do not set it. When this queue is full, the app sends outputs directly. These outputs can arrive out of order.
Set a small value (1 or 2) for live inputs where only the latest input is important. Do not set buffering when the app must process every input. Two related parameters control the session:
  • max_batch_size passes up to this number of inputs from the input buffer to a unary function in one call.
  • session_timeout ends the session when the client sends no message for this number of seconds.

Client-Side Connection

Connecting to @fal.realtime() Endpoints

For endpoints decorated with @fal.realtime(), use fal_client.realtime() or fal_client.realtime_async(). These methods handle serialization automatically using fal’s binary protocol:

Connecting to Raw WebSocket Endpoints

For endpoints using is_websocket=True, use fal_client.ws_connect() or fal_client.ws_connect_async() for direct WebSocket access:
  • For @fal.realtime() endpoints: Use fal_client.realtime() - serialization is handled automatically.
  • For raw is_websocket=True endpoints: Use fal_client.ws_connect() with the path parameter to specify the endpoint path.
A shared WebSocket endpoint can declare billing on its 101 upgrade response. See Define billable units.

WebRTC Transport

For applications that need direct video/audio streaming (webcam feeds, live game rendering), you can use WebRTC as the transport layer on top of fal’s WebSocket infrastructure. WebRTC provides lower latency for media streams compared to sending frames over msgpack. The low-level pattern uses a bidirectional @fal.realtime("/realtime") endpoint for WebRTC signaling. The endpoint receives an async iterator of signaling messages (offer, answer, and ICE candidates) and yields its replies. The media then flows between the browser and your runner over WebRTC. If no direct path is available, the media goes through a TURN relay.
For new apps, use the experimental fal WMA (World Model Accelerator). It handles the signaling, ICE, tracks, and frame pacing for you. The examples below use WMA instead of this low-level pattern.

Real-time World Model

Deploy a keyboard-controlled world model with WebRTC video streaming

Real-time Video Style Transfer

Restyle a live webcam stream with a text prompt

Real-time Voice Chat

Talk to a full-duplex speech model over WebRTC audio

Next Steps

Streaming Endpoints

Stream progressive results (image previews, video updates) using SSE

Real-time Client Docs

Client library documentation for realtime connections