npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@useknockout/node

v0.5.0

Published

Official Node.js client for useknockout — state-of-the-art background removal API.

Readme

🥊 @useknockout/node

Open in Spaces

Official TypeScript / Node.js client for useknockout — state-of-the-art background removal API.

MIT License npm version npm downloads GitHub stars TypeScript Node Zero deps

Install · Quick Start · API · Framework examples · API repo

One method call. Transparent PNG out. ~200ms per image.


  • Zero runtime dependencies — uses the native fetch built into Node 18+
  • First-class TypeScript — full types, no anys in the public API
  • Works anywhere fetch works — Node, Bun, Deno, Vercel/Cloudflare Workers, serverless
  • MIT licensed

Install

npm install @useknockout/node
# or
pnpm add @useknockout/node
# or
yarn add @useknockout/node

Requires Node 18+ (for global fetch and FormData).

Quick start

Public beta token

During the public beta, anyone can use this shared bearer token:

kno_public_beta_4d7e9f1a3c5b2e8d6a9f7c1b3e5d8a2f

No signup — copy, paste, call the API. Need your own key / production limits? DM @useknockout on X.

One-minute example

import { writeFile } from "node:fs/promises";
import { Knockout } from "@useknockout/node";

const client = new Knockout({ token: "kno_public_beta_4d7e9f1a3c5b2e8d6a9f7c1b3e5d8a2f" });

// Remove background — returns transparent PNG buffer
const png = await client.remove({ file: "./input.jpg" });
await writeFile("out.png", png);

// Replace background with a hex color
const jpg = await client.replaceBackground({
  file: "./input.jpg",
  bgColor: "#FF5733",
  format: "jpg",
});
await writeFile("out.jpg", jpg);

// Replace background with a remote image
const composed = await client.replaceBackground({
  file: "./input.jpg",
  bgUrl: "https://example.com/beach.jpg",
});

// Batch — remove bg from up to 10 URLs in one call
const batch = await client.removeBatchUrl({
  urls: ["https://example.com/a.jpg", "https://example.com/b.jpg"],
});
for (const r of batch.results) {
  if (r.success) {
    await writeFile(`out.png`, Buffer.from(r.data_base64!, "base64"));
  }
}

From a Buffer or remote URL

// From a Buffer (e.g. uploaded via multer)
const buf = await fs.readFile("./input.jpg");
const out = await client.remove({ file: buf, filename: "input.jpg" });

// From a remote URL
const png = await client.removeUrl({ url: "https://example.com/cat.jpg" });

New in 0.0.5 — presets

// Sticker — thick outline, transparent bg (iMessage / WhatsApp style)
const sticker = await client.sticker({ file: "./photo.jpg", strokeWidth: 24 });

// Outline — thin stroke around subject
const outlined = await client.outline({ file: "./photo.jpg", outlineColor: "#000000", outlineWidth: 4 });

// Smart crop — auto-crop to subject bbox + padding
const cropped = await client.smartCrop({ file: "./photo.jpg", padding: 32 });

// Shadow — drop shadow on a new background
const withShadow = await client.shadow({ file: "./photo.jpg", bgColor: "#F3F4F6" });

// Studio shot — e-commerce preset (centered subject, white bg, shadow, square)
const studio = await client.studioShot({ file: "./photo.jpg", aspect: "1:1" });

// Compare — before/after side-by-side image
const preview = await client.compare({ file: "./photo.jpg" });

// Mask — just the black/white mask for your own pipeline
const mask = await client.mask({ file: "./photo.jpg" });

API

new Knockout(options?)

| Option | Type | Default | Description | |---|---|---|---| | token | string | — | Bearer token. Required unless self-hosting without auth. | | baseUrl | string | https://useknockout--api.modal.run | Override the API endpoint. | | timeoutMs | number | 60_000 | Per-request timeout. | | fetch | typeof fetch | globalThis.fetch | Custom fetch (for edge runtimes or polyfills). |

client.remove(input)

Remove the background from a local file or in-memory buffer.

