Why async matters for video
I've been running useKnockout - a background removal API that processes images in ~200ms - for a few months. Images are fast enough to handle synchronously: POST a file, wait 200ms, get a PNG back.
Video is different. Even a 5-second clip at 30fps is 150 frames. At 200ms per frame, that's 30 seconds of processing. You can't hold an HTTP connection open for 30 seconds and call it a good API.
So today I shipped POST /video/remove - async video background removal that returns a job ID immediately, processes in the background, and gives you ProRes 4444 (RGB+alpha) when it's done.
What shipped
As of v0.11.0 (July 10, 2026):
-
POST /video/remove- upload a video, get a job ID back -
GET /jobs/{job_id}- poll for status, download the result when ready - ProRes 4444 output - RGB with full alpha channel, ready to drop into Premiere/Final Cut/DaVinci
- Node SDK
videoRemove()andgetJob()in v0.7.0 - Python SDK
video_remove()andget_job()in v0.7.0
Billing is a dedicated video.seconds meter at $0.10/sec (different from the per-image rate), with a 15-second cap to keep costs predictable.
How to use it (Node SDK)
import { useKnockout } from 'useknockout-node';
import fs from 'fs';
const client = useKnockout({ apiKey: process.env.KNOCKOUT_API_KEY });
// Submit the video
const job = await client.videoRemove({
file: fs.createReadStream('./input.mp4')
});
console.log('Job ID:', job.id);
// Poll until done
let status = await client.getJob(job.id);
while (status.status === 'processing') {
await new Promise(resolve => setTimeout(resolve, 2000));
status = await client.getJob(job.id);
}
if (status.status === 'completed') {
// Download the ProRes 4444 result
const video = await fetch(status.result_url);
const buffer = await video.arrayBuffer();
fs.writeFileSync('./output.mov', Buffer.from(buffer));
}
The job object includes duration_seconds (billed amount), status (processing/completed/failed), and result_url when done.
Billing: $0.10/sec, 15s cap
Video uses its own meter (video.seconds) so you can track image vs. video usage separately. A 7-second clip costs $0.70. Clips longer than 15 seconds are trimmed (the 15s cap keeps runaway bills from killing indie projects).
For context, useKnockout's image endpoint is ~$0.005/image on the starter tier - about 40x cheaper than remove.bg's $0.11-$0.23/image. Video is more expensive per second of processing, but still priced for solo builders.
Other recent additions
Before video, I shipped:
- POST /collage (July 3) - N-photo product collages, billed N units. Pass 4 product shots, get a 2×2 grid back.
- RealESRGAN upscaling (July 2) - default upscale switched to RealESRGAN with refined alpha matting and linear compositing.
-
studio-shot enhance (June 22) - GFPGAN face restoration now available on
/studio-shotwithenhance=true.
All of these shipped in the last month because the API is self-hostable (MIT-licensed) and I'm the only one shipping it - no committee, no quarters, just daily commits.
Why this matters
Most indie devs I talk to are either:
- Paying remove.bg [placeholder: $X/mo] and wincing at the bill, or
- Avoiding background removal features entirely because the APIs are too expensive.
Video makes it worse - remove.bg doesn't do video at all. Other video APIs charge per frame (30fps × 5sec = 150 frames × $0.10 = $15 for 5 seconds).
At $0.10/sec, that same 5-second clip costs $0.50. Still not free, but it's in "I can actually ship this feature" territory.
What's next
I'm working on batch video (submit 10 clips, get 10 job IDs back) and a webhook callback option so you don't have to poll. The async job pattern is solid now - those are just API surface.
If you're building something that needs video background removal (marketplace demos, avatar videos, TikTok filters, whatever), the SDKs are on npm/PyPI and the API is at useknockout.com. Free tier includes 10 images/month across 5 endpoints. Video is pay-as-you-go.
No lock-in - it's MIT-licensed if you want to self-host. But the hosted version is live and you can start with a curl:
curl -X POST https://useknockout--api.modal.run/video/remove \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@input.mp4"
You'll get a job ID back. Poll /jobs/{id} until it's done, then download the ProRes file. That's it.
Top comments (0)