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.
Framework Integration
The Telnyx WebRTC JS SDK works with any JavaScript framework. This guide covers integration patterns for popular frameworks.
React
Install
npm install @telnyx/webrtc @telnyx/react-client
Using the React wrapper
The @telnyx/react-client package provides hooks and context providers:
import { TelnyxClientProvider, useCall, useTelnyxClient } from '@telnyx/react-client';
function App() {
return (
<TelnyxClientProvider>
<CallScreen />
</TelnyxClientProvider>
);
}
function CallScreen() {
const { client } = useTelnyxClient();
const { call, makeCall, hangup } = useCall();
return (
<div>
{call?.state === 'active' && <p>Call in progress</p>}
<button onClick={() => makeCall('+12345678900')}>Call</button>
{call && <button onClick={hangup}>Hang up</button>}
</div>
);
}
Using the SDK directly
If you prefer to use the SDK without the React wrapper:
import { useEffect, useRef, useState } from 'react';
import { TelnyxRTC } from '@telnyx/webrtc';
function useTelnyxRTC(token) {
const clientRef = useRef(null);
const [calls, setCalls] = useState([]);
useEffect(() => {
const client = new TelnyxRTC({ login_token: token });
client.on('telnyx.ready', () => {
console.log('Connected');
});
client.on('telnyx.notification', (notification) => {
if (notification.type === 'callUpdate') {
setCalls([...client.calls]);
}
});
client.connect();
clientRef.current = client;
return () => {
client.disconnect();
};
}, [token]);
return { client: clientRef.current, calls };
}
Always disconnect the client on component unmount to prevent zombie WebSocket connections.
Next.js
Next.js requires special handling because the SDK uses browser APIs (WebSocket, RTCPeerConnection) that don’t exist on the server.
Dynamic import
import dynamic from 'next/dynamic';
const CallScreen = dynamic(() => import('../components/CallScreen'), {
ssr: false, // Required — SDK uses browser APIs
});
export default function Page() {
return <CallScreen />;
}
Client component (App Router)
'use client';
import { useEffect, useState } from 'react';
export default function CallScreen() {
const [client, setClient] = useState(null);
useEffect(() => {
// Dynamic import to avoid SSR
import('@telnyx/webrtc').then(({ TelnyxRTC }) => {
const rtc = new TelnyxRTC({ login_token: getToken() });
rtc.connect();
setClient(rtc);
});
return () => {
client?.disconnect();
};
}, []);
return <div>Call UI here</div>;
}
Vue
Composable
// composables/useTelnyx.js
import { ref, onUnmounted } from 'vue';
import { TelnyxRTC } from '@telnyx/webrtc';
export function useTelnyx(token) {
const client = ref(null);
const calls = ref([]);
const connected = ref(false);
function connect() {
const rtc = new TelnyxRTC({ login_token: token });
rtc.on('telnyx.ready', () => {
connected.value = true;
});
rtc.on('telnyx.notification', (notification) => {
if (notification.type === 'callUpdate') {
calls.value = [...rtc.calls];
}
});
rtc.connect();
client.value = rtc;
}
function disconnect() {
client.value?.disconnect();
connected.value = false;
}
onUnmounted(() => {
disconnect();
});
return { client, calls, connected, connect, disconnect };
}
Component
<template>
<div>
<button @click="makeCall">Call</button>
<button @click="disconnect" v-if="connected">Disconnect</button>
</div>
</template>
<script setup>
import { useTelnyx } from '../composables/useTelnyx';
const { client, calls, connected, connect, disconnect } = useTelnyx(token);
function makeCall() {
client.value?.newCall({
destinationNumber: '+12345678900',
audio: true,
});
}
connect();
</script>
Angular
Service
import { Injectable, OnDestroy } from '@angular/core';
import { TelnyxRTC } from '@telnyx/webrtc';
@Injectable({ providedIn: 'root' })
export class TelnyxService implements OnDestroy {
private client: TelnyxRTC | null = null;
connect(token: string) {
this.client = new TelnyxRTC({ login_token: token });
this.client.on('telnyx.ready', () => {
console.log('Connected');
});
this.client.on('telnyx.notification', (notification) => {
// Handle notifications
});
this.client.connect();
}
makeCall(destination: string) {
return this.client?.newCall({
destinationNumber: destination,
audio: true,
});
}
disconnect() {
this.client?.disconnect();
this.client = null;
}
ngOnDestroy() {
this.disconnect();
}
}
General Patterns
Token fetching
All frameworks should fetch JWT tokens from a backend endpoint:
// Don't hardcode tokens
const token = await fetch('/api/telnyx-token').then(r => r.text());
Audio element management
The SDK auto-creates audio elements, but in some frameworks you may want to manage them yourself:
const call = client.newCall({
destinationNumber: '+12345678900',
audio: true,
remoteElement: document.getElementById('remoteAudio'),
localElement: document.getElementById('localAudio'),
});
Or after the call is active:
// The SDK appends audio elements to document.body by default
// You can move them:
const audioEl = document.querySelector('audio[src^="blob:"]');
if (audioEl) {
document.getElementById('audioContainer').appendChild(audioEl);
}
Cleanup
Always clean up on unmount/unload:
// React
useEffect(() => {
return () => client?.disconnect();
}, []);
// Vue
onUnmounted(() => client?.disconnect());
// Angular
ngOnDestroy() { this.client?.disconnect(); }
// Vanilla
window.addEventListener('beforeunload', () => client?.disconnect());
See Also