ffmpegvideo-watermarkingapi

Video watermarking API: protect UGC and branded content

·Javid Jamae·9 min read
Video watermarking API: protect UGC and branded content

You've got user uploads coming in and every one of them needs your mark on it before it goes anywhere. Doing that with a local FFmpeg install works fine for ten clips and falls apart at a thousand. What you actually need is the overlay step to happen somewhere else, on demand, without you running a media server.

Quick answer: A video watermarking API adds a logo or text overlay to video in the cloud with a single HTTP request, so you don't install FFmpeg or run a worker. With FFmpeg Micro you POST the input URL and an overlay option to https://api.ffmpeg-micro.com/v1/transcodes, poll GET /v1/transcodes/:id until status is completed, then fetch a signed download URL. The free tier includes 100 video processing minutes.

What a watermark actually protects

Conventional wisdom says a watermark protects your video. Mostly it doesn't. A corner logo is one command away from gone:

ffmpeg -i marked.mp4 -vf "crop=iw:ih*0.92:0:0" -c:a copy stripped.mp4

That crops off the bottom 8% of the frame, logo included, in about the time it takes to re-encode. Anyone who wants your clip badly enough will do it.

So the mechanism isn't obfuscation. It's attribution and traceability. A visible watermark does two jobs well: it survives the casual re-upload (which is 95% of what happens to UGC), and if you make the text unique per user, a leaked file tells you exactly which account leaked it. That second one is where a watermarking API earns its keep, because a per-user mark can't be a static asset you burn in once. It has to be generated at request time.

A UGC platform I'd describe as typical of this problem was stamping every creator submission with the same PNG in After Effects, by hand, in batches of 200 a night. Switching to a per-submission text mark carrying the creator handle and a submission ID meant every reposted clip could be traced back in one lookup.

The FFmpeg CLI way

Here are the commands that do the real work, so you know what the API is doing on your behalf.

Static logo in the corner

ffmpeg -i input.mp4 -i logo.png \
  -filter_complex "[1]scale=iw*0.15:-1[wm];[0][wm]overlay=W-w-24:H-h-24" \
  -c:a copy output.mp4

scale=iw*0.15:-1 sizes the logo to 15% of its own width with the aspect ratio preserved. W-w-24:H-h-24 anchors it 24 pixels in from the bottom-right corner, using the video's dimensions (W, H) and the overlay's (w, h).

Opacity

ffmpeg -i input.mp4 -i logo.png \
  -filter_complex "[1]format=rgba,colorchannelmixer=aa=0.4[wm];[0][wm]overlay=W-w-24:H-h-24" \
  -c:a copy output.mp4

The format=rgba is not optional. Without an alpha channel present, colorchannelmixer=aa=0.4 silently does nothing and you get a fully opaque logo.

Dynamic text, per user

ffmpeg -i input.mp4 \
  -vf "drawtext=text='@creator_8842':fontcolor=white@0.35:fontsize=36:\
box=1:boxcolor=black@0.25:boxborderw=8:x=w-tw-30:y=h-th-30" \
  -c:a copy output.mp4

This is the one that actually deters reposting, because the mark identifies a person rather than a brand.

Timed watermark

Add :enable='between(t,0,5)' to any overlay filter to show it only for the first five seconds. Useful for branded content where a permanent mark would annoy viewers.

The API way: one call instead of a worker

Same result, no binary, no queue, no disk. Three steps.

1. Upload the source. Request a presigned URL, PUT the bytes, confirm:

curl -X POST https://api.ffmpeg-micro.com/v1/upload/presigned-url \
  -H "Authorization: Bearer $FFMPEG_MICRO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename":"clip.mp4","contentType":"video/mp4","fileSize":18432001}'

fileSize has to be a JSON number in bytes. Send it as a string and the request fails validation. If your video already lives at a public URL, skip this and pass the URL straight into inputs.

2. Submit the watermark job.

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer $FFMPEG_MICRO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [{ "url": "gs://your-bucket/1234567890-clip.mp4" }],
    "outputFormat": "mp4",
    "options": [
      { "option": "-c:v", "argument": "libx264" },
      { "option": "-crf", "argument": "23" },
      { "option": "@text-overlay", "argument": {
          "text": "@creator_8842 | id 5f21",
          "style": {
            "position": "bottom-right",
            "fontSize": 36,
            "outlineThickness": 6,
            "margin": 48
          }
        }
      }
    ]
  }'

@text-overlay is a virtual option: a high-level effect that expands to the right drawtext filter server-side. It takes position presets or raw x/y expressions like 0.15*w, plus fontColor, outlineThickness, margin, and textWidth for wrapping. Image overlays and the full current option list live at /docs/virtual-options. Standard flags go in the same array as {option, argument} pairs, so you control the encode alongside the mark.

3. Poll, then download.

curl -H "Authorization: Bearer $FFMPEG_MICRO_KEY" \
  https://api.ffmpeg-micro.com/v1/transcodes/JOB_ID
{
  "success": true,
  "jobId": "job-uuid",
  "status": "completed",
  "outputUrl": "gs://output-bucket/processed-video.mp4",
  "createdAt": "2025-01-01T00:00:00Z",
  "completedAt": "2025-01-01T00:02:30Z"
}

