Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt

Use this file to discover all available pages before exploring further.

Production Best Practices

Going from “it works on my machine” to “it works for all users, reliably” requires addressing security, reliability, performance, and monitoring. This guide covers the key areas.

Authentication

Use JWT in production

// Production
const client = new TelnyxRTC({ login_token: jwt });

// Development only
const client = new TelnyxRTC({ login: 'user', password: 'pass' });
JWTs are time-limited, revocable, and don’t expose passwords. See Authenticating Your App.

Generate JWTs on your backend

// Backend generates token — API key never reaches the browser
app.post('/api/telnyx-token', async (req, res) => {
 const token = await telnyx.telephonyCredentials.createToken(credentialId);
 res.json({ token });
});

// Never do this — API key in browser source
const response = await fetch('https://api.telnyx.com/v2/telnyx_rtc/access_tokens', {
 headers: { Authorization: `Bearer ${API_KEY}` }, // API_KEY exposed!
});

Handle token refresh

client.on('telnyx.notification', (notification) => {
 if (notification.type === 'userMediaError') return;

 // Check for token expiring soon
 if (notification.type === 'callUpdate' && notification.call?.state === 'destroyed') {
 // If disconnected due to auth, try refresh
 }
});

// Or use the session event
client.on('telnyx.ready', () => {
 console.log('Connected and authenticated');
});

One credential per user

Never share a Telephony Credential across multiple users. Each user must have their own JWT to ensure they receive their own incoming calls.

Connection Management

One client instance per tab

// Create once
let client = null;

function getClient() {
 if (!client) {
 client = new TelnyxRTC({ login_token: getJwt() });
 client.connect();
 }
 return client;
}

// Creating multiple instances
const client1 = new TelnyxRTC({ login_token: jwt }); // WebSocket 1
const client2 = new TelnyxRTC({ login_token: jwt }); // WebSocket 2 — wasteful

Clean up on page unload

window.addEventListener('beforeunload', () => {
 if (client) {
 client.calls.forEach(call => call.hangup());
 client.disconnect();
 }
});

Handle reconnection gracefully

client.on('telnyx.notification', (notification) => {
 if (notification.type === 'callUpdate') {
 const call = notification.call;
 if (call.state === 'reconnecting') {
 showBanner('Connection lost. Reconnecting...');
 } else if (call.state === 'active' && wasReconnecting) {
 hideBanner();
 }
 }
});
See Handle Reconnection for the full guide.

Audio Quality

Request microphone with constraints

const call = client.newCall({
 destinationNumber: '+12345678900',
 audio: true,
 // SDK handles getUserMedia internally
});
If you need to control the microphone before making a call:
const stream = await navigator.mediaDevices.getUserMedia({
 audio: {
 echoCancellation: true,
 noiseSuppression: true,
 autoGainControl: true,
 },
});

Monitor call quality

Enable call reports in production:
const client = new TelnyxRTC({
 login_token: jwt,
 enableCallReports: true,
 callReportInterval: 5000,
});
Set up quality alerts:
client.on('telnyx.notification', (notification) => {
 if (notification.type === 'callQuality') {
 const { mos, rtt, jitter, packetLoss } = notification.callQuality;
 if (mos < 3.0 || rtt > 500 || jitter > 100 || packetLoss > 5) {
 logQualityIssue(notification);
 }
 }
});

Recommend headphones for agents

Built-in speakers + microphone create echo. For call center agents, recommend USB headsets or enforce echo cancellation.

Network Configuration

Allowlist Telnyx domains

Ensure your firewall allows:
DomainPortProtocolPurpose
rtc.telnyx.com443WebSocket (TLS)Signaling
stun.telnyx.com3478UDPSTUN (ICE)
turn.telnyx.com3478UDPTURN relay
turn.telnyx.com443TCPTURN fallback
api.telnyx.com443HTTPSREST API

Don’t force relay unless necessary

// Only if you have a specific security requirement
const client = new TelnyxRTC({
 login_token: jwt,
 forceRelayCandidate: true, // Forces all media through TURN
});

// Default — lets ICE find the best path
const client = new TelnyxRTC({
 login_token: jwt,
});
Forcing relay adds 20-80ms latency per direction. Use it only when corporate policy requires all media to go through a relay. See Configure Network & Firewall for the full guide.

Error Handling

Always handle errors

client.on('telnyx.notification', (notification) => {
 if (notification.type === 'userMediaError') {
 const { code, message } = notification.error;

 switch (code) {
 case 1: // Not allowed
 showError('Microphone access denied. Please allow access in browser settings.');
 break;
 case 2: // Not found
 showError('No microphone detected. Please connect a microphone.');
 break;
 case 3: // Not readable
 showError('Microphone in use by another application.');
 break;
 }
 }
});

Handle connection failures

client.on('telnyx.socket.close', () => {
 showError('Connection to Telnyx lost. Attempting to reconnect...');
});

client.on('telnyx.socket.error', (error) => {
 logError('WebSocket error', error);
});

Don’t show raw errors to users

// Technical error exposed to user
showError(`Call failed: ${error.message}`);

// User-friendly message
showError('Unable to connect the call. Please try again.');

Memory Management

Clean up call references

client.on('telnyx.notification', (notification) => {
 if (notification.call?.state === 'destroyed') {
 // Remove call from your state
 removeCallFromState(notification.call.id);
 }
});

Remove event listeners

// When component unmounts (React example)
useEffect(() => {
 const handler = (notification) => { /* ... */ };
 client.on('telnyx.notification', handler);

 return () => {
 client.off('telnyx.notification', handler);
 };
}, []);

Monitoring & Observability

Enable call reports

const client = new TelnyxRTC({
 login_token: jwt,
 enableCallReports: true, // Auto-upload reports after each call
 callReportInterval: 5000, // Stats every 5 seconds
});

Track key metrics

MetricGoodWarningCritical
MOS> 4.03.0–4.0< 3.0
RTT< 150ms150–300ms> 300ms
Jitter< 20ms20–50ms> 50ms
Packet Loss< 1%1–3%> 3%

Log quality issues server-side

client.on('telnyx.notification', (notification) => {
 if (notification.type === 'callQuality') {
 sendToMonitoring({
 callId: notification.call.id,
 mos: notification.callQuality.mos,
 timestamp: Date.now(),
 });
 }
});

Deployment Checklist

RequirementDetails
Authentication uses JWTlogin_token in production, not login+password
JWT generated on backendAPI key never in browser
Token refresh handles TOKEN_EXPIRING_SOONCall client.updateToken() on warning code 34001
beforeunload disconnects clientHang up calls and call client.disconnect()
enableCallReports: trueAutomatic call reports for production monitoring
Error handling covers key eventsuserMediaError, socket.close, socket.error
Firewall allows Telnyx domainsrtc.telnyx.com:443, stun.telnyx.com:3478, turn.telnyx.com:443
Reconnection UI shown during reconnecting stateUsers should see connection status
Call references cleaned up on destroyed statePrevent memory leaks
No forceRelayCandidate: true unless requiredForced relay adds 20-80ms latency
Quality metrics logged to monitoringTrack MOS, RTT, jitter, packet loss
User-friendly error messagesNo raw errors shown to users

See Also