Transport & Connectivity
Overshoot uses LiveKit as its default transport layer. When you create a stream, the server sets up a LiveKit room and gives you a URL and token to connect — no SDP, no TURN servers, no ICE candidates to manage.
Source Types
There are three ways to send video to Overshoot:
| Source | API field | Who manages transport? | When to use |
|---|---|---|---|
| Native (default) | Omit source, or { type: "native" } | Server creates LiveKit room + tokens | Most use cases — simplest option |
| WebRTC (legacy) | { type: "webrtc", sdp: "..." } | Client does WebRTC handshake | Legacy clients, backwards compatibility |
| LiveKit (user-managed) | { type: "livekit", url: "...", token: "..." } | User provides their own LiveKit room | Advanced users with their own LiveKit infrastructure |
Recommendation: Use native transport (the default). It's simpler, more reliable, and requires no transport configuration.
Native Transport
The default. Just create a stream without a source field:
POST /streams
{
"mode": "frame",
"processing": { "interval_seconds": 2.0 },
"inference": {
"prompt": "Describe what you see",
"model": "Qwen/Qwen3.5-9B"
}
}The response includes a LiveKit URL and token:
{
"stream_id": "abc-123",
"livekit": {
"url": "wss://livekit.overshoot.ai",
"token": "<client JWT>"
},
"lease": { "ttl_seconds": 45 },
"webrtc": null,
"turn_servers": null
}Connect to the LiveKit room and publish your video track — that's it.
WebRTC (Legacy)
The original transport. You create a WebRTC offer SDP locally and send it in the request:
{
"source": { "type": "webrtc", "sdp": "v=0\r\n..." },
...
}The response includes an SDP answer and TURN server credentials. You complete the WebRTC handshake yourself.
Note: WebRTC streams don't support automatic reconnection or deploy resilience. Consider migrating to native transport.
User-Managed LiveKit
For advanced users who run their own LiveKit infrastructure:
{
"source": {
"type": "livekit",
"url": "wss://your-livekit-server.example.com",
"token": "your-livekit-token"
},
...
}You're responsible for room creation, token generation, and publishing video.
SDK Integration
If you're using the Overshoot SDK, you don't need to think about transport at all. Both SDKs use native transport by default:
const vision = new RealtimeVision({
apiKey: 'your-api-key',
model: 'Qwen/Qwen3.5-9B',
prompt: 'Describe what you see',
source: { type: 'camera', cameraFacing: 'environment' },
onResult: (result) => console.log(result.result)
})
await vision.start()
// SDK automatically: creates stream -> connects to LiveKit -> publishes video -> handles keepalive + token refreshManual Integration (Without SDK)
If you're integrating directly with the API:
- Create stream —
POST /streams(no source field) - Connect to LiveKit — use the
livekit-clientSDK with the returned URL and token - Publish video — publish your video track to the room
- Receive results — connect to
WS /ws/streams/{stream_id}as usual - Keepalive — send keepalives as normal; each response includes a fresh
livekit_token
import { Room, Track } from 'livekit-client'
// 1. Create stream
const res = await fetch('https://api.overshoot.ai/v0.2/streams', {
method: 'POST',
headers: {
'Authorization': 'Bearer your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
mode: 'frame',
processing: { interval_seconds: 2.0 },
inference: {
prompt: 'Describe what you see',
model: 'Qwen/Qwen3.5-9B'
}
})
})
const { stream_id, livekit } = await res.json()
// 2. Connect to LiveKit room
const room = new Room({ adaptiveStream: false, dynacast: false })
await room.connect(livekit.url, livekit.token)
// 3. Publish video
const stream = await navigator.mediaDevices.getUserMedia({ video: true })
const videoTrack = stream.getVideoTracks()[0]
await room.localParticipant.publishTrack(videoTrack, {
source: Track.Source.Camera,
simulcast: false,
})
// 4. Connect WebSocket for results (same as before)
// 5. Send keepalives — store the fresh livekit_token from each responseToken Lifecycle
Native streams use short-lived LiveKit tokens:
- Initial token: Returned in the
POST /streamsresponse, 5-minute TTL - Refreshed tokens: Each keepalive response includes a fresh
livekit_token - Tokens are always refreshed well before they expire via the regular keepalive cycle
The SDK handles token refresh automatically. If you're integrating manually, store the fresh token from each keepalive response — livekit-client will use it when it needs to reconnect internally.
Reliability & Reconnection
Native transport provides built-in reliability features:
Automatic Reconnection
Network transitions (WiFi to cellular), temporary disconnections, and ICE restarts are handled automatically. You don't need to implement any reconnection logic.
Deploy Resilience
Native streams survive server-side deploys with zero disruption to the client:
- Your client stays connected to the LiveKit room throughout the deploy
- On the next keepalive, the server automatically recovers and resumes inference
- No action needed on the client side
This only works for native streams. Legacy WebRTC streams do not survive server restarts.
Automatic Cleanup
If a client disconnects without calling stop(), resources are cleaned up automatically.
Comparison
| Feature | Native (default) | WebRTC (legacy) | LiveKit (user-managed) |
|---|---|---|---|
| Setup complexity | Minimal | SDP + ICE + TURN | Requires own LiveKit infra |
| Automatic reconnection | Yes | No | Depends on your setup |
| Survives server deploys | Yes | No | Depends on your setup |
| Token refresh | Automatic via keepalive | N/A | You manage tokens |
| LiveKit account needed | No | No | Yes |