Skip to main content

Migrate from Tavus

Tavus is a great product and we respect their team. If you're evaluating a move to Lookalike, this guide maps the calls you already make onto ours, side by side, so you can see exactly what changes. The Tavus snippets are shown for orientation against its v2 API.

Two things are worth knowing up front:

  • One object instead of two. In Tavus you manage a replica for the face and a separate persona for the personality, then pair them per conversation. Here they are a single identity: face, voice, and personality in one object you create once and reuse by identity_id.
  • LiveKit, not Pipecat. A Lookalike session runs over LiveKit. You start a session, get a room name, an access token, and a server URL back, and join with a LiveKit client. If your Tavus integration is built on Pipecat (Daily's open-source framework), swapping its client for the LiveKit client is the main change on the browser side.

How the concepts map​

TavusLookalikeNotes
Replicapart of an identityThe visual likeness
Personapart of an identityIts system_prompt becomes the identity prompt
Voice on the personapart of an identityA reference audio clip
Replica + personaone identity_idCreated and trained in a single call
ConversationsessionPOST /v1/sessions/start
conversation_url (Pipecat)room_name + token + livekit_urlJoin with a LiveKit client
x-api-key headerAuthorization: Bearer or X-API-KeyKeys start with lk_
Conversational minutescreditsOne balance covers onboarding and realtime

Authenticate​

Tavus sends x-api-key; Lookalike sends a bearer token (or X-API-Key), and keys start with lk_. Get one in the console.

Tavus

curl https://tavusapi.com/v2/replicas -H "x-api-key: $TAVUS_API_KEY"

Lookalike

curl https://api.lookalike.com/v1/identities -H "Authorization: Bearer $LOOKALIKE_API_KEY"

Create the avatar​

In Tavus this is two objects and an asynchronous wait: train a replica from a consent video, then create a persona bound to it. In Lookalike it is one multipart call that carries the face, the voice, and the personality, and trains inline — your Tavus persona prompt moves over unchanged as prompt.

Tavus

# 1. train a replica from a consent video (asynchronous — poll until ready)
curl -sS -X POST https://tavusapi.com/v2/replicas \
-H "x-api-key: $TAVUS_API_KEY" -H "Content-Type: application/json" \
-d '{ "replica_name": "Ada", "train_video_url": "https://example.com/ada-consent.mp4" }'
# -> { "replica_id": "r1a2b3c4", "status": "training" }

# 2. create a persona bound to that replica
curl -sS -X POST https://tavusapi.com/v2/personas \
-H "x-api-key: $TAVUS_API_KEY" -H "Content-Type: application/json" \
-d '{ "persona_name": "Ada",
"system_prompt": "You are Ada, a warm and concise product guide.",
"default_replica_id": "r1a2b3c4" }'
# -> { "persona_id": "p5f6g7h8" }

Lookalike

curl -sS -X POST https://api.lookalike.com/v1/identities \
-H "Authorization: Bearer $LOOKALIKE_API_KEY" \
-F "name=Ada" \
-F "prompt=You are Ada, a warm and concise product guide." \
-F "image=@ada.jpg;type=image/jpeg" \
-F "audio=@ada.wav;type=audio/wav"
# -> { "identity_id": "id_...", "status": "ready" }

See Create an Identity for the full field list.

note

With a photo our create returns ready inline, so you usually skip the poll step Tavus requires after training a replica. To re-check later, GET /v1/identities/{identity_id}/status.

Start a session​

Tavus creates a conversation from a replica_id plus a persona_id and returns a conversation_url. Lookalike starts a session from just the identity_id and returns the LiveKit room name, token, and URL.

Tavus

curl -sS -X POST https://tavusapi.com/v2/conversations \
-H "x-api-key: $TAVUS_API_KEY" -H "Content-Type: application/json" \
-d '{ "replica_id": "r1a2b3c4", "persona_id": "p5f6g7h8" }'
# -> { "conversation_id": "c9i8h7g6", "conversation_url": "https://.../c9i8h7g6" }

Lookalike

curl -sS -X POST https://api.lookalike.com/v1/sessions/start \
-H "Authorization: Bearer $LOOKALIKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "identity_id": "id_3f9a2b7c4d1e8a05f6b3" }'
# -> { "room_name": "...", "token": "...", "livekit_url": "wss://..." }

The token is minted server-side and already encodes the room, so your browser never sees the API key. See Realtime API for the full response.

Pick the conversation language​

Tavus sets the language under the conversation's properties. Lookalike takes it as a top-level language on the session, and falls back to the language stored on the identity when you omit it.

const s = await fetch(`${LOOKALIKE}/v1/sessions/start`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ identity_id, language: 'es' }),
});
const { room_name, token, livekit_url } = await s.json();

Supported values are auto, en, es, pl, and uk. The other Tavus conversation properties do not map: max_call_duration remains unsupported, so end a session yourself when you need a hard limit.

Join the call​

Tavus hands you a conversation_url that you open in your Pipecat client. Lookalike hands you livekit_url + token that you join with a LiveKit client.

Lookalike

import { Room, RoomEvent, Track } from 'livekit-client';

// livekitUrl and token come from the sessions/start response
const room = new Room();

room.on(RoomEvent.TrackSubscribed, (track) => {
if (track.kind === Track.Kind.Video) {
document.getElementById('avatar').appendChild(track.attach());
} else if (track.kind === Track.Kind.Audio) {
document.body.appendChild(track.attach());
}
});

await room.connect(livekitUrl, token);
await room.localParticipant.setMicrophoneEnabled(true); // so the avatar can hear you

The agent listens and responds on its own, handling turns and interruptions natively — there is no push-to-talk. Transcripts arrive through LiveKit's own client SDK.

Avatar audio

When an avatar is enabled it publishes both audio and video. Attach both, but don't also play the agent's raw voice track, or you'll hear it twice.

End the session​

Tavus ends a conversation with an explicit call. Lookalike gives you both options: disconnect from the room, or call the End Session endpoint.

Tavus

curl -sS -X POST https://tavusapi.com/v2/conversations/c9i8h7g6/end \
-H "x-api-key: $TAVUS_API_KEY"

Lookalike

Disconnect the client:

await room.disconnect();

Or end it from your backend, passing the room_name from sessions/start as the session_id:

curl -sS -X POST https://api.lookalike.com/v1/sessions/ROOM_NAME/end \
-H "Authorization: Bearer $LOOKALIKE_API_KEY"

Billing​

Tavus meters conversational minutes. Lookalike meters credits from one balance: onboarding an identity is a one-time charge, and a realtime session is charged per minute while the avatar is streaming. Buy credits and view usage in the Console; full rates are on the Billing & credits page. A request that would spend credits you don't have returns 402, and a live session that runs out ends on its own with an insufficient_credits notice.

What's different​

  • One identity, not a replica plus persona. You manage a single object. Updating its prompt, look, or voice retrains it, so send those inputs together, the same way you created it.
  • Create is synchronous with a photo. No training webhook to wait on for the common case.
  • Local file upload. You upload the reference image directly, rather than hosting it at a public URL first.

Next steps​