APIMODELSAPIMODELS

Video Eraser (subtitles, watermarks, logos)

Remove hardcoded subtitles, on-screen text and text watermarks from a video, rebuilding a clean background where they were. High-frame-rate detection plus AIGC inpainting with multi-frame consistency, so the patch does not shimmer. Two ways to say what should go: automatic mode finds the text for you, and region mode works on rectangles you supply — the route for watermarks, station bugs and signatures, which detection would never classify as text (solid-colour graphic logos are unreliable; see below). Output resolution matches the input (up to 1080p), billed $0.015 per second of video, charged only on success.

Read this first: draw the box generously

In region mode, make the rectangle about 30-50% larger than the mark itself. A box cropped tight to the mark very often returns the video unchanged, while the same mark with margin around it is removed cleanly. For a corner logo, run the box out to the frame edges — there is nothing there to protect.

This is by far the most common reason a region erase appears to do nothing — and we learned it the hard way: our own first tests boxed the mark exactly and we nearly concluded the feature was broken.

The two modes

eraseModeUse it forWhat the boxes do
auto (default)Hardcoded subtitles, any on-screen textOptional. They only NARROW detection — just the text found inside them is erased
manualText watermarks (e.g. @handles), signatures, text in station bugs and corner marks; solid-colour graphic logos are unreliableRequired. The boxes ARE the target — no reliance on text detection

The same eraseRatioLocation means two different things depending on the mode, and this is the easy mistake: box a text-free logo in auto mode and nothing changes at all, because there is no text inside the box to find. To erase something that is not text, switch to manual.

Measured 2026-10-18 on a synthetic clip: a semi-transparent text watermark ("@demo_channel") came out cleanly in manual mode, and also in auto mode with eraseType "text"; a solid-colour graphic logo, boxed 30-50% larger, was left essentially untouched by manual mode. Try a short segment before running a whole video when the mark is a graphic logo.

Create a task

POST /api/v1/video/generations — async: create, then poll the same endpoint for the result.

# ── Region mode — remove a watermark / corner logo ──────────────────────
# Box the mark with normalized 0-1 coordinates (fractions of width/height).
curl -X POST https://api.apimodels.app/v1/video/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "subtitle-erase",
    "video_url": "https://example.com/clip-with-watermark.mp4",
    "eraseMode": "manual",
    "eraseRatioLocation": [
      { "topLeftX": 0.70, "topLeftY": 0.02, "bottomRightX": 1.0, "bottomRightY": 0.20 }
    ]
  }'

# ⚠️ Draw the box GENEROUSLY — about 30-50% larger than the mark itself.
# A box cropped tight to the mark very often returns the video unchanged.
# For a corner logo, run the box out to the frame edges as above.

# ── Automatic mode — remove hardcoded subtitles (no box needed) ─────────
curl -X POST https://api.apimodels.app/v1/video/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "subtitle-erase",
    "video_url": "https://example.com/clip-with-subtitles.mp4",
    "eraseType": "subtitle"
  }'

# Poll until state == "completed" — data.resultUrls[0] is the cleaned video.
# Result files are kept 30 days.
curl "https://api.apimodels.app/v1/video/generations?task_id=TASK_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"

Request parameters

FieldRequiredTypeDescription
modelYesstringAlways subtitle-erase
video_urlYesstringPublic URL of the video to clean (MP4 / MOV). videoUrl is accepted too
eraseModeNostring"auto" (default — detects text for you) or "manual" (works on your boxes; eraseRatioLocation then required)
eraseTypeNostring"subtitle" (default, caption-style only) or "text" (any on-screen text). Auto mode only
eraseRatioLocationNoarrayNormalized (0-1) boxes [{ topLeftX, topLeftY, bottomRightX, bottomRightY }]. Required in manual mode. ⚠️ Draw them 30-50% larger than the mark
clipFilterNoobject{ mode: "Selected" | "Skip", clips: [{ start, end }] } — in seconds, clean only ("Selected") or skip ("Skip") these ranges. Works in both modes
callback_urlNostringCalled when the task finishes, so you can skip polling

Both spellings are accepted: eraseMode / erase_mode, eraseType / erase_type, eraseRatioLocation / erase_ratio_location, clipFilter / clip_filter. If both are sent, the camelCase one wins. clipFilter.mode is case-insensitive.

What a failure looks like

  • Rejected at creation: the HTTP status is the error code and the body is { code, msg }. 400 means a bad request (no video_url, an invalid value, manual mode without boxes) or a video whose duration cannot be read (private or expired link); 401 means an invalid API key; 402 means insufficient balance. No task is created and nothing is charged.
  • Created but failed during processing: polling GET ?task_id= still returns HTTP 200 and code 200, and the failure is in data — data.state is "failed", data.failCode / data.failMsg give the reason, data.credits is 0 (fully refunded), and data.retryable says whether a retry is worth it. Typical causes: the source video could not be imported (the link expired mid-job), or processing ran past the 60-minute limit. With callback_url set, the callback carries the same data.

Billing and limits

  • $0.015 per second, billed on the INPUT video duration, charged only on success and refunded on failure. 30 seconds = $0.45, 3 minutes = $2.70.
  • Limiting the job with clipFilter does NOT reduce the price — the whole file still has to be decoded and re-encoded.
  • Processing is measured in minutes: a 30–60 second clip usually takes around 10 minutes, most finish within 16, and an occasional one takes longer. Nearly all of it is the per-frame text detection and inpainting itself, not queueing — this is normal, not a stalled task. Use callback_url rather than holding a long poll.
  • There is no hard duration limit, but a task that has not finished within 60 minutes fails as a timeout (fully refunded). Keep each request to 60 seconds or less, and split longer videos into segments of up to 60 seconds.
  • The source URL must stay reachable for the whole job — give presigned URLs a lifetime of at least 30 minutes (import usually finishes in seconds, but an expired URL fails the task).
  • Output resolution matches the input, capped at 1080p.
  • Result files are kept for 30 days — download or re-host anything you need to keep.
  • A mark that stays put is the easy case; for one that moves, give several boxes covering its path or split the timeline with clipFilter. A mark drifting across the whole frame is not a good fit.
  • Whether removing a watermark is lawful depends entirely on the footage and is your call: cleaning your own or licensed material is ordinary post-production, stripping a mark from someone else's copyrighted work to republish it is not.

Related

FAQ

Can I remove a watermark from a video with an API?

Yes. POST the video URL plus a normalized 0-1 rectangle around the mark to /api/v1/video/generations with model "subtitle-erase" and eraseMode "manual", then poll the task id. You get back a video with the background rebuilt where the mark was, at the input resolution up to 1080p, for $0.015 per second.

Why was my watermark not removed?

Almost always the box was too tight. Draw it roughly 30-50% larger than the mark — a rectangle cropped to the visible edge frequently returns the video unchanged, while the same mark with margin is removed cleanly. Also check that eraseMode is "manual": in the default auto mode your boxes only narrow where text detection may look, so a box around a text-free logo changes nothing. Coordinates are fractions of width and height between 0 and 1, not pixels.

How much does it cost to remove subtitles or a watermark from video?

$0.015 per second of the input video, charged only on success — 30 seconds is $0.45 and 3 minutes is $2.70. Subtitles, on-screen text and watermarks are all the same price. Restricting the job to part of the timeline with clipFilter does not lower it, because the whole file is still decoded and re-encoded.

How long does subtitle or watermark removal take?

Minutes, not seconds: a 30-second 1080p clip typically takes 10–14 minutes and a 60-second clip about 14–16 (measured on production jobs). Nearly all of that time is the per-frame text detection and inpainting itself rather than queueing, so a task that has been running for ten minutes is normal, not stalled. Use callback_url instead of holding a long poll, and keep the source URL reachable for at least 30 minutes.

Do I need to draw a box to remove hardcoded subtitles?

No. Leave eraseMode out and it runs automatically: eraseType "subtitle" (the default) removes caption-style subtitles wherever they appear, and eraseType "text" removes any on-screen text. Boxes are optional there and only narrow where detection looks, which helps when you want the lower third cleaned but a title card kept.

What video formats and resolutions are supported?

MP4 and MOV input via a public URL. Output resolution matches the input and is capped at 1080p by the upstream. It is an async create-then-poll job; result files are hosted for 30 days, so download or re-host anything you need to keep.