| Field | Type | Description | |---|---|---| | file | string \| Buffer \| Blob \| ArrayBuffer \| Uint8Array | File path or raw image bytes. | | filename | string? | Optional override — auto-inferred from path if omitted. | | format | "png" \| "webp" | Output format. Default "png". |

Returns: Buffer of the processed image (PNG or WebP with transparent alpha).

client.removeUrl(input)

Remove the background from a remote image URL.

| Field | Type | Description | |---|---|---| | url | string | Remote image URL. | | format | "png" \| "webp" | Output format. Default "png". |

Returns: Buffer of the processed image.

client.replaceBackground(input)

Remove the background and composite the subject onto a new background — solid color or remote image.

| Field | Type | Description | |---|---|---| | file | string \| Buffer \| Blob \| ArrayBuffer \| Uint8Array | Foreground image (path or bytes). | | filename | string? | Optional filename. | | bgColor | string? | Hex color for the new background. Default "#FFFFFF". Ignored if bgUrl is set. | | bgUrl | string? | Remote URL of a background image. Takes precedence over bgColor. | | format | "png" \| "webp" \| "jpg" | Output format. Default "png". "jpg" for smallest file. |

Returns: Buffer of the composited image. Edges refined via closed-form foreground matting (no halos).

client.removeBatch(input)

Remove backgrounds from up to 10 images in a single call.

| Field | Type | Description | |---|---|---| | files | Array<string \| Buffer \| Blob \| ArrayBuffer \| Uint8Array> | 1–10 file paths or buffers. | | filenames | string[]? | Optional filename aligned to each file. | | format | "png" \| "webp" | Output format. Default "png". |

Returns: BatchResponse{ count, format, results: [{ filename, success, format, size_bytes, data_base64 | error }] }. Decode data_base64 with Buffer.from(b64, "base64").

client.removeBatchUrl(input)

Same as removeBatch but takes a JSON array of remote URLs.

| Field | Type | Description | |---|---|---| | urls | string[] | 1–10 remote image URLs. | | format | "png" \| "webp" | Output format. Default "png". |

Returns: BatchResponse with url in place of filename in each result.

client.mask(input)

Return just the black/white alpha mask as a grayscale PNG/WebP.

| Field | Type | Description | |---|---|---| | file | FileInput | Image to process. | | format | "png" \| "webp" | Default "png". |

Returns: Buffer of a grayscale image (0 = bg, 255 = subject).

client.smartCrop(input)

Auto-crop to the subject's tight bounding box + padding.

| Field | Type | Description | |---|---|---| | file | FileInput | Image to process. | | padding | number | Padding in pixels. Default 24. | | transparent | boolean | true → transparent cutout. false → cropped from original. Default true. | | format | "png" \| "webp" \| "jpg" | Default "png" (or "jpg" when transparent=false). |

client.shadow(input)

Composite subject onto a new background with a configurable drop shadow.

| Field | Type | Description | |---|---|---| | file | FileInput | Image to process. | | bgColor | string | Hex color. Default "#FFFFFF". | | bgUrl | string | Remote URL. Takes precedence over bgColor. | | shadowColor | string | Default "#000000". | | shadowOffsetX | number | Default 8. | | shadowOffsetY | number | Default 12. | | shadowBlur | number | Default 14. | | shadowOpacity | number | 0.0–1.0. Default 0.45. | | format | "png" \| "webp" \| "jpg" | Default "png". |

client.sticker(input)

Subject with a thick outline on transparent background — sticker style.

| Field | Type | Description | |---|---|---| | file | FileInput | Image to process. | | strokeColor | string | Default "#FFFFFF". | | strokeWidth | number | Pixels. Default 20, capped at 80. | | format | "png" \| "webp" | Default "png". |

client.outline(input)

Subject with a thin outline on transparent background.

| Field | Type | Description | |---|---|---| | file | FileInput | Image to process. | | outlineColor | string | Default "#000000". | | outlineWidth | number | Pixels. Default 4, capped at 60. | | format | "png" \| "webp" | Default "png". |

client.studioShot(input)

E-commerce preset: cutout + centered on canvas + optional drop shadow + standardized aspect ratio.