Then GET /v1/transcodes/:id/download returns a signed HTTPS URL you can hand to a browser or a downstream step.

Batch watermarking in n8n, Make, or Zapier

The pattern for watermarking every upload automatically is the same in all three tools:

  1. Trigger on new file (Google Drive, S3, a webhook from your app).
  2. HTTP node: POST to /v1/transcodes with the creator's handle interpolated into the @text-overlay text.
  3. Wait, then poll GET /v1/transcodes/:id on a loop until status is completed or failed.
  4. GET the download URL and push the output wherever it goes next.

The polling loop is where most builds break, because n8n's default HTTP timeout will kill a long job before it finishes. The fix is to never hold the connection open. There's a full recipe in how to fix n8n timeout errors when processing video.

For reconciling a night's batch, GET /v1/transcodes?status=failed&since=2026-08-07T00:00:00Z gives you the ones to retry. Pagination defaults to 20 per page and caps at 100.

CLI vs API

FFmpeg CLI on your boxWatermarking API
SetupInstall FFmpeg, match versions across dev and prodAPI key
200 clipsSequential, or you write a worker pool200 POSTs, concurrent
Long jobsYour process holds the file and the RAMJob ID, poll later
Per-user textShell-escape the string yourselfJSON field
CostServer + your timeFree tier: 100 minutes, 250 MB max input
`-filter_complex`Full supportNot accepted; use options and virtual options

That last row is a real constraint. If your watermark is a hand-tuned multi-input filtergraph, you'll express it as options rather than pasting the graph.

Common pitfalls

Fixed pixel sizes break across aspect ratios. A 300 px logo is 15% of a 1920-wide landscape frame and 28% of a 1080-wide vertical one. Size relative to the frame (iw*0.15) or set position presets and let the service do the math.

Bottom-right is the worst spot for social. On a 1080x1920 Reel or TikTok, roughly the bottom 250 px and the right 180 px sit under platform UI: the caption band, the action rail, the profile bubble. Your mark disappears under a like button. Move it up and left. The Instagram Reels settings post covers the rest of the frame geometry.

Order matters with compression. Watermark first, then compress, and a low-bitrate encoder will smear a thin logo into mush. Compress to your target bitrate, then apply the mark, or do both in one pass with a CRF around 23. See compress video for the web for the bitrate targets.

Watermarking always re-encodes video. You're changing pixels, so there's no stream-copy shortcut. Audio is a different story: -c:a copy keeps the original track untouched and saves real time on long files.

Free-tier inputs cap at 250 MB. A 20-minute 1080p source will blow past that. Starter is $19/month with a 1,024 MB cap and 2,000 processing minutes; Pro is $89/month for 12,000 minutes. Annual billing runs 40% cheaper.

When not to use a watermarking API

Be honest about which problem you have.

  • You need forensic, invisible watermarking. Per-viewer imperceptible marks that survive re-encoding are a separate product category, sold by vendors like NexGuard, Irdeto, and Verimatrix. A visible overlay is deterrence and attribution, not tamper-proof tracing.
  • You need DRM and signed playback. Mux and api.video handle encrypted delivery and token-gated streams. A batch processing API doesn't.
  • Your watermark is really an animated template. If you want keyframed layers, transitions, and a design-tool workflow, Creatomate and Shotstack are template-first by design.
  • You're already deep in Cloudinary. If your images run through Cloudinary transformations today, its video overlays may be less integration work than adding a service, even if the per-minute cost is higher.
  • It's a live stream. Overlaying on a live feed is a streaming-stack job, not an async transcode job.

FAQ

How do I add a watermark to a video programmatically without installing FFmpeg?

Send the video URL and an overlay option to a hosted FFmpeg API. With FFmpeg Micro that's one POST to https://api.ffmpeg-micro.com/v1/transcodes with an @text-overlay or image overlay entry in the options array, then a poll on GET /v1/transcodes/:id. Nothing installs locally, and it works identically from Python, Node, Go, or an HTTP node in n8n.

Can I watermark every uploaded video automatically?

Yes. Trigger on the upload event, POST a transcode job with the watermark option, poll for completion, and store the output. In n8n, Make, or Zapier this is four nodes. In code it's a webhook handler and a background poller.

Does a watermark stop someone from stealing my video?

No. A visible watermark can be cropped, blurred, or covered by anyone with FFmpeg. What it does reliably is attribute the clip when it's reposted as-is, and if the text is unique per user, identify the source of a leak.

Can I use a different watermark for each user?

That's the strongest reason to use an API instead of a pre-rendered logo. The overlay text is a JSON field, so you interpolate the account handle, an order ID, or a session token per request and get a per-user mark with no extra assets.

How much does watermarking videos with an API cost?

FFmpeg Micro bills by processing minutes rather than per job. The free tier gives you 100 video processing minutes with a 250 MB input cap, which is enough to watermark a few hundred short-form clips before you pay anything. Paid plans start at $19/month for 2,000 minutes.

If you want to see the overlay on your own footage before wiring anything up, the playground runs a job against a real file in the browser. Sign up free and the 100 processing minutes are enough to watermark a full batch and check how the mark survives your platform's re-encode.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Skip the command line

The Logo Watermark blueprint stamps your logo on the video for you: upload both files, pick a corner, done.

Run it (free)