batondocs← SiteSign in
Help/Troubleshooting

Troubleshooting

The real, common failure modes — what causes them, how to confirm, and how to fix.

TURN isn't being used / only host candidates appear

If chrome://webrtc-internals shows only host (internal) candidates, the relay never enters negotiation. Most often this is a server advertising an internal IP.

  • Confirm your iceServers actually reached the RTCPeerConnection (log the config you pass in).
  • On LiveKit, check rtc.use_external_ip and the node's advertised address — an SFU behind NAT advertising a private IP suppresses relay candidates.
  • Force the relay path while testing with iceTransportPolicy: "relay"; if nothing connects, the credentials or URLs are wrong, not the network.

No relay candidates over TCP or TLS

UDP works on your network but you see no candidates from the turn:…?transport=tcp or turns:…:443 URLs.

  • Verify the client can reach relay.usebaton.io:443 outbound (many strict networks allow only outbound 443).
  • Ensure all four URLs are present in the array you pass — a trimmed array silently drops the TLS path.
  • Re-test from the restricted network itself; office and home networks behave very differently.

Works on STUN but fails behind a strict corporate / hospital firewall

Direct/STUN connections succeed everywhere except inside locked-down enterprise or hospital networks. Those networks block UDP and inspect traffic (DPI), so plain TURN is filtered.

The fix is the turns:relay.usebaton.io:443?transport=tcp endpoint: TURN over TLS on 443 looks like ordinary HTTPS and traverses deny-all / DPI firewalls. Make sure it's in your iceServers and reachable — this is the endpoint that matters most for enterprise clients.

How do I confirm the relay is actually used?

  • Open chrome://webrtc-internals during a call and read the selected candidate pair — look for typ relay with the relay.usebaton.io address.
  • Use the WebRTC Trickle ICE test tool: paste your iceServers and check that a relay candidate is gathered.
  • Set iceTransportPolicy: "relay" in a test build so only relayed candidates are allowed — if the call connects, the relay path is healthy.

Credentials expired / 401

A credential stops working at the Unix expiry encoded in its username.

  • Mint a fresh pair from the credentials API before expiry; for long calls, refresh ahead of the TTL.
  • If a brand-new credential is rejected as expired, suspect clock skew — put your servers on NTP.
  • Never cache one credential pair across users or for longer than its TTL.

Allowlisting our IPs with a client's firewall team

Enterprise clients often need to approve fixed relay IPs once. Baton's relay hostnames map to stable, allowlistable IPs, so you can share them with a firewall team and they won't change underneath you.

  • Share the relay hostname (relay.usebaton.io) and its static IPs, plus the ports: 3478 (UDP/TCP) and 443 (TLS).
  • For strict outbound-443-only networks, turns on 443 is usually all that needs approving.
Static IPs

The exact static IP list for each region is provided with your project during onboarding. Ask the team and we'll send the current mapping to hand to your client's firewall admins.