| Field | Type | Description | |---|---|---| | file | FileInput | Image to process. | | bgColor | string | Canvas color. Default "#FFFFFF". | | aspect | string | "W:H" format, e.g. "1:1", "4:5", "16:9". Default "1:1". | | padding | number | Padding in pixels. Default 48. | | shadow | boolean | Include drop shadow. Default true. | | transparent | boolean | Keep a transparent background. Ignores bgColor and shadow; output is PNG (jpg is coerced). Default false. | | enhance | boolean | Apply a subtle brightness + saturation lift to the subject for ecommerce-ready output. Default false. | | enhanceStrength | number | Lift amount, 0.00.5. Default 0.15. Only applies when enhance is true. | | format | "png" \| "webp" \| "jpg" | Default "jpg". |

// Transparent product cutout, centered & squared
const cutout = await client.studioShot({ file: "./product.jpg", transparent: true });

// Ecommerce-ready shot with a brightness + saturation boost
const bright = await client.studioShot({ file: "./product.jpg", aspect: "1:1", enhance: true });

client.compare(input)

Before/after side-by-side preview — original on the left, transparent cutout (on a checkerboard) on the right.

| Field | Type | Description | |---|---|---| | file | FileInput | Image to process. | | format | "png" \| "webp" | Default "png". |

client.headshot(input) — v0.4.0

Studio-quality professional headshot — background removed, neutral studio backdrop, optional soft drop shadow, smart crop to bust framing.

| Field | Type | Description | |---|---|---| | file | FileInput | Source portrait. | | bgColor | string | Studio backdrop hex. Default "#f5f5f5". | | addShadow | boolean | Soft drop shadow. Default true. | | crop | "bust" \| "head" \| "full" | Default "bust". | | format | "png" \| "webp" \| "jpg" | Default "png". |

client.preview(input) — v0.4.0

Cheap, fast low-res preview — 512px max, ~1.5s. Use for thumbnail UI before user pays for full-res.

| Field | Type | Description | |---|---|---| | file | FileInput | Source image. | | maxSize | number | Max edge length. Default 512. | | watermark | boolean | Add useknockout watermark. Default false. |

client.estimate(input) — v0.4.0

Returns expected processing time + output size without running the model. Show users "this'll take ~3s, ~1.2 MB" before they hit submit.

const est = await client.estimate({ width: 2048, height: 1536, endpoint: "remove" });
// { estimated_seconds: 2.4, estimated_output_kb: 1180, warm: true }

client.stats() — v0.4.0

Public stats — total images processed, last-24h count, last-7d trend. Powered by Modal Dict cross-container counter. No auth required.

const stats = await client.stats();
// { total: 12340, last_24h: 312, last_7d: [...] }

client.upscale(input) — v0.6.0

Swin2SR / Real-ESRGAN x2/x4 super-resolution. Defaults to Swin2SR (SwinV2 Transformer) — sharper detail and natural texture on real photos. Pass model: "realesrgan" for the legacy backend (better on anime / illustrations).

const big = await client.upscale({ file: "./small.jpg", scale: 4 });
const anime = await client.upscale({ file: "./art.png", scale: 4, model: "realesrgan" });

| Field | Type | Description | |---|---|---| | file | FileInput | Source image. | | scale | 2 \| 4 | Default 4. | | model | "swin2sr" \| "realesrgan" | Default "swin2sr". | | format | "png" \| "webp" \| "jpg" | Default "png". |

client.faceRestore(input) — v0.5.0

GFPGAN v1.4 face restoration. Detects faces, restores blurred/compressed/damaged ones while preserving identity. Background also upscaled. Multi-face safe.

const restored = await client.faceRestore({ file: "./blurry-portrait.jpg" });

| Field | Type | Description | |---|---|---| | file | FileInput | Image with one or more faces. | | format | "png" \| "webp" \| "jpg" | Default "png". |

client.colorize(input) — v0.7.0

DDColor colorization. Turns black-and-white or faded photos into natural color. Single call, no params required.

const colored = await client.colorize({ file: "./old-photo.jpg" });

