Docs

TURN (ICE)

Updated

On this page

The TURN API returns STUN and TURN credentials for RTCPeerConnection. STUN helps peers discover network addresses; TURN provides a relay path when a direct connection is not possible. TURN substantially improves connectivity on restrictive networks, but no relay service can guarantee that every network or application configuration will connect.

Keep the secret server-side: call the Xirsys REST API from a trusted backend and return only the temporary iceServers data to your client.

Request Temporary Credentials

PUT/_turn/{channel}?webrtc=1

Send PUT /_turn/{channel}?webrtc=1 with HTTP Basic authentication. The exact webrtc=1 flag returns v.iceServers as the standard WebRTC array, ready to pass to RTCPeerConnection. Its ICE server object already contains urls as an array, so format=urls is not needed.

RequestShell
curl --request PUT \
  --user "$XIRSYS_IDENT:$XIRSYS_SECRET" \
  "https://global.xirsys.net/_turn/myChannel?webrtc=1&expire=60"
ResponseJSON
{
  "s": "ok",
  "v": {
    "iceServers": [
      {
        "username": "temporary-username",
        "credential": "temporary-credential",
        "urls": [
          "stun:xx-turn1.xirsys.com",
          "turn:xx-turn1.xirsys.com:80?transport=udp",
          "turn:xx-turn1.xirsys.com:3478?transport=udp",
          "turn:xx-turn1.xirsys.com:80?transport=tcp",
          "turn:xx-turn1.xirsys.com:3478?transport=tcp",
          "turns:xx-turn1.xirsys.com:443?transport=tcp",
          "turns:xx-turn1.xirsys.com:5349?transport=tcp"
        ]
      }
    ]
  }
}

expire is the credential lifetime in seconds. It defaults to 60 seconds and is capped at 21,600 seconds (six hours). The lifetime controls how long the credentials can authenticate a new TURN allocation; it does not automatically end an established call when the credential reaches that age.

Xirsys keeps its outer {s, v} response envelope. Read the standard array from data.v.iceServers and pass it directly to WebRTC:

JavaScriptJS
const iceServers = data.v.iceServers;
const peerConnection = new RTCPeerConnection({ iceServers });

Response format compatibility:

ParametersResponse in v.iceServers
webrtc=1Standard one-element WebRTC array.
webrtc=1&format=urlsSame as webrtc=1; format=urls is redundant.
webrtc=0&format=urlsExisting single ICE server object.
format=urlsExisting single ICE server object; wrap it in an array before passing it to WebRTC.
No response-format parameterExisting seven-object legacy response.

Use webrtc=1 by itself when you want the standard WebRTC schema. Only the value 1 selects this format; do not substitute true, yes, or urls=1. Request fresh credentials shortly before creating a new peer connection or retrying an allocation.

Route TURN for the End User

PUT/_turn/{channel}?webrtc=1&geo=1JSON body: user_ip

A normal request to global.xirsys.net is routed according to the location of the system making that request. However, to provide the closest and fastest data center for your end user, enable geo routing on the TURN request and provide the user's public IP address:

RequestShell
curl --request PUT \
  --user "$XIRSYS_IDENT:$XIRSYS_SECRET" \
  --header "Content-Type: application/json" \
  --data '{"user_ip":"203.0.113.42"}' \
  "https://global.xirsys.net/_turn/myChannel?webrtc=1&geo=1&expire=60"

203.0.113.42 is a documentation-only placeholder; replace it with the actual trusted public IP. Both inputs are required: add geo=1 to the query string and send user_ip in the JSON body. Derive the value from authenticated request context or a trusted proxy chain, validate that it is a public IP address, and do not accept an arbitrary client-supplied value.

If user_ip is missing, private, invalid, or cannot be geolocated, Xirsys falls back to normal TURN routing. New Free accounts can use geo routing and all available regions during their first 30 days. After the trial, Free accounts use their assigned home TURN region even when geo=1 and user_ip are provided. Paid accounts retain geo routing. The response schema is unchanged.

End-user IP privacy: The user_ip value is strictly transient. Xirsys uses it only in memory to select a TURN region for the current request, then discards it. It is not persisted, stored, cached, or logged anywhere within the Xirsys service, and it is not included in forwarded request bodies.

Node.js Backend Example

This example uses the built-in fetch available in Node.js 18 and later:

Node.js backendJS
async function getIceServers(trustedEndUserPublicIp) {
  const channel = process.env.XIRSYS_CHANNEL;
  const encodedChannel = encodeURIComponent(channel);
  const auth = Buffer.from(
    `${process.env.XIRSYS_IDENT}:${process.env.XIRSYS_SECRET}`
  ).toString('base64');

  const useGeo = Boolean(trustedEndUserPublicIp);
  const url =
    `https://global.xirsys.net/_turn/${encodedChannel}` +
    `?webrtc=1&expire=60${useGeo ? '&geo=1' : ''}`;

  const response = await fetch(url, {
    method: 'PUT',
    headers: {
      Authorization: `Basic ${auth}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      ...(useGeo ? { user_ip: trustedEndUserPublicIp } : {})
    })
  });
  const data = await response.json();

  if (!response.ok || data.s !== 'ok') {
    throw new Error(`Xirsys TURN request failed (${response.status})`);
  }

  return data.v.iceServers;
}

Test Relay-Only Connectivity

To verify that your application can use a relay path, set iceTransportPolicy: "relay" while testing:

JavaScriptJS
const peerConnection = new RTCPeerConnection({
  iceServers,
  iceTransportPolicy: 'relay'
});

This tells the browser to use relay candidates only. It is useful for diagnostics and for products that intentionally require relaying, but it increases relay traffic and may add latency. Most applications should use the default "all" policy so WebRTC can prefer a direct path and fall back to TURN.

Network and Firewall Requirements

Allow outbound DNS and connectivity to the hostnames returned by the API. Common returned transports use:

  • TURN over UDP or TCP on ports 80 and 3478.
  • TURN over TLS on TCP ports 443 and 5349.

Do not describe these as HTTP or HTTPS ports; the protocols are TURN and TURN over TLS. If your organization allowlists destination IPs, use the maintained IP Allowlist and monitor it for changes.

Static Credentials

Static TURN credentials are persistent until rotated or deleted. Use them only in trusted, controlled infrastructure where they can be protected and rotated. A secret embedded in a native or mobile application can still be extracted, so static credentials are not a substitute for a backend token service.

Create and manage static credentials from the authenticated Xirsys dashboard. The public TURN API creates expiring credentials only; requests for non-expiring credentials through the public API are rejected.

New Free accounts can create and use static credentials during their first 30 days. When the trial ends, existing static credentials are archived and rejected until the account upgrades to a paid plan; upgrading re-enables the same credentials automatically. Dynamic credentials remain available on Free accounts.

For most browser and consumer-client applications, issue short-lived dynamic credentials from your backend.

Questions about this page? Email experts@xirsys.com