# Auto Captions & Lyric Video Maker - TikTok Subtitles, Karaoke (`kantolabs/auto-captions-lyric-video`) Actor

Add animated captions to videos (TikTok-style word highlight, karaoke or classic subtitles burned in) and turn songs into lyric videos with lyrics synced to the singing. MP4 + SRT/VTT out. $0.06 per output minute (720p).

- **URL**: https://apify.com/kantolabs/auto-captions-lyric-video.md
- **Developed by:** [Kanto Labs](https://apify.com/kantolabs) (community)
- **Categories:** Videos, Social media, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $56.00 / 1,000 720p output minutes

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Auto Captions & Lyric Video Maker - add TikTok-style subtitles to any video

**Auto Captions & Lyric Video Maker** adds **animated captions** to your videos and turns songs into **lyric videos** - automatically. Give it a video link and get back an MP4 with **burned-in subtitles** (TikTok / Reels / Shorts word-by-word highlight, karaoke or classic style), plus the **SRT and VTT subtitle files** and the transcript. Give it a song (and optionally the lyrics) and get a **karaoke-style lyric video** with every word timed to the singing.

No editor, no account anywhere else, no API key: speech recognition (OpenAI Whisper), subtitle styling and video rendering all run inside the Actor. **$0.06 per output minute** at 720p, failures are free.

### What it does

| Mode | You give | You get |
|---|---|---|
| **Captions** | Video URL(s) - MP4, MOV, WEBM, MKV... (optional: your own SRT/VTT) | MP4 with captions burned in + SRT + VTT + transcript + preview image |
| **Lyric video** | Song / audio URL + optional lyrics + optional background image | MP4 lyric video (16:9, 9:16, 1:1 or 4:5) with lyrics synced to the singing + SRT/VTT |

- **TikTok-style captions**: 1-6 big bold words at a time, the spoken word lit up in your highlight colour, a small pop-in per phrase, placed clear of the TikTok/Reels buttons.
- **Karaoke captions**: a full subtitle line where words light up as they are spoken.
- **Classic subtitles**: clean two-line subtitles for YouTube, courses and webinars.
- **Lyric videos**: paste the lyrics and they are aligned to the vocals word by word; or leave them out and the words are transcribed. Image, video, colour or gradient background, slow zoom, title card, next line previewed.
- **99 languages** (auto-detected), including Chinese, Japanese and Korean with proper CJK fonts.
- **Your own subtitles**: burn an existing SRT/VTT into the video instead of transcribing.

### Style examples

All examples below were made by this Actor from public-domain NASA footage and a public-domain U.S. Navy Band recording.

| TikTok style (green highlight) | Lyric video, TikTok style | Japanese captions | Lyric video, gradient |
|---|---|---|---|
| ![TikTok-style captions with the spoken word highlighted](https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/example-tiktok-captions.jpg?signature=J3ThmKrzHGsQiJkSHIft) | ![Vertical lyric video with the sung word highlighted](https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/example-lyric-video-tiktok.jpg?signature=wP4YwyseYprVO9MTvVp7) | ![Japanese captions burned into a vertical video](https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/example-japanese-captions.jpg?signature=P1XctcjbKFoSJlH7w8O2) | ![Lyric video on a gradient background](https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/example-lyric-video-gradient.jpg?signature=1fSQ1f5mCd6DQ5KRaT4DO) |

**Karaoke captions** - words light up as they are spoken:

![Karaoke-style captions on a landscape video](https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/example-karaoke-captions.jpg?signature=1pjjwJ2yr7pVfEGGo8H7S)

**Classic subtitles** (1080p):

![Classic two-line subtitles on a 1080p video](https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/example-classic-subtitles.jpg?signature=HaUjjTwcr1KbJshAxDrm)

**Lyric video, karaoke style** - the current line fills word by word, the next line is previewed underneath:

![Karaoke lyric video with next-line preview](https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/example-lyric-video-karaoke.jpg?signature=1cnXSehHuuiyeC2ayQI8e)

### Who uses it

- **Faceless shorts / content automation** (n8n, Make, Zapier): script -> voice-over -> stock clip -> **this Actor adds the captions** -> post to TikTok, Reels and YouTube Shorts. One HTTP call, one MP4 link back.
- **Social media managers and agencies**: caption a batch of client clips in one run, in a consistent brand colour and font.
- **AI agents** (Apify MCP server, Claude, ChatGPT, Cursor): "add captions to this video" becomes a single tool call that returns a finished MP4.
- **Musicians and labels**: lyric videos for YouTube and vertical lyric clips for TikTok/Reels without editing software.
- **Podcasters**: audiograms - lyric video mode without lyrics turns an audio clip into a captioned video on your cover image.
- **Course creators and marketers**: classic burned-in subtitles plus SRT/VTT files for every platform.

### How to use it

1. Click **Try for free** and keep the prefilled sample video, or paste your own **direct video links** (one per line).
2. Pick a **caption style** (TikTok, karaoke or classic), colours, font and position - or keep the defaults.
3. Click **Start**. Each video becomes one row in the results with a **link to the captioned MP4**, a preview image, the SRT/VTT files and the transcript.
4. For a lyric video, switch **What to make** to *Lyric / audio video*, paste the song link and the lyrics, and optionally a background image.

#### Input example (captions)

```json
{
  "mode": "captions",
  "videoUrls": ["https://example.com/my-short.mp4"],
  "captionStyle": "tiktok",
  "highlightColor": "#FFD60A",
  "uppercase": true,
  "wordsPerLine": 3
}
```

#### Input example (lyric video)

```json
{
  "mode": "lyricVideo",
  "audioUrl": "https://example.com/song.mp3",
  "lyrics": "First line of the song\nSecond line of the song\n...",
  "lyricStyle": "karaoke",
  "aspectRatio": "9:16",
  "backgroundUrl": "https://example.com/cover.jpg",
  "songTitle": "My Song",
  "artist": "My Band"
}
```

#### Output example (one dataset row per video)

```json
{
  "fileName": "my-short.mp4",
  "status": "ok",
  "style": "tiktok",
  "width": 720,
  "height": 1280,
  "durationSeconds": 52.05,
  "billedMinutes": 1,
  "language": "en",
  "videoUrl": "https://api.apify.com/v2/key-value-stores/.../records/...-my-short.mp4?signature=...",
  "thumbnailUrl": "https://api.apify.com/v2/key-value-stores/.../records/...-my-short.jpg?signature=...",
  "srtUrl": "https://api.apify.com/v2/key-value-stores/.../records/...-my-short.srt?signature=...",
  "vttUrl": "https://api.apify.com/v2/key-value-stores/.../records/...-my-short.vtt?signature=...",
  "text": "Full transcript...",
  "segments": [{ "id": 1, "start": 0.0, "end": 2.74, "text": "rock and ice that we call a debris disk." }]
}
```

The links work without an Apify token. Files are kept for your plan's data-retention period - download or re-host them in your workflow.

### Auto captions API for n8n, Make and AI agents

Call the Actor with **Run Actor synchronously and get dataset items** - the response is the list of rows above, so the next step can read `videoUrl` directly:

```bash
curl -X POST "https://api.apify.com/v2/acts/kantolabs~auto-captions-lyric-video/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"videoUrls": ["https://example.com/my-short.mp4"], "captionStyle": "tiktok"}'
```

- **n8n**: the official Apify node -> *Run an Actor and get dataset* -> next node uses `{{$json.videoUrl}}` (e.g. upload to TikTok/YouTube, save to Drive).
- **Make / Zapier**: the Apify app -> *Run an Actor* (wait for finish) -> *Get dataset items*.
- **AI agents**: add Apify's MCP server; the agent finds this Actor with a search like "add captions to a video" and gets the MP4 link back.

A one-minute short usually finishes in 1-2 minutes, so synchronous calls work well for shorts; for long videos start the run and wait for it (or use a webhook).

### Pricing

Pay per event - you pay only for finished video:

| Event | Price (Free/Starter plans) |
|---|---|
| Output video minute, up to 720p | **$0.06** |
| Output video minute, 1080p | **$0.08** |

- Minutes are **started minutes of finished video, rounded up per video**: a 45-second short = 1 minute = **$0.06**. The transcription is included.
- **Free**: refused links, failed downloads, files without speech, over-limit files, render failures - you are never charged for a video you did not get.
- The 1080p price applies only when you choose 1080p **and** the source is larger than 720p (the output's short side is above 720 px) - a 720p source stays 720p and is charged as 720p. Videos are never upscaled.
- Your **"Max cost per run"** is respected: a video that would go over it is skipped (free) before any work is done.
- Scale and Business plans get a small Store discount automatically.

#### Worked examples and measured run times (Apify, 4 GB default memory)

| Job | Output | Run time (measured) | You pay |
|---|---|---|---|
| 21 s vertical clip, TikTok style (the prefilled sample) | 720x1280 | 47 s | $0.06 |
| 52 s vertical 1080x1920 talking-head video, TikTok style | 720x1280 | 70 s | $0.06 |
| Same clip at 1080p | 1080x1920 | about 1 min 50 s | $0.08 |
| 60 s Spanish interview, karaoke style | 1280x720 | about 1 min | $0.06 |
| 93 s 1080p explainer (AV1), karaoke style | 1280x720 | about 2 min | $0.12 |
| 4 min 1080p video, classic subtitles at 1080p | 1920x1080 | 5 min 50 s | $0.40 |
| 64 s song, words transcribed, gradient background | 720x1280 | 90 s | $0.12 |
| 64 s song + lyrics, TikTok style, image background | 1080x1920 | 2 min 20 s | $0.16 |
| 10 shorts of 30-60 s in one run (estimate from the runs above) | 720p | about 10 min | $0.60 |

### Languages and accuracy

- Speech recognition is **OpenAI Whisper small** (MIT licence) running inside the Actor: 99 languages, auto-detected per video, best on English and the major European and Asian languages.
- Names and rare terms can be misheard (for example "plantesimals" for "planetesimals"). For exact wording, provide your own **SRT/VTT** - its text and timing are burned in as-is.
- **Lyric videos**: when you paste the lyrics, the displayed words are always yours; the speech model is only used to find *when* each word is sung (we report an `alignmentScore` - near 1.0 means almost every word was found). Write the lyrics out **in full as sung**, repeating the chorus each time. Without lyrics, the words are transcribed and sung words are misheard more often than speech.
- Chinese, Japanese and Korean use Noto Sans CJK and are line-broken at natural points; Arabic, Hindi, Thai, Cyrillic and other scripts fall back to Noto Sans automatically.

### Limits

- **Direct file links only**: your storage, S3/R2/GCS (public or pre-signed), CDNs, Dropbox and Google Drive share links. Pages of **YouTube, TikTok, Instagram, Facebook, X, LinkedIn, Vimeo, Twitch, Douyin, Bilibili, SoundCloud and Spotify are refused** because their terms forbid downloading - only caption videos you own or may edit.
- Up to **120 minutes and 4 GB per file** (defaults 30 minutes / 2 GB - raise them in the input).
- Output up to **1080p**, frame rate capped at **30 fps**, H.264 + AAC MP4 (plays everywhere, ready for TikTok, Reels, Shorts and YouTube).
- Lyric video mode makes **one video per run**; captions mode takes many videos per run (processed one after another).
- Emoji are not drawn.

### Fonts and licences

Fonts are bundled from Debian packages, all under the **SIL Open Font License 1.1** (free for commercial use, including in videos you sell): **Montserrat** (Julieta Ulanovsky), **Inter** (Rasmus Andersson), **Bebas Neue** (Dharma Type), **Noto Sans** and **Noto Sans CJK** (Google / Adobe). Whisper is MIT-licensed; FFmpeg and libass do the rendering.

### FAQ

#### How do I add subtitles to a video automatically?

Paste the video link in **Video URLs**, keep the TikTok style (or pick karaoke/classic) and start the run. The Actor transcribes the speech, times every word and burns the captions into a new MP4.

#### Can I use a YouTube or TikTok link?

No. Platform pages are refused on purpose (their terms forbid downloading). Upload the video file to your own storage, Dropbox or Google Drive and use that link.

#### Can I burn my own SRT file into the video?

Yes - put the SRT/VTT link in **Your own SRT/VTT files** (same order as the videos) or paste the text into the box for a single video. Classic style shows your cues exactly; TikTok and karaoke styles spread the highlight over the words of each cue.

#### How do I make a lyric video from a song?

Choose **Lyric / audio video**, paste the song link and the lyrics (one sung line per line), pick 16:9 for YouTube or 9:16 for Shorts/Reels, add a background image if you like, and start. Lines appear and light up in time with the singing.

#### Is there a free trial?

Apify's free plan includes monthly platform credit you can use to try the Actor; the prefilled 21-second sample costs $0.06.

#### Do you keep my videos?

The input is downloaded into the run, used, and deleted when the run ends. Results are stored in **your** run's storage under your Apify account, with your plan's retention.

#### Which caption style gets the most views?

For Shorts/Reels/TikTok, the TikTok style with 2-3 words at a time in the lower third is the common choice; for YouTube and courses, classic subtitles. Uppercase and a bright highlight colour (yellow or green) read best on busy footage.

### Related Actors by Kanto Labs

- [Audio & Video to Text - Whisper Transcriber](https://apify.com/kantolabs/audio-video-to-text) - transcripts and SRT/VTT subtitles without rendering a video, $0.008 per audio minute.
- [Video Frame Extractor](https://apify.com/kantolabs/video-frame-extractor) - keyframes, scene frames and thumbnails from any video, for AI vision and previews.

### Support

Something not right with a video? Open an issue in the **Issues** tab with the input link (if you can share it) and we will look at it quickly.

# Actor input Schema

## `mode` (type: `string`):

'captions' = burn animated captions into your video(s). 'lyricVideo' = turn a song (or any audio) into a video with the lyrics/words on an image or colour background.

## `videoUrls` (type: `array`):

Direct links to your video files (MP4, MOV, WEBM, MKV, AVI...), one per line. Your storage, S3/R2/GCS (public or pre-signed), CDNs, Dropbox and Google Drive share links work. Pages of YouTube, TikTok, Instagram and other platforms are refused (their terms forbid downloading).

## `captionStyle` (type: `string`):

'tiktok' = 1-6 big words at a time, the spoken word highlighted (Shorts/Reels/TikTok look). 'karaoke' = full subtitle line, words light up as they are spoken. 'classic' = plain two-line subtitles.

## `subtitleUrls` (type: `array`):

Optional. Links to SRT or VTT files, in the same order as the videos (leave empty to transcribe automatically). With your own file the text and timing are used as-is; word highlighting is then estimated within each subtitle line.

## `subtitleText` (type: `string`):

Optional. Paste the content of an SRT or VTT file to burn it into the first video instead of transcribing.

## `audioUrl` (type: `string`):

Direct link to the song or audio (MP3, WAV, M4A, AAC, OGG, OPUS, FLAC) - or a video, whose sound is used. One song per run.

## `lyrics` (type: `string`):

Paste the lyrics, one sung line per line, written out in full as sung (repeat the chorus each time it is sung). They are timed to the singing automatically. Lines like \[Chorus] are ignored. Leave empty to transcribe the words from the audio.

## `lyricStyle` (type: `string`):

'karaoke' = the current line fills with colour word by word, next line previewed underneath. 'lines' = line by line, no word fill. 'tiktok' = a few big words at a time with the sung word highlighted.

## `songTitle` (type: `string`):

Shown at the start, before the first lyric (only if the intro is at least 2 seconds long).

## `artist` (type: `string`):

Shown under the title at the start.

## `aspectRatio` (type: `string`):

Shape of the lyric video. 16:9 for YouTube, 9:16 for Shorts/Reels/TikTok, 1:1 or 4:5 for feeds. (Captions mode keeps your video's own shape.)

## `backgroundUrl` (type: `string`):

Direct link to a JPG/PNG/WEBP image (or a short video, which is looped). It is cropped to fill the frame. Leave empty to use the colour/gradient below.

## `backgroundColor` (type: `string`):

Hex colour used when no background image is given, e.g. #1B1F3B.

## `backgroundColor2` (type: `string`):

Optional hex colour; with it the background is a diagonal gradient from the first colour to this one, e.g. #7B2FF7.

## `backgroundZoom` (type: `boolean`):

A slow push-in on the background over the whole song (Ken Burns). Turn off for a still background (renders faster, same price).

## `backgroundDim` (type: `integer`):

Darkens a background image so the words stay readable. 0 = original image.

## `font` (type: `string`):

'auto' = Montserrat ExtraBold for TikTok/karaoke/lyrics, Inter for classic subtitles. Chinese, Japanese and Korean always use Noto Sans CJK; other scripts (Arabic, Hindi, Thai, Cyrillic...) fall back to Noto Sans automatically.

## `fontSize` (type: `integer`):

100 = our tuned default for the style and frame size. 50-200.

## `textColor` (type: `string`):

Hex colour of the words, e.g. #FFFFFF.

## `highlightColor` (type: `string`):

Hex colour of the word being spoken/sung (TikTok, karaoke and lyric styles), e.g. #FFD60A yellow, #39FF14 green.

## `outlineColor` (type: `string`):

Hex colour of the outline and shadow around the letters, e.g. #000000.

## `position` (type: `string`):

'auto' = lower third on vertical video (clear of the TikTok/Reels buttons), bottom on landscape, centre for lyric videos.

## `uppercase` (type: `boolean`):

Show the words in capitals (the SRT/VTT files keep normal case).

## `wordsPerLine` (type: `integer`):

Maximum words shown together in the TikTok style. 1 = one word at a time.

## `resolution` (type: `string`):

720p (short side 720 px) is sharp on phones and cheapest. 1080p costs more per minute. Videos are never upscaled: a 720p source stays 720p and is charged as 720p.

## `language` (type: `string`):

'auto' detects it. Or a 2-letter ISO 639-1 code (en, es, de, fr, pt, it, ja, zh, ko, ar, hi...) - recommended for short clips and songs.

## `wordTimestamps` (type: `boolean`):

Also return the start and end time of every word in the dataset item.

## `maxDurationMinutes` (type: `integer`):

Longer inputs are skipped (free). Up to 120 minutes.

## `maxFileSizeMb` (type: `integer`):

Larger files are skipped (free).

## `downloadTimeoutSecs` (type: `integer`):

Give up on a file that does not download within this time (free).

## Actor input object example

```json
{
  "mode": "captions",
  "videoUrls": [
    "https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/sample-vertical-talk.mp4?signature=105QVevs72w3z5gMQzgIJ"
  ],
  "captionStyle": "tiktok",
  "lyricStyle": "karaoke",
  "aspectRatio": "16:9",
  "backgroundColor": "#1B1F3B",
  "backgroundZoom": true,
  "backgroundDim": 35,
  "font": "auto",
  "fontSize": 100,
  "textColor": "#FFFFFF",
  "highlightColor": "#FFD60A",
  "outlineColor": "#000000",
  "position": "auto",
  "uppercase": false,
  "wordsPerLine": 3,
  "resolution": "720p",
  "language": "auto",
  "wordTimestamps": false,
  "maxDurationMinutes": 30,
  "maxFileSizeMb": 2000,
  "downloadTimeoutSecs": 600
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `files` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "videoUrls": [
        "https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/sample-vertical-talk.mp4?signature=105QVevs72w3z5gMQzgIJ"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kantolabs/auto-captions-lyric-video").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "videoUrls": ["https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/sample-vertical-talk.mp4?signature=105QVevs72w3z5gMQzgIJ"] }

# Run the Actor and wait for it to finish
run = client.actor("kantolabs/auto-captions-lyric-video").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "videoUrls": [
    "https://api.apify.com/v2/key-value-stores/aXcXwfChlioPWAUJv/records/sample-vertical-talk.mp4?signature=105QVevs72w3z5gMQzgIJ"
  ]
}' |
apify call kantolabs/auto-captions-lyric-video --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kantolabs/auto-captions-lyric-video"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/U30mt4PM7l3hgwTcB/builds/XO3lEinzIM7cafafx/openapi.json