| Field | Type | Description | |---|---|---| | file | FileInput | Grayscale or faded source image. | | format | "png" \| "webp" \| "jpg" | Default "png". |

client.silhouette(input) — v0.7.1

Two-tone silhouette portrait. Runs BiRefNet, then flattens subject and background into two solid colors. Defaults to a purple subject on white.

const sil = await client.silhouette({ file: "./portrait.jpg" });
const custom = await client.silhouette({ file: "./portrait.jpg", subjectColor: "#000000", bgColor: "#F5F5F5" });

| Field | Type | Description | |---|---|---| | file | FileInput | Source image. | | subjectColor | string | Hex color for the subject. Default "#7C3AED". | | bgColor | string | Hex color for the background. Default "#FFFFFF". | | format | "png" \| "webp" \| "jpg" | Default "png". |

client.inpaint(input) — v0.8.0

LaMa large-mask inpainting (Apache-2.0). Removes objects or fills regions. Three modes: auto-subject (no mask/bbox — runs BiRefNet and inverts the subject), mask (white pixels = inpaint), or bbox (rectangular region).

// auto-subject: erase the main subject
const clean = await client.inpaint({ file: "./photo.jpg" });
// mask mode
const masked = await client.inpaint({ file: "./photo.jpg", mask: "./mask.png" });
// bbox mode
const region = await client.inpaint({ file: "./photo.jpg", bbox: { x: 100, y: 100, w: 300, h: 400 } });

| Field | Type | Description | |---|---|---| | file | FileInput | Source image. | | mask | FileInput | Optional. White pixels = inpaint, black = keep. Mutually exclusive with bbox. | | bbox | { x, y, w, h } | Optional rectangular region to inpaint. Mutually exclusive with mask. | | dilation | number | Mask dilation in pixels. Default 8, range 0..32. | | format | "png" \| "webp" \| "jpg" | Default "png". |

client.health()

Returns: Promise<{ status: string; model: string }>. No auth required.

KnockoutError

Thrown on any non-2xx response. Fields:

  • status — HTTP status code
  • code"auth" | "rate_limit" | "bad_request" | "payload_too_large" | "server" | "unknown"
  • body — raw response body string
import { KnockoutError } from "@useknockout/node";

try {
  await client.remove({ file: "./huge.jpg" });
} catch (err) {
  if (err instanceof KnockoutError && err.code === "payload_too_large") {
    // retry with a resized image
  }
  throw err;
}

Framework examples

Next.js App Router

// app/api/remove/route.ts
import { Knockout } from "@useknockout/node";

const client = new Knockout({ token: process.env.KNOCKOUT_TOKEN! });

export async function POST(req: Request) {
  const form = await req.formData();
  const file = form.get("file") as File;
  const buf = Buffer.from(await file.arrayBuffer());

  const png = await client.remove({ file: buf, filename: file.name });

  return new Response(new Uint8Array(png), {
    headers: { "Content-Type": "image/png" },
  });
}

Express

import express from "express";
import multer from "multer";
import { Knockout } from "@useknockout/node";

const app = express();
const upload = multer();
const client = new Knockout({ token: process.env.KNOCKOUT_TOKEN! });

app.post("/remove", upload.single("file"), async (req, res) => {
  const png = await client.remove({
    file: req.file!.buffer,
    filename: req.file!.originalname,
  });
  res.type("image/png").send(png);
});

Cloudflare Workers / Vercel Edge

import { Knockout } from "@useknockout/node";

const client = new Knockout({ token: env.KNOCKOUT_TOKEN });

export default {
  async fetch(req: Request) {
    const { searchParams } = new URL(req.url);
    const imageUrl = searchParams.get("url")!;
    const png = await client.removeUrl({ url: imageUrl });
    return new Response(new Uint8Array(png), {
      headers: { "Content-Type": "image/png" },
    });
  },
};

Self-hosting

Point the SDK at your own Modal deployment:

const client = new Knockout({
  token: "your-self-hosted-token",
  baseUrl: "https://YOUR_WORKSPACE--api.modal.run",
});

See useknockout/api for the Modal deployment.

License

MIT — see LICENSE.