Your logo on every frame. Or a second video in the corner.
Overlay images, videos, text and subtitles at the position, size and time you choose. A PNG with transparency keeps its edges.
Who uses it: Products that export video for their customers, stock and preview libraries, course and tutorial makers.
01
Watermark or logo
Places an image, such as a PNG logo with transparency, over every frame.
- What it is for
- Brand every video your product exports, or mark previews as previews.
- Endpoint and fields
POST /v1/transcodeextra_inputsoverlays- In ffmpeg
overlayscale
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/talk.mp4",
"filename": "talk-branded.mp4",
"extra_inputs": {
"logo": "https://example.com/logo.png"
},
"overlays": [
{
"input": "logo",
"position": "bottom-right",
"margin": 24,
"width": 160
}
]
}' import { Videxo } from '@videxo/sdk';
const videxo = new Videxo({ apiKey: process.env.VIDEXO_API_KEY, baseUrl: process.env.VIDEXO_API_URL });
const job = await videxo.transcode({
"input": "https://example.com/talk.mp4",
"filename": "talk-branded.mp4",
"extra_inputs": {
"logo": "https://example.com/logo.png"
},
"overlays": [
{
"input": "logo",
"position": "bottom-right",
"margin": 24,
"width": 160
}
]
});
const done = await videxo.jobs.wait(job.id); Install with npm i @videxo/sdk, or send the same request with curl or JavaScript. About the SDK
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/talk.mp4",
"filename": "talk-branded.mp4",
"extra_inputs": {
"logo": "https://example.com/logo.png"
},
"overlays": [
{
"input": "logo",
"position": "bottom-right",
"margin": 24,
"width": 160
}
]
}),
});
const job = await response.json(); ffmpeg \
-i https://example.com/talk.mp4 \
-i https://example.com/logo.png \
-filter_complex "[0:v:0]scale='min(trunc(iw/2)*2,min(7680,min(trunc(7680*iw/ih/2)*2,trunc(sqrt(33554432*iw/ih)/2)*2)))':-2[o0s0];[1:v]scale=160:7680:force_original_aspect_ratio=decrease,tpad=stop=-1:stop_mode=clone[o0l0];[o0s0][o0l0]overlay=x=W-w-24:y=H-h-24:shortest=1[o0s1]" \
-map "[o0s1]" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p \
-map "0:a:0?" \
-c:a aac -b:a 128k -movflags +faststart \
talk-branded.mp4 Output. talk-branded.mp4: the logo, 160 pixels wide, 24 pixels in from the bottom right corner.
02
Picture in picture
Shrinks a second video and places it in a corner of the first.
- What it is for
- A camera over a screen recording, a reaction over the clip it reacts to.
- Endpoint and fields
POST /v1/transcodeextra_inputsoverlaysaudio- In ffmpeg
overlayscale
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/screen.mp4",
"filename": "lesson.mp4",
"extra_inputs": {
"camera": "https://example.com/camera.mp4"
},
"overlays": [
{
"input": "camera",
"position": "top-right",
"margin": 32,
"width": 480
}
],
"audio": {
"input": "camera"
}
}' import { Videxo } from '@videxo/sdk';
const videxo = new Videxo({ apiKey: process.env.VIDEXO_API_KEY, baseUrl: process.env.VIDEXO_API_URL });
const job = await videxo.transcode({
"input": "https://example.com/screen.mp4",
"filename": "lesson.mp4",
"extra_inputs": {
"camera": "https://example.com/camera.mp4"
},
"overlays": [
{
"input": "camera",
"position": "top-right",
"margin": 32,
"width": 480
}
],
"audio": {
"input": "camera"
}
});
const done = await videxo.jobs.wait(job.id); Install with npm i @videxo/sdk, or send the same request with curl or JavaScript. About the SDK
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/screen.mp4",
"filename": "lesson.mp4",
"extra_inputs": {
"camera": "https://example.com/camera.mp4"
},
"overlays": [
{
"input": "camera",
"position": "top-right",
"margin": 32,
"width": 480
}
],
"audio": {
"input": "camera"
}
}),
});
const job = await response.json(); ffmpeg \
-i https://example.com/screen.mp4 \
-i https://example.com/camera.mp4 \
-filter_complex "[0:v:0]scale='min(trunc(iw/2)*2,min(7680,min(trunc(7680*iw/ih/2)*2,trunc(sqrt(33554432*iw/ih)/2)*2)))':-2[o0s0];[1:v]scale=480:7680:force_original_aspect_ratio=decrease,tpad=stop=-1:stop_mode=clone[o0l0];[o0s0][o0l0]overlay=x=W-w-32:y=32:shortest=1[o0s1]" \
-map "[o0s1]" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p \
-map 1:a:0 \
-af apad \
-c:a aac -b:a 128k -shortest -movflags +faststart \
lesson.mp4 Output. lesson.mp4: the screen recording with the camera 480 pixels wide in the top right, 32 pixels in, and the camera’s sound.
03
Text and titles
Draws titles, captions and labels into the picture in a font from a curated set, with a box, outline or shadow, timed and faded.
- What it is for
- Lower thirds, chapter titles and calls to action without opening an editor.
- Endpoint and fields
POST /v1/transcodetext- In ffmpeg
drawtext
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/talk.mp4",
"filename": "talk-titled.mp4",
"text": [
{
"text": "Launch day",
"font": "inter-bold",
"size": 64,
"position": "bottom",
"box": {
"opacity": 0.6,
"padding": 16
},
"start": 1,
"end": 6,
"fade": {
"in": 0.5,
"out": 0.5
}
}
]
}' import { Videxo } from '@videxo/sdk';
const videxo = new Videxo({ apiKey: process.env.VIDEXO_API_KEY, baseUrl: process.env.VIDEXO_API_URL });
const job = await videxo.transcode({
"input": "https://example.com/talk.mp4",
"filename": "talk-titled.mp4",
"text": [
{
"text": "Launch day",
"font": "inter-bold",
"size": 64,
"position": "bottom",
"box": {
"opacity": 0.6,
"padding": 16
},
"start": 1,
"end": 6,
"fade": {
"in": 0.5,
"out": 0.5
}
}
]
});
const done = await videxo.jobs.wait(job.id); Install with npm i @videxo/sdk, or send the same request with curl or JavaScript. About the SDK
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/talk.mp4",
"filename": "talk-titled.mp4",
"text": [
{
"text": "Launch day",
"font": "inter-bold",
"size": 64,
"position": "bottom",
"box": {
"opacity": 0.6,
"padding": 16
},
"start": 1,
"end": 6,
"fade": {
"in": 0.5,
"out": 0.5
}
}
]
}),
});
const job = await response.json(); ffmpeg \
-i https://example.com/talk.mp4 \
-map 0:v:0 \
-vf "scale='min(trunc(iw/2)*2,min(7680,min(trunc(7680*iw/ih/2)*2,trunc(sqrt(33554432*iw/ih)/2)*2)))':-2,drawtext=expansion=none:fontfile=/opt/videxo/fonts/Inter-Bold.ttf:text=Launch day:fontsize=64:fontcolor=0xFFFFFF:x=(w-tw)/2:y=h-48-80:y_align=font:box=1:boxcolor=0x000000@0.6:boxborderw=16|16|16|16:enable='between(t,1,6)':alpha='clip(min((t-1)/0.5,(6-t)/0.5),0,1)'" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p \
-map "0:a:0?" \
-c:a aac -b:a 128k -movflags +faststart \
talk-titled.mp4 Output. talk-titled.mp4: “Launch day” in Inter Bold at the bottom on a dark box, from second 1 to second 6, fading in and out.
04
Burned-in subtitles
Draws the captions of an SRT or WebVTT file into the picture at their cue times, in a font from the curated set.
- What it is for
- Captions that play everywhere, muted autoplay feeds included, with no player support needed.
- Endpoint and fields
POST /v1/transcodeextra_inputssubtitles- In ffmpeg
subtitles
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/talk.mp4",
"extra_inputs": {
"captions": "https://example.com/talk.srt"
},
"filename": "talk-captioned.mp4",
"subtitles": {
"input": "captions",
"font": "inter-bold",
"size": 44
}
}' import { Videxo } from '@videxo/sdk';
const videxo = new Videxo({ apiKey: process.env.VIDEXO_API_KEY, baseUrl: process.env.VIDEXO_API_URL });
const job = await videxo.transcode({
"input": "https://example.com/talk.mp4",
"extra_inputs": {
"captions": "https://example.com/talk.srt"
},
"filename": "talk-captioned.mp4",
"subtitles": {
"input": "captions",
"font": "inter-bold",
"size": 44
}
});
const done = await videxo.jobs.wait(job.id); Install with npm i @videxo/sdk, or send the same request with curl or JavaScript. About the SDK
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/talk.mp4",
"extra_inputs": {
"captions": "https://example.com/talk.srt"
},
"filename": "talk-captioned.mp4",
"subtitles": {
"input": "captions",
"font": "inter-bold",
"size": 44
}
}),
});
const job = await response.json(); ffmpeg \
-i https://example.com/talk.mp4 \
-map 0:v:0 \
-vf 'scale='\''min(trunc(iw/2)*2,min(7680,min(trunc(7680*iw/ih/2)*2,trunc(sqrt(33554432*iw/ih)/2)*2)))'\'':-2,subtitles=filename=https\\://example.com/talk.srt:fontsdir=/opt/videxo/fonts:charenc=UTF-8:force_style='\''FontName=Inter,FontSize=11.7,Bold=-1,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,BorderStyle=1,Outline=0.5,Alignment=2,MarginV=13'\''' \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p \
-map "0:a:0?" \
-c:a aac -b:a 128k -movflags +faststart \
talk-captioned.mp4 Output. talk-captioned.mp4: the captions of talk.srt in Inter Bold, white with a thin black outline, centred at the bottom, each at its time.
Limits. Set by your plan.
- Overlays are images or videos given as inputs. Text and subtitles use the fonts on the Fonts page of the docs.
- Subtitles come from an SRT or WebVTT input of at most 1 MB; the tags and styles in the file are removed, so every cue is plain text.
- Inputs are public http or https URLs, or completed private uploads up to 100 MB and your plan’s input limit. Outputs have signed download links. A job names up to 16 input and 16 output files.
| Limit | Pay as you go | Starter | Pro | Scale |
|---|---|---|---|---|
| Longest job | 10 min | 10 min | 30 min | 60 min |
| Inputs per job | 1 GB | 1 GB | 5 GB | 10 GB |
| Outputs per job | 1 GB | 1 GB | 5 GB | 8 GB |
| Outputs expire after | 7 days | 7 days | 30 days | 30 days |
Pay as you go
- Longest job
- 10 min
- Inputs per job
- 1 GB
- Outputs per job
- 1 GB
- Outputs expire after
- 7 days
Starter
- Longest job
- 10 min
- Inputs per job
- 1 GB
- Outputs per job
- 1 GB
- Outputs expire after
- 7 days
Pro
- Longest job
- 30 min
- Inputs per job
- 5 GB
- Outputs per job
- 5 GB
- Outputs expire after
- 30 days
Scale
- Longest job
- 60 min
- Inputs per job
- 10 GB
- Outputs per job
- 8 GB
- Outputs expire after
- 30 days