Pular para o conteúdo principal

WebTransport

WebTransport provides low latency, bidirectional communication using Centrifugo with automatic WebSocket fallback.

Try it Online

Open WebTransport Dashboard — See real-time streaming in action!

Overview

PropertyValue
ServerCentrifugo v6
Primary TransportWebTransport (QUIC/HTTP/3)
Fallback TransportWebSocket (TCP)
Latency~10ms
DirectionBidirectional
ScalingHorizontal via Redis
Browser SupportAll browsers (WebSocket fallback)

Architecture

WebTransport is implemented using Centrifugo, a real-time messaging server that provides WebTransport with automatic WebSocket fallback:

┌─────────────────────────────────────────────────────────────────────────┐
│ WEBTRANSPORT ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Consumer │────▶│ Centrifugo │────▶│ Clients │ │
│ │ (Publisher) │ │ (Server) │ │ (Browsers) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │ │ │ │
│ │ HTTP API │ Redis │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ /api/publish │ │ Pub/Sub │ │ WebTransport │ │
│ │ POST + X-API- │ │ + History │ │ or WebSocket │ │
│ │ Key │ │ │ │ (automatic) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘

Why Centrifugo for WebTransport?

FeatureNative WebTransportCentrifugo
Auto ReconnectionManualBuilt-in
Fallback TransportNoYes (WT → WS)
History/RecoveryNoYes
Horizontal ScalingComplexBuilt-in (Redis)
Browser SupportChrome/Firefox onlyAll browsers
TLS/CertificatesManual (certmagic)Standard

Endpoints

TransportURL
WebTransporthttps://wt.datastream.hypetech.games/connection/webtransport
WebSocket (fallback)wss://wt.datastream.hypetech.games/connection/websocket

Client Implementation

JavaScript (Browser)

<script src="https://unpkg.com/centrifuge@5/dist/centrifuge.js"></script>
<script>
const CENTRIFUGO_WS_URL = 'wss://wt.datastream.hypetech.games/connection/websocket';
const CENTRIFUGO_WT_URL = 'https://wt.datastream.hypetech.games/connection/webtransport';

async function connect() {
const hasWebTransport = typeof WebTransport !== 'undefined';

// Configure transports with automatic fallback
const transports = [];

// Try WebTransport first if available
if (hasWebTransport) {
transports.push({
transport: 'webtransport',
endpoint: CENTRIFUGO_WT_URL
});
}

// Always add WebSocket as fallback
transports.push({
transport: 'websocket',
endpoint: CENTRIFUGO_WS_URL
});

const centrifuge = new Centrifuge(transports);

centrifuge.on('connected', (ctx) => {
console.log(`Connected via ${ctx.transport}`);
});

centrifuge.on('disconnected', () => {
console.log('Disconnected');
});

centrifuge.connect();
return centrifuge;
}

function subscribe(centrifuge, gameSlug, onMessage) {
const channel = `stream:${gameSlug}`;
const sub = centrifuge.newSubscription(channel);

sub.on('publication', (ctx) => {
onMessage(ctx.data);
});

sub.subscribe();
return sub;
}

// Usage
const centrifuge = await connect();
subscribe(centrifuge, 'crash', (data) => {
console.log('Round result:', data);
});
</script>

React Hook

import { useState, useEffect } from 'react';
import { Centrifuge } from 'centrifuge';

const CENTRIFUGO_WS_URL = 'wss://wt.datastream.hypetech.games/connection/websocket';
const CENTRIFUGO_WT_URL = 'https://wt.datastream.hypetech.games/connection/webtransport';

function useWebTransport(channels) {
const [data, setData] = useState({});
const [connected, setConnected] = useState(false);
const [transport, setTransport] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
const hasWebTransport = typeof WebTransport !== 'undefined';
const transports = [];

if (hasWebTransport) {
transports.push({ transport: 'webtransport', endpoint: CENTRIFUGO_WT_URL });
}
transports.push({ transport: 'websocket', endpoint: CENTRIFUGO_WS_URL });

const centrifuge = new Centrifuge(transports);

centrifuge.on('connected', (ctx) => {
setConnected(true);
setTransport(ctx.transport);
});

centrifuge.on('disconnected', () => {
setConnected(false);
});

centrifuge.on('error', (ctx) => {
setError(ctx.error?.message || 'Unknown error');
});

// Subscribe to channels
const subscriptions = channels.map(channel => {
const sub = centrifuge.newSubscription(channel);
sub.on('publication', (ctx) => {
setData(prev => ({
...prev,
[channel]: ctx.data
}));
});
sub.subscribe();
return sub;
});

centrifuge.connect();

return () => {
subscriptions.forEach(sub => sub.unsubscribe());
centrifuge.disconnect();
};
}, [channels.join(',')]);

return { data, connected, transport, error };
}

// Usage
function GameDashboard() {
const { data, connected, transport } = useWebTransport([
'stream:crash',
'stream:double'
]);

return (
<div>
<div>Status: {connected ? `Connected (${transport})` : 'Disconnected'}</div>
{Object.entries(data).map(([channel, result]) => (
<div key={channel}>
<h3>{channel}</h3>
<pre>{JSON.stringify(result, null, 2)}</pre>
</div>
))}
</div>
);
}

Channel Naming

Channels follow the format: stream:{game_slug}

ChannelDescription
stream:crashCrash game results
stream:doubleDouble game results
stream:aviadorAviador game results
stream:wall-streetWall Street game results
stream:fortune-tigerFortune Tiger game results

Browser Support

BrowserWebTransportWebSocket Fallback
Chrome 97+YesYes
Edge 97+YesYes
Firefox 114+YesYes
SafariNoYes
iOS SafariNoYes
Automatic Fallback

When WebTransport is not available (Safari, iOS, or UDP blocked), the client automatically falls back to WebSocket. No code changes required.

Performance Comparison

MetricWebSocketWebTransport
Connection time1 RTT0-1 RTT
Message latency5-10ms1-5ms
Head-of-line blockingYesNo
Connection migrationNoYes

Infrastructure

WebTransport via Centrifugo is deployed on Kubernetes with:

  • Centrifugo v6 with WebTransport enabled
  • AWS NLB for TCP (WebSocket) and UDP (QUIC) traffic
  • cert-manager for TLS certificates
  • Redis for horizontal scaling

For detailed infrastructure configuration, see the Centrifugo documentation.

Troubleshooting

WebTransport Not Connecting

Cause: Browser doesn't support WebTransport or UDP is blocked

Solution: The client automatically falls back to WebSocket. Check the transport value in the connection event.

"unknown channel" Error

Cause: Channel namespace not configured in Centrifugo

Solution: Use the correct channel format: stream:{game_slug}

High Latency

Cause: Falling back to WebSocket instead of WebTransport

Solution:

  1. Use Chrome or Firefox
  2. Ensure UDP traffic is not blocked by firewall
  3. Check if the server supports WebTransport

When to Use WebTransport

Use WebTransport (via Centrifugo) when:

  • You need automatic reconnection
  • You want horizontal scaling
  • You need universal browser support (with fallback)
  • You want managed infrastructure

Consider native WebSocket when:

  • You need maximum control
  • You have simple single-server deployment
  • You don't need reconnection logic

Resources