DEV Community

Javid Jamae
Javid Jamae

Posted on • Originally published at ffmpeg-micro.com

How to Add a Watermark to Video with FFmpeg (CLI + API)

Originally published at ffmpeg-micro.com

The Quick Answer

FFmpeg adds a watermark to video using the overlay filter. Two inputs (your video + your logo PNG), one filter, one output.

ffmpeg -i input.mp4 -i logo.png -filter_complex "[1:v]scale=100:-1[wm];[0:v][wm]overlay=W-w-10:H-h-10" -c:a copy output.mp4
Enter fullscreen mode Exit fullscreen mode

That command scales your logo to 100px wide, pins it to the bottom-right corner with 10px padding, and copies the audio untouched. If you want to skip the FFmpeg installation and do this through an API call instead, jump to the API section below.

How the Overlay Filter Works

The overlay filter combines two video streams into one. Stream [0:v] is your base video. Stream [1:v] is the watermark image. The filter positions the watermark on top of the base at the coordinates you specify.

The basic syntax:

ffmpeg -i video.mp4 -i watermark.png -filter_complex "overlay=x:y" output.mp4
Enter fullscreen mode Exit fullscreen mode

x and y are pixel positions measured from the top-left corner. But hardcoded pixel values break when your input resolution changes. That's where FFmpeg's position variables come in:

  • W / H = base video width / height
  • w / h = overlay (watermark) width / height
Position Overlay value
Top-left overlay=10:10
Top-right overlay=W-w-10:10
Bottom-left overlay=10:H-h-10
Bottom-right overlay=W-w-10:H-h-10
Center overlay=(W-w)/2:(H-h)/2

The 10 in each expression is padding in pixels. Adjust it to taste.

Scaling the Watermark

If your logo is 2000px wide and your video is 1280px, the watermark will cover the entire frame. Always scale first using scale2ref or a fixed-width scale:

ffmpeg -i input.mp4 -i logo.png \
  -filter_complex "[1:v]scale=100:-1[wm];[0:v][wm]overlay=W-w-10:H-h-10" \
  -c:a copy output.mp4
Enter fullscreen mode Exit fullscreen mode

scale=100:-1 sets the width to 100px and calculates the height automatically to preserve aspect ratio. For a watermark that's always 10% of the video width:

-filter_complex "[1:v]scale=main_w/10:-1[wm];[0:v][wm]overlay=W-w-10:H-h-10"
Enter fullscreen mode Exit fullscreen mode

Semi-Transparent Watermarks

If your watermark PNG already has an alpha channel (transparent background), overlay preserves it automatically. For adding opacity to a fully opaque logo, use the colorchannelmixer filter:

ffmpeg -i input.mp4 -i logo.png \
  -filter_complex "[1:v]colorchannelmixer=aa=0.3,scale=100:-1[wm];[0:v][wm]overlay=W-w-10:H-h-10" \
  -c:a copy output.mp4
Enter fullscreen mode Exit fullscreen mode

aa=0.3 sets the alpha channel to 30% opacity. Lower values make the watermark more transparent.

Adding a Watermark via API (No Server Required)

Running FFmpeg locally works for one-off jobs. But if you're building an app that watermarks user-uploaded video, or automating a content pipeline, you don't want to manage FFmpeg servers.

FFmpeg Micro handles this with two API calls. Upload your logo once, then watermark any video with a single POST request.

Step 1: Upload your logo

Upload your watermark PNG using the 3-step presigned URL flow:

# Get a presigned upload URL for your logo
curl -X POST https://api.ffmpeg-micro.com/v1/upload/presigned-url \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "my-logo.png",
    "contentType": "image/png",
    "fileSize": 24680
  }'

# Upload the file to the returned URL
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/png" \
  --data-binary @my-logo.png

# Confirm the upload
curl -X POST https://api.ffmpeg-micro.com/v1/upload/confirm \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "20260519-my-logo.png",
    "fileSize": 24680
  }'
Enter fullscreen mode Exit fullscreen mode

The confirm response gives you a gcsUrl like gs://bucket/20260519-my-logo.png. Save this. You only upload the logo once and reuse it across all your watermark jobs.

Step 2: Watermark a video

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [
      { "url": "https://example.com/my-video.mp4" },
      { "url": "gs://your-bucket/20260519-my-logo.png" }
    ],
    "outputFormat": "mp4",
    "filters": [
      { "filter": "[1:v]scale=100:-1[wm];[0:v][wm]overlay=main_w-overlay_w-10:main_h-overlay_h-10" }
    ]
  }'
Enter fullscreen mode Exit fullscreen mode

The filters field takes the same FFmpeg filter graph syntax you'd use locally. Two inputs, one filter, one API call. No FFmpeg binary to install, no server to scale.

Step 3: Poll and download

The response includes a job id. Poll GET /v1/transcodes/{id} until status is completed, then grab the output:

curl https://api.ffmpeg-micro.com/v1/transcodes/$JOB_ID/download \
  -H "Authorization: Bearer $API_KEY"
Enter fullscreen mode Exit fullscreen mode

This returns a signed download URL valid for 10 minutes.

Text Watermarks via API

For text-based watermarks (copyright notices, channel branding), FFmpeg Micro has a built-in @text-overlay virtual option that handles font rendering, word wrap, and positioning:

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [{ "url": "https://example.com/my-video.mp4" }],
    "outputFormat": "mp4",
    "options": [
      {
        "option": "@text-overlay",
        "argument": {
          "text": "(c) 2026 My Brand",
          "style": {
            "fontSize": 24,
            "fontColor": "white",
            "x": "main_w-text_w-20",
            "y": "main_h-text_h-20",
            "boxBorderW": 8
          }
        }
      }
    ]
  }'
Enter fullscreen mode Exit fullscreen mode

No font files to install, no drawtext filter compilation issues.

Common Pitfalls

Your FFmpeg build might not have drawtext. The drawtext filter requires FFmpeg compiled with --enable-libfreetype. Many default installations skip it. If you see No such filter: 'drawtext', you need to rebuild FFmpeg or switch to the image overlay approach. The FFmpeg Micro API handles this for you since @text-overlay runs on infrastructure where fonts are pre-installed.

PNG without alpha channel = ugly rectangle. If your logo is a JPEG or a PNG with a solid background, the watermark renders as a rectangle covering your video. Export your logo as PNG with a transparent background before using it as a watermark.

Scaling breaks aspect ratio if you set both width and height. Use scale=100:-1 (set width, auto-calculate height) instead of scale=100:100 (which stretches the logo).

Position variables differ between -vf and -filter_complex. In -filter_complex, use main_w and main_h for the base video dimensions, and overlay_w / overlay_h for the watermark. In -vf mode, the shorthand W, H, w, h also works.

Watermark disappears on short videos. If the watermark image has a longer duration than the video, FFmpeg may drop it. Add -shortest to your command to stop encoding at the end of the shortest input stream.

FAQ

Can I add a watermark to multiple videos at once?
With the CLI, you'd loop through files in a shell script. Through the FFmpeg Micro API, fire off one POST request per video. Each job runs independently on cloud infrastructure, so 100 watermark jobs process in parallel without you managing concurrency.

Does watermarking re-encode the entire video?
Yes. The overlay filter requires decoding and re-encoding. This means some quality loss unless you set a low CRF value (18 or lower for near-lossless). There's no way to avoid re-encoding when compositing two streams.

What image formats work for watermarks?
PNG is the standard choice because it supports transparency. JPEG works but renders with a solid background. SVG doesn't work directly with FFmpeg. Convert SVGs to PNG first.

Can I animate the watermark (fade in, move across the screen)?
Yes. FFmpeg's overlay filter accepts expressions for x and y that reference the frame number (n) or timestamp (t). For example, overlay=10:'if(lt(t,3),H,H-h-10)' keeps the watermark off-screen for the first 3 seconds, then snaps it into position.

How much does watermarking cost through the API?
FFmpeg Micro bills by processed input duration. A 1-minute video costs the same whether you're watermarking, transcoding, or trimming. Check the pricing page at ffmpeg-micro.com/pricing for current rates.

Last verified: 2026-05-19 against FFmpeg 3.3.3 (CLI) and FFmpeg Micro API v1

Top comments (0)