📹 Video Calls
This guide explains how to set up TURN relay for YSeries video calls.
YSeries supports two RTC relay providers:
- Cloudflare TURN (managed, API-generated ICE servers)
- Coturn (self-hosted TURN, TURN REST shared-secret credentials)
If you don't configure a relay provider, video calls may still work on open networks, but NAT/firewall users will often get black screens / frozen video.
Choose a Provider (Quick)
- Pick Cloudflare if you want the easiest setup and don't want to host TURN yourself.
- Pick Coturn if you want full control, self-hosting, or you already run your own TURN server.
What is TURN?
TURN (Traversal Using Relays around NAT) relays WebRTC media when direct peer-to-peer connectivity fails.
Benefits of using a TURN relay:
- ✅ Better reliability for restrictive networks (NAT/firewalls)
- ✅ Time-limited/dynamic credentials (more secure than static TURN users)
Prerequisites
- Access to your FiveM server configuration files
- Ability to restart your server/resource after configuration changes
Common Config (Applies to Both)
The provider selection lives in config/config.upload.lua:
luaConfig.RTCRelay = {} Config.RTCRelay.Enabled = true -- Enable dynamic RTC relay Config.RTCRelay.Provider = "cloudflare" -- Options: "cloudflare", "coturn" Config.RTCRelay.StripStun = false -- Keep STUN servers (recommended) Config.RTCRelay.CredentialTTL = 86400 -- Credential TTL in seconds (max: 86400)
After setting a provider, continue with the matching section below.
Provider: Cloudflare (Managed TURN)
Cloudflare TURN generates ICE servers via API and automatically handles credential creation/revocation.
Cloudflare benefits:
- ✅ Free tier: 1,000 GB of data per month
- ✅ Globally distributed servers for low latency
Step 1: Create Cloudflare Account
- Visit cloudflare.com and sign up for a free account
- Complete the account verification process
Step 2: Generate TURN Credentials
- Log in to your Cloudflare dashboard
- Navigate to Realtime → TURN Server(Search in the search bar for "TURN Server")
- Click Create to generate a new TURN key
- Copy the following credentials:
- Turn Token ID (a long string)
- API Token (another long string)
⚠️ Important: Keep these credentials secure and never share them publicly.
Step 3: Configure Server Credentials
Open server/apiKeys.lua and locate the RTCRelaySecrets section:
luaRTCRelaySecrets = { token = GetConvar("yseriesRTCRelayToken", nil), -- Turn Token ID from Cloudflare apiKey = GetConvar("yseriesRTCRelayApiKey", nil) -- API Token from Cloudflare }
Option A: Using Convars (Recommended)
Add these lines to your server.cfg:
Codeset yseriesRTCRelayToken "YOUR_TURN_TOKEN_ID_HERE" set yseriesRTCRelayApiKey "YOUR_API_TOKEN_HERE"
Option B: Direct Configuration
Replace nil with your credentials directly in apiKeys.lua:
luaRTCRelaySecrets = { token = "YOUR_TURN_TOKEN_ID_HERE", apiKey = "YOUR_API_TOKEN_HERE" }
Step 4: Enable Cloudflare Provider
In config/config.upload.lua:
luaConfig.RTCRelay.Enabled = true Config.RTCRelay.Provider = "cloudflare"
Step 5: Restart Server/Resource
- Save all configuration files
- Restart your FiveM server
Provider: Coturn (Self-Hosted TURN)
Coturn uses TURN REST shared-secret credentials, so each player gets time-limited TURN login details. The shared secret never goes to the client/UI.
Step 1: Install + Configure Coturn
Set up coturn with:
lt-cred-mechuse-auth-secretstatic-auth-secret=<sharedSecret>
Your TURN server must be reachable from the internet and your firewall must allow the ports you use (commonly 3478 for TURN and 5349 for TURNS).
Step 2: Configure Coturn URLs (No Secrets)
In config/config.upload.lua, set the URLs your clients should use:
luaConfig.RTCRelay.Coturn = { Urls = { "turn:turn.example.com:3478?transport=udp", "turn:turn.example.com:3478?transport=tcp", "turns:turn.example.com:5349?transport=tcp", }, }
Notes:
- Use your domain or public IP.
- Use
turns:only if you configured TLS on coturn.
Step 3: Configure the Shared Secret (server.cfg)
Add this to your server.cfg (recommended, do not hardcode secrets in Lua):
Codeset yseriesRTCRelayCoturnSecret "REPLACE_WITH_SHARED_SECRET"
Step 4: Enable Coturn Provider
In config/config.upload.lua:
luaConfig.RTCRelay.Enabled = true Config.RTCRelay.Provider = "coturn"
Step 5: Restart Server/Resource
Save changes and restart your server (or at least restart the yseries resource).
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
Enabled | boolean | false | Enable/disable dynamic RTC relay |
Provider | string | "cloudflare" | TURN service provider: "cloudflare" or "coturn" |
StripStun | boolean | false | Remove STUN servers when using relay (not recommended) |
CredentialTTL | number | 86400 | Credential lifetime in seconds (max: 86400 = 24 hours) |
Coturn.Urls | table | {} | List of TURN/TURNS URLs (only used when Provider=coturn) |
How It Works
- When a player initiates a video call, the system requests fresh TURN credentials from the configured provider
- Credentials are generated with a configurable expiration time (default: 24 hours)
- These credentials are used to establish the WebRTC connection
- When the call ends or player disconnects:
- Cloudflare credentials are revoked automatically
- Coturn credentials simply expire (TURN REST)
- If the provider is unavailable or misconfigured, the system falls back to static ICE servers (less reliable)
Troubleshooting
Video Calls Not Working
Check 1: Verify Configuration
- Ensure
Config.RTCRelay.Enabled = trueinconfig/config.upload.lua - Ensure
Config.RTCRelay.Providermatches what you set up (cloudflareorcoturn) - Cloudflare: verify credentials are set correctly in
server/apiKeys.lua(orserver.cfgconvars) - Coturn: verify
Config.RTCRelay.Coturn.Urlsis not empty and theyseriesRTCRelayCoturnSecretconvar is set
Check 2: Server Console
- Look for error messages about missing credentials
- Cloudflare: check for API errors (status codes other than 201)
- Coturn: check for missing secret / empty URLs errors
Check 3: Credentials
- Cloudflare: verify your Turn Token ID and API Token are correct and not revoked
- Coturn: verify the
static-auth-secretin your coturn config matchesyseriesRTCRelayCoturnSecret
Common Error Messages
"RTC Relay is enabled but credentials are missing"
- Solution: Add your credentials to
server/apiKeys.luaor set convars inserver.cfg
"RTC Relay (coturn) is enabled but shared secret is missing"
- Solution: add
set yseriesRTCRelayCoturnSecret "..."toserver.cfgand restart
"RTC Relay (coturn) is enabled but Config.RTCRelay.Coturn.Urls is empty"
- Solution: set
Config.RTCRelay.Coturn.Urls = { "turn:...", "turns:..." }inconfig/config.upload.lua
"Failed to get RTC relay credentials from Cloudflare. Status: 401"
- Solution: Your API Token is incorrect or expired. Generate a new one in Cloudflare dashboard.
"Failed to get RTC relay credentials from Cloudflare. Status: 404"
- Solution: Your Turn Token ID is incorrect. Check it in Cloudflare dashboard.
Fallback Behavior
If the configured TURN provider is unavailable or disabled, the system automatically uses the default ICE servers (this is unreliable and it can cause issues like black screen, frozen video calls, etc.). Video calls may still work, but will have reduced reliability in restrictive network environments.
Monitoring Usage
Cloudflare
- Log in to Cloudflare dashboard
- Navigate to Realtime → TURN Server
- View usage statistics and monitor data consumption
- Free tier includes 1,000 GB per month; additional usage costs $0.05 per GB
Coturn
Monitor your server bandwidth and coturn logs. Because coturn is self-hosted, usage/cost depends entirely on your hosting provider.
Security Best Practices
- ✅ Never commit credentials to version control
- ✅ Use convars in
server.cfginstead of hardcoding in files - ✅ Rotate credentials periodically
- ✅ Monitor usage for unusual activity
- ✅ Cloudflare: keep your account secure (2FA recommended)
- ✅ Coturn: keep your TURN host secured and patched
Additional Resources
Support
If you encounter issues not covered in this guide:
- Check server console logs for detailed error messages
- Enable
Config.DebugPrint = truefor additional debugging information - Verify your provider setup:
- Cloudflare: account status, TURN key validity, API token permissions
- Coturn: public reachability, firewall rules, and shared secret match