Personalized Video Messaging
Personalized Video Messaging
Personalized video messaging uses AI lip sync to create unique video content for individual recipients at scale. By combining text-to-speech with Sync Labs’ lip sync API, a single recorded video becomes thousands of personalized messages — each with the speaker appearing to address the recipient by name. This approach leads to higher engagement, better conversion rates, and a more personal connection compared to generic video messages.
This page covers two approaches: the text-to-speech example project below, and replacing one word of the recording with each recipient’s name using dialogue edits and the Batch API.
Follow these steps to run the personalized video messaging example:
Configure API Keys
You will need Sync_API_KEY and ELEVEN_LABS_API_KEY to run the example. Update constants.py file with your own API keys:
SYNC_API_KEY: Your API key for Sync LabsELEVEN_LABS_API_KEY: Your API key for ElevenLabs (used for voice generation).
Ensure the file is saved after adding your keys.
Prepare Input Data (Optional)
The repository includes a sample input file example.csv for quickstart.
You can modify it with your own inputs if desired. Each row typically represents one recipient.
The input file should have the following columns:
video: URL of the video to be personalized.text: Text to be personalized in the video.segment_start: start time of the video segment to be personalized.segment_end: end time of the video segment to be personalized.output_format: output format of the video.sync_mode: mode to sync text to video segment if lengths don’t match. optionsvoice_id: elevenlabs voice id to use for the video. If empty, audio from the video will be cloned.lipsync_model: sync.so lipsync model to use for the video. default:lipsync-2tts_model: elevenlabs text to speech model. default:eleven_multilingual_v2
Replace a word with each recipient’s name (early access)
Instead of generating new audio for the whole message, you can keep the recording and change one word, such as a name, for each recipient. Sync transcribes the video and re-speaks only that word in the speaker’s cloned voice, then the Batch API lip syncs every variant in one batch.
This uses dialogue edit rows in the Batch API, which are in early access and enabled per organization. Contact us to turn them on. The Batch API requires the Scale plan or higher.
You need:
- A single-speaker video uploaded to Sync storage. Follow Asset Uploads and keep the hosted URL.
- The word to replace, as spoken in the video. For example, record the message with a placeholder name such as “Alex” and replace that word.
- A CSV with a
namecolumn and 20 to 500 rows, one per recipient. An optionalpronunciationcolumn holds a respelling for names the voice says wrong. The first rows might look like this:
How it works
- Transcribe the video with
POST /v2/transcriptionsand find theidof the word to replace. - Create one preview per CSV row with
POST /v2/dialogue-edits, changing that word to the row’s name. The first preview clones the voice and returnsvoiceId; pass it asvoiceIdon the other previews to skip cloning. Preview requests are limited to 30 per minute, so space them about 2 seconds apart. - Wait for every preview to complete. Listen to the
previewAudioUrlof a few previews before a large batch. If the voice says a name wrong, add apronunciationrespelling, for example{"kind": "change", "wordId": "w35", "replacement": "Mia", "pronunciation": "Meeah"}. The transcript and results keep thereplacementtext. - Submit one batch row per completed preview, first with
dry_run: trueand then for real. Every row sends the same source video anddialogueEdit: {"id": "..."}. Each row is charged the same as rendering that preview withPOST /v2/generate. - Poll
GET /v2/batch/{id}until it isCOMPLETED, or passwebhook_urlto be notified. Download the results file fromoutputUrland match each line to its CSV row byrequest_id. A completed row’s video is atresponse.output_url.
Run the example script
The script below runs all five steps with the Python 3 standard library (3.8 or later, nothing to install). Save it as personalize_batch.py, then run:
Progress goes to stderr, including each preview’s audio URL so you can listen to a few. A preview that completes only partially (COMPLETED_PARTIAL) is still used, with a note to listen to it first; rows whose preview fails or times out are reported and left out of the batch. The script never resubmits a batch: if the submit returns a 5xx error or times out, the batch may exist, so it tells you to list your batches with GET /v2/batch and resume with --batch-id. Results go to stdout as tab-separated lines with the CSV line, name, status, and output URL (or error). Optional flags:
--dry-runcreates the previews and validates the batch, then stops without rendering any video.--batch-id <id>resumes an interrupted run: it polls that batch and prints its results. Pass the same CSV.--modelsets the lip sync model (defaultsync-3).--occurrence Nreplaces the Nth match of--wordwhen it is spoken more than once.--webhook-urlsets the batch completion webhook.--timeout-min Nlimits how long each step (transcription, previews, batch) waits, 60 minutes by default. If the batch is still running when it expires, the script prints the--batch-idcommand to resume.
Set SYNC_API_BASE to use another API host.
In a test with a 10-second clip and 20 names, the previews (one voice clone, then 19 reuses of its voiceId) were ready in about a minute and the batch completed all 20 rows about 5.5 minutes later. Batches have a target turnaround of 24 hours, so allow for longer runs, and use --batch-id to pick up where you left off. The results file starts like this:
Frequently Asked Questions
How many personalized videos can I generate at once?
The CSV files above are input to the example scripts, not the Batch API. The Batch API accepts 20 to 500 generation requests on eligible plans, as a JSONL file or as a JSON rows array. Each record must contain a unique request_id, endpoint: "/v2/generate", and a generation payload. Convert your recipient data into that format before submitting a batch; for volumes above 500, split it into batches that each meet these limits.
What if the voice mispronounces a name?
With dialogue edits, add a pronunciation respelling to that row’s change edit, for example “shivawn” for “Siobhan”. Write it like an ordinary word, without hyphens or all-caps syllables, since capital letters may be spelled out one by one. Short names can still come out differently between takes. The voice speaks the respelling while the transcript and results keep the name. Listen to a few previews before you submit a large batch.
What TTS providers work with Sync Labs?
The example project includes built-in ElevenLabs integration for text-to-speech. However, any TTS provider that outputs standard WAV or MP3 audio files works with Sync Labs’ lip sync API — simply pass the generated audio URL as the audio_url parameter.
How much does personalized video messaging cost?
Cost depends on the lip sync model and video duration. Use the /v2/generate/estimate-cost endpoint to get exact pricing before submitting a batch. lipsync-2 is the most cost-effective option for high-volume personalized messaging. With dialogue edits, each batch row is charged the same as rendering that preview with POST /v2/generate.
Related Resources
- Quickstart — get up and running with your first Sync Labs API call
- Python SDK — use the official Python SDK for streamlined API integration
- Webhooks — receive real-time notifications when your video generations complete
- Transcription and Dialogue Editing — transcribe a video and preview word edits
- Batch Processing — batch limits, row format, and dialogue edit refusal codes

