Skip to main content

Quick Start (WebRTC)

Best for client-side apps

This guide covers the WebRTC-based integration, which is recommended for client-side applications (browsers, mobile apps). If you are building a backend integration, see the WebSockets Quick Start Guide instead.

Palabra API client​

Consider using Palabra API JavaScript client for WebRTC-based integrations.

How it works​

  1. You create a session and receive a WebRTC API URL and an publisher access token.
  2. You connect to WebRTC API URL and publish your original audio track.
  3. You send a set_task message with your language settings through the room's data channel.
  4. Palabra transcribes, translates, and synthesizes your speech in real time and publishes the translated audio track to the same room. You are auto-subscribed to it and can play it back instantly.

Step 1. Get API Credentials​

Create an API Key on the Palabra API Keys page. See Obtaining an API Key for details.

Step 2. Create a Session​

Call POST /session-storage/session with your API Key. The response contains the webrtc_url and the publisher JWT token required for the next steps.

Request Example​

const { data } = await axios.post(
"https://api.palabra.ai/session-storage/session",
{
data: {},
},
{
headers: {
Authorization: "Bearer <API_KEY>",
},
}
);

Response Example​

{
"publisher": "eyJhbGciOiJIU...Gxr2gjWSA4",
"webrtc_url": "https://streaming-0.palabra.ai/livekit/",
"ws_url": "wss://streaming-0.palabra.ai/streaming-api/v1/speech-to-speech/stream",
"id": "7f99b553-4697...7d450728"
}

You need two fields from the response:

  • webrtc_url — the WebRTC Speech-to-Speech Translation API URL.
  • publisher — the JWT token used to authenticate your connection.

Step 3. Connect to the Translation Room​

Use the LiveKit SDK to join webrtc_url with your publisher token.

npm install livekit-client
import { Room } from "livekit-client";

const connectTranslationRoom = async (WEBRTC_URL, PUBLISHER) => {
try {
const room = new Room();
await room.connect(WEBRTC_URL, PUBLISHER, { autoSubscribe: true });
return room;
} catch (e) {
console.error(e);
throw e;
}
};

Step 4. Publish the Original Audio Stream​

Get the audio stream from your microphone and publish it to the room.

Recommended publish options

Disable dtx and red when publishing your audio track — see Recommended settings.

import { LocalAudioTrack } from "livekit-client";

const publishAudioTrack = async (room) => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1 } });
const localTrack = new LocalAudioTrack(stream.getAudioTracks()[0]);
await room.localParticipant.publishTrack(localTrack, {
dtx: false,
red: false,
audioPreset: {
maxBitrate: 32000,
priority: "high"
}
});
} catch (e) {
console.error("Error while publishing audio track:", e);
throw e;
}
}

Step 5. Handle the Translated Audio Track​

As soon as Palabra publishes the translated audio track to the room, you are auto-subscribed to it. Handle it in a callback and play it through the speakers.

import { RoomEvent } from "livekit-client";

const playTranslationInBrowser = (track) => {
if (track.kind === "audio") {
const mediaStream = new MediaStream([track.mediaStreamTrack]);
const audioElement = document.getElementById(
"remote-audio"
); // Your HTML audio element

if (audioElement) {
audioElement.srcObject = mediaStream;
audioElement.play();
} else {
console.error("Audio element not found!");
}
}
};

// Add a handler for the TrackSubscribed event
room.on(RoomEvent.TrackSubscribed, playTranslationInBrowser);

Step 6. Start the Translation​

Publish a set_task message with your translation settings through the WebRTC data channel to start the translation.

The Palabra translator joins the LiveKit room a moment after you do. A set_task published before it is in the room is not delivered to anyone and the translation never starts — the room accepts the data message, but there is no one subscribed to receive it. Wait for the translator to appear before sending the first set_task.

Your session room contains only you and the translator, so the first remote participant to join is the translator. It may also already be in the room by the time you connect, so check the current participant list before subscribing to the event.

import { RoomEvent } from 'livekit-client';

const TRANSLATOR_JOIN_TIMEOUT_MS = 30000;

// Resolves true once the Palabra translator is present in the room, false if it never joined.
const waitForTranslator = (room) => new Promise((resolve) => {
// The translator may already have joined by the time we get here.
if (room.remoteParticipants.size > 0) {
resolve(true);
return;
}

let timeoutId;

const onParticipantConnected = (participant) => {
console.log(`Translator joined: ${participant.identity}`);
clearTimeout(timeoutId);
room.off(RoomEvent.ParticipantConnected, onParticipantConnected);
resolve(true);
};

timeoutId = setTimeout(() => {
room.off(RoomEvent.ParticipantConnected, onParticipantConnected);
resolve(false);
}, TRANSLATOR_JOIN_TIMEOUT_MS);

room.on(RoomEvent.ParticipantConnected, onParticipantConnected);
});

const startTranslation = async (room, translationSettings) => {
// The translator has to be in the room before set_task is published,
// otherwise there is no one to receive it and the translation never starts.
const translatorJoined = await waitForTranslator(room);

if (!translatorJoined) {
console.error(
`Translator did not join the room within ${TRANSLATOR_JOIN_TIMEOUT_MS}ms. ` +
'set_task was not sent and the translation will not start.'
);
return;
}

const payload = JSON.stringify({
message_type: "set_task",
data: translationSettings
});
const encoder = new TextEncoder();
const message = encoder.encode(payload);

// Send the set_task message through the data channel
room.localParticipant.publishData(message, { reliable: true });
};

Summary​

As soon as you send the set_task message, Palabra takes your published audio track, translates it into the target languages from your settings, and publishes a translated track to the same room. The LiveKit SDK auto-subscribes you to this track, so you can play it back through the speakers in real time.

Good to know​

  • Pausing and stopping the translation are covered in the Translation management API.
  • Unused sessions stay active for at least 1 minute. To avoid hitting the limit on simultaneously active sessions, delete sessions you no longer need — for example, when translation stops or the page unmounts. See Session Management.
  • Due to browser security restrictions, audio cannot play until the user has interacted with the page. Don't start the pipeline automatically on page load — wait for a user action (such as pressing a "Start" button) before activating audio playback.

Need help?​

If you have any questions or need assistance, contact us at api.support@palabra.ai.