unscreen.io logounscreen.io
HomeNEWUnscreen App
Video Editor
Video Background RemoverRemove Background from MP4Remove Video Background Online
Social Medias
Remove Background from TikTok VideoRemove Background from Facebook ReelsRemove Background from InstagramRemove Background from YouTube Video
100% FREEFREE UnscreenAPIPricing
Checking account…Get Started

Product

  • Unscreen Alternative
  • Features
  • API
  • Pricing

Resources

  • Blog
  • Migration Guide
  • Documentation

Company

  • About
  • Contact
  • Status

Legal

  • Privacy Policy
  • Terms of Service
  • Imprint
unscreen.io logounscreen.io

© 2026 unscreen.io. All rights reserved.

Made inGermany bywww.RemBG.com

  1. Home
  2. Blog
  3. Remove a Video Background with JavaScript and Node.js
Tutorials

Remove a Video Background with JavaScript and Node.js

Build a Node.js video background removal workflow with @unscreen/video-background-remover, including polling with wait and webhook callbacks without wait.

unscreen.io TeamMay 11, 202612 min read

JavaScript is a practical way to automate video background removal. Instead of uploading each clip by hand, you can submit a video from Node.js, let Unscreen process it, and download the finished transparent or background-removed result from your own script, backend route, queue worker, or content pipeline.

This guide shows how to use @unscreen/video-background-remover from install to production-style usage. You will see two main approaches:

  • wait for a job to finish inside the same Node.js process
  • submit the job without waiting and receive the result through a webhook callback

1. Install the SDK

The package is published as an npm Node.js library and requires Node.js 20 or newer.

npm install @unscreen/video-background-remover

Set your API key as an environment variable:

export UNSCREEN_API_KEY="your_api_key_here"

In production, set the same variable in your hosting provider, CI runner, container secret, or server environment. Do not ship the API key to browser-side JavaScript.

2. Create a client

Create one Unscreen client and reuse it where you submit jobs.

import { Unscreen } from "@unscreen/video-background-remover";

const unscreen = new Unscreen({
  apiKey: process.env.UNSCREEN_API_KEY,
});

The SDK reads the API key from UNSCREEN_API_KEY when you pass it explicitly like this. Keeping it explicit also makes tests and deployment configuration easier to understand.

3. Fastest path: remove and download with wait

For a simple Node.js script, use removeBackground. When no webhookUrl is provided, this convenience method waits for the job to complete by default.

import { Unscreen } from "@unscreen/video-background-remover";

const unscreen = new Unscreen({
  apiKey: process.env.UNSCREEN_API_KEY,
});

await unscreen.removeBackground({
  input: "./input.mp4",
  output: "./output.mp4",
  mode: "auto",
});

console.log("Saved ./output.mp4");

This flow creates the job, uploads the local video, starts processing, waits until the status is terminal, and writes the finished output video to ./output.mp4.

The mode option accepts auto or human_only. Use auto when Unscreen should detect the foreground subject automatically, and use human_only when the clip should focus on people as the foreground.

4. Manual polling with "jobs.wait"

If you want more control, split the workflow into explicit steps:

import { Unscreen } from "@unscreen/video-background-remover";

const unscreen = new Unscreen({
  apiKey: process.env.UNSCREEN_API_KEY,
});

const started = await unscreen.jobs.submit({
  input: "./input.mp4",
  mode: "auto",
});

console.log(`Started job ${started.jobId}`);

const completed = await unscreen.jobs.wait(started.jobId, {
  intervalMs: 2000,
  timeoutMs: 10 * 60 * 1000,
});

await unscreen.jobs.download(completed, {
  asset: "outputVideo",
  path: "./output.mp4",
});

console.log(`Downloaded result for ${completed.jobId}`);

jobs.wait polls the job status until it becomes completed or failed. If the job fails, the SDK throws an UnscreenError. If it takes longer than timeoutMs, it throws an UnscreenTimeoutError.

5. Use a remote video URL instead of a local file

The input field can be a local path, a remote HTTP(S) URL, a Blob, an ArrayBuffer, or a Uint8Array.

const completed = await unscreen.removeBackground({
  input: "https://example.com/videos/product-demo.mp4",
  output: "./product-demo-no-background.mp4",
  mode: "auto",
});

console.log(completed.status);

When you use a remote URL, the SDK fetches the file and uploads it to the Unscreen job. If the URL does not expose a recognizable video content type, you can pass contentType manually:

await unscreen.jobs.submit({
  input: "https://example.com/download?id=123",
  contentType: "video/mp4",
});

6. Download different result assets

The default download asset is outputVideo. You can also request other assets when they are available on the completed job:

await unscreen.jobs.download(completed, {
  asset: "alphaVideo",
  path: "./alpha.webm",
});

await unscreen.jobs.download(completed, {
  asset: "mask",
  path: "./mask.mp4",
});

Supported asset names are:

  • outputVideo
  • alphaVideo
  • mask
  • previewImage
  • metadata

Use the asset that matches your pipeline. For example, a creator tool may need outputVideo, while a compositing workflow may prefer alphaVideo or mask.

7. Submit without wait by using a webhook callback

Polling is simple, but it keeps your Node.js process busy until the video is done. For web apps, marketplaces, user uploads, and background queues, a webhook is usually better.

When you pass webhookUrl, removeBackground submits and starts the job without waiting unless you explicitly set wait: true.

import { Unscreen } from "@unscreen/video-background-remover";

const unscreen = new Unscreen({
  apiKey: process.env.UNSCREEN_API_KEY,
});

const started = await unscreen.removeBackground({
  input: "./input.mp4",
  mode: "auto",
  webhookUrl: "https://example.com/api/webhooks/unscreen",
});

console.log(`Started ${started.jobId}; waiting for webhook callback`);

This returns after the upload and start request. Your server receives the completion event later.

8. Handle the webhook event in Node.js

Here is a minimal Express-style endpoint:

import express from "express";
import { writeFile } from "node:fs/promises";

const app = express();

app.use(express.json());

app.post("/api/webhooks/unscreen", async (req, res) => {
  const event = req.body;

  if (event.eventType === "video.completed") {
    console.log(`Job completed: ${event.jobId}`);

    if (event.resultUrl) {
      const response = await fetch(event.resultUrl);
      const arrayBuffer = await response.arrayBuffer();

      await writeFile(
        `./downloads/${event.jobId}.mp4`,
        Buffer.from(arrayBuffer)
      );
    }
  }

  if (event.eventType === "video.failed") {
    console.error(`Job failed: ${event.jobId}`);
  }

  res.sendStatus(200);
});

app.listen(3000, () => {
  console.log("Webhook server listening on http://localhost:3000");
});

For a production app, store the jobId when you submit the job, then update that database row when the webhook arrives. The webhook should respond quickly with a 2xx status after you have accepted the event.

9. Type the webhook event

If you write TypeScript, import the WebhookEvent type:

import type { WebhookEvent } from "@unscreen/video-background-remover";

export async function handleUnscreenWebhook(event: WebhookEvent) {
  if (event.eventType === "video.completed") {
    console.log(event.jobId, event.resultUrl);
    return;
  }

  if (event.eventType === "video.failed") {
    console.error(`Unscreen job failed: ${event.jobId}`);
  }
}

Webhook event names are video.completed and video.failed.

10. Force wait even when using a webhook

Most webhook flows should not wait. But if you need both a webhook and a synchronous result, pass wait: true:

const completed = await unscreen.removeBackground({
  input: "./input.mp4",
  output: "./output.mp4",
  webhookUrl: "https://example.com/api/webhooks/unscreen",
  wait: true,
  waitOptions: {
    intervalMs: 3000,
    timeoutMs: 15 * 60 * 1000,
  },
});

console.log(completed.status);

This is useful for internal tooling, but most user-facing apps should prefer the non-waiting webhook pattern so requests do not stay open for a long video.

11. Check credits before a batch

For batch jobs, check the current credit balance before submitting work:

const balance = await unscreen.credits.getBalance();

console.log(`Credits remaining: ${balance.credits}`);

You can use this before queueing a folder of videos or before accepting a paid user upload.

12. Basic error handling

Wrap job submission, waiting, and downloads in try/catch:

import {
  Unscreen,
  UnscreenError,
  UnscreenTimeoutError,
} from "@unscreen/video-background-remover";

const unscreen = new Unscreen({
  apiKey: process.env.UNSCREEN_API_KEY,
});

try {
  await unscreen.removeBackground({
    input: "./input.mp4",
    output: "./output.mp4",
    waitOptions: {
      timeoutMs: 10 * 60 * 1000,
    },
  });
} catch (error) {
  if (error instanceof UnscreenTimeoutError) {
    console.error("The job is still running. Check status later.");
  } else if (error instanceof UnscreenError) {
    console.error(error.message);
  } else {
    throw error;
  }
}

For queues and background workers, store the jobId as soon as you receive it. That lets you inspect status later even if a worker restarts.

Which flow should you choose?

Choose wait when:

  • you are building a CLI script
  • the video is short enough for the process to stay open
  • you want the output file immediately
  • the job is part of a controlled batch worker

Choose webhook callbacks when:

  • users upload videos through your app
  • jobs may take longer than an HTTP request should stay open
  • you need reliable async processing
  • you want to update a database, dashboard, email, or notification after completion

The SDK supports both patterns, so you can start with the simple wait workflow and move to webhooks when your app needs asynchronous processing.

Complete wait example

import { Unscreen } from "@unscreen/video-background-remover";

const unscreen = new Unscreen({
  apiKey: process.env.UNSCREEN_API_KEY,
});

const completed = await unscreen.removeBackground({
  input: "./input.mp4",
  output: "./output.mp4",
  mode: "auto",
  waitOptions: {
    intervalMs: 2000,
    timeoutMs: 10 * 60 * 1000,
  },
});

console.log(`Finished ${completed.jobId}`);

Complete webhook example

import { Unscreen } from "@unscreen/video-background-remover";

const unscreen = new Unscreen({
  apiKey: process.env.UNSCREEN_API_KEY,
});

const started = await unscreen.removeBackground({
  input: "./input.mp4",
  mode: "auto",
  webhookUrl: "https://example.com/api/webhooks/unscreen",
});

console.log(`Submitted ${started.jobId}`);

That is the core Node.js workflow: install the SDK, create a client, submit a video, and decide whether your app should wait for the result or receive it later through a webhook.

Related Articles

Tutorials

How to Remove Video Background Without a Green Screen: AI Solutions in 2025

Learn how to remove video backgrounds without a green screen using AI technology. Step-by-step guide, tool comparisons, and pro tips for creators.

Tutorials

Free Online Video Background Remover: What You Actually Get vs The Promises

Honest comparison of free video background remover tools. Learn about real limitations, hidden costs, and when it makes sense to upgrade to paid plans.