Browser library
Add on-device background removal to your own web app with @bg0/browser.
@bg0/browser is the engine behind bg0.dev. It selects a BiRefNet ONNX model for the available hardware, runs it with WebGPU or WebAssembly, and returns a transparent PNG. No server, no API key.
Install
npm install @bg0/browserpnpm add @bg0/browseryarn add @bg0/browserbun add @bg0/browsernub add @bg0/browseraube add @bg0/browserRecover after a failed model load
Transformers.js 4.3.0 queues every ONNX session load and inference call behind the previous one. When one of them fails, every later load in the page fails too, so BG0 cannot fall back from WebGPU to WebAssembly or try again without a reload. bg0.dev ships with a small patch that lets the queue continue after a failure. npm does not apply it for you.
Without the patch, a working load is unaffected. After a failed load, ask the user to reload the page. To get the same recovery as bg0.dev, pin @huggingface/transformers to 4.3.0 and apply the patch with your package manager, for example Bun’s patchedDependencies or patch-package.
Remove a background
import { removeBackground } from '@bg0/browser'
const result = await removeBackground(file, {
quality: 'quality',
onProgress: ({ stage, progress, message }) => console.log(stage, progress, message),
})
const url = URL.createObjectURL(result.blob)
file is any Blob, such as a File from an input or a drop event. PNG, JPG, WebP, HEIC, and HEIF up to 60 MB are accepted. HEIF still collections use their designated primary image; HEIC/HEIF sequences are not supported.
Automatic model selection
The engine uses hardware hints to decide which model to attempt first. It tries full BiRefNet on Chromium WebGPU adapters reporting fp16 shaders, at least a 256 MiB buffer limit and a 128 MiB storage binding limit. A reported device-memory hint below 4 GiB keeps the lite model; browsers that omit that hint remain eligible for full BiRefNet. GPU brand and CPU count do not restrict GPU selection. Without an eligible fp16 GPU, browsers reporting at least four logical CPU cores attempt full BiRefNet on WASM unless they report less than 4 GiB of memory or need the iOS single-threaded compatibility path. Other CPU-only browsers attempt lite. These thresholds are selection heuristics, not a guarantee that a device can run the selected model. Both exports take 512px input; the full model uses the larger Swin-L backbone.
If loading or running the full model fails, the engine retries with lite on
the same provider, then lite on WASM. Failed full-model and GPU combinations
are skipped for the current page session.
prepareBackgroundRemoval() uses the same selection and shares initialization
with removal calls. The quality option controls mask refinement separately.
Choose the model yourself
Pass model to pin which weights download, regardless of what the hardware
hints suggest. MODEL_TIER_BYTES holds each tier’s download size for your UI.
import { MODEL_TIER_BYTES, removeBackground } from '@bg0/browser'
// 94 MiB instead of 452 MiB, for example on a slow connection.
const result = await removeBackground(file, { model: 'lite' })
console.log(MODEL_TIER_BYTES.lite) // 98484532
model |
Behavior |
|---|---|
'auto' |
Default. Hardware-based selection as described above |
'lite' |
Only lite BiRefNet, on WebGPU when the GPU qualifies, otherwise WASM |
'full' |
Full BiRefNet first, even where selection would pick lite. Uses WebGPU when the GPU supports fp16 shaders, otherwise WASM. Lite remains the fallback |
A pinned tier does not override failures already seen in the page session or
the week-long block after a tab died running the full model. result.model
reports what actually ran, and onProgress events carry model once an
engine is chosen. iPhone and iPad ignore the option and keep their own model.
When a call asks for lite, a full-model download that no call is waiting on
stops, so it does not compete with the lite download. A full download that a
pending call still waits on continues until that call finishes or is
cancelled. Session creation is never interrupted. A loaded full session that
no call holds is released, so the page does not keep both models in memory.
iPhone and iPad
On iOS, including desktop-mode iPad, the library uses a dedicated single-threaded
WASM worker and optimized 512px BiRefNet-lite export. It does not attempt the
larger desktop models. Output and sourceBlob are capped at 1280px on the longest
edge without upscaling; width and height describe that bounded output, not the
original photo. Use sourceBlob for a correctly sized comparison preview.
Calls share a serialized worker. A queued aborted call rejects immediately without interrupting the active call; an active inference abort terminates its worker. The next removal can initialize a new worker. Refinement is optional: a failed refinement preserves the base mask, and a dead worker is not reused.
The integrated UI processed three fixtures on a physical iPhone 13. Explicit repeated-run/refinement interactions, native HEIC, iPad, and other iPhones remain unverified; this is not a claim of universal iOS compatibility.
Verification scope
Local verification exercised full and lite BiRefNet with WebGPU and WASM on an Apple M4 Max with 64 GiB RAM, macOS, and Chrome for Testing 153. WebGPU used the physical Apple Metal adapter. Low-memory and CPU-only selection were tested by overriding browser hints on that same Mac; they do not establish support on physical low-memory devices. Windows, Android, iOS, Safari, Firefox, and the deployed origin have not been verified for this model-selection change.
Options
| Option | Type | Default | Meaning |
|---|---|---|---|
quality |
'fast' | 'quality' |
'fast' |
Mask smoothing level. quality costs a little time and gives cleaner edges |
model |
'auto' | 'lite' | 'full' |
'auto' |
Which weights to use. See Choose the model yourself |
onProgress |
(progress) => void |
Called through the preparing, downloading, processing, and finishing stages |
|
signal |
AbortSignal |
Cancel a run. The promise rejects with a BackgroundRemovalError |
prepareBackgroundRemoval({ model, signal }) accepts the same model option.
Its signal stops waiting without cancelling the shared load.
Result
| Field | Type | Meaning |
|---|---|---|
blob |
Blob |
PNG with alpha |
sourceBlob |
Blob | undefined |
Displayable source PNG. Always provided on iOS at the bounded output dimensions; elsewhere provided for HEIC/HEIF and omitted for natively displayable formats |
width, height |
number |
Pixel size of the output |
provider |
'webgpu' | 'wasm' |
Which backend ran the model |
model |
'birefnet' | 'birefnet-lite' |
The model that produced the result, including any fallback |
quality |
'fast' | 'quality' |
Which mask smoothing level was used |
durationMs |
number |
Wall time for the whole call |
Errors
Every failure is a BackgroundRemovalError with a stable code and a message written for end users, so you can show it directly.
import { BackgroundRemovalError } from '@bg0/browser'
try {
await removeBackground(file)
} catch (error) {
if (error instanceof BackgroundRemovalError) toast(error.message)
}
Capabilities
import { getBrowserCapabilities } from '@bg0/browser'
const { webgpu } = getBrowserCapabilities()
Use this to warn users on the WASM path that a large photo will take longer.
Model caching
On desktop/Android, the selected model (about 452 MiB for full BiRefNet or 94 MiB for lite) is fetched from the Hugging Face hub and kept in browser storage. Calls in the same page reuse the initialized model. After a reload, BG0 reuses the stored files but still initializes ONNX and uploads weights to WebGPU. Browsers may evict the files under storage pressure. clearModelCache() resets hardware selection and failure state and clears the IndexedDB fallback cache. It releases engines after any pending preparation or removal calls finish, including refinement. Files already in the browser Cache API may still be reused.
On iOS, model/runtime files are build-emitted same-origin assets cached by HTTP.
Calls queued behind each other reuse the worker. When no call is waiting, the
worker is released after inference to free its memory, so the next call starts
a new runtime from the HTTP-cached files.
clearModelCache() retires the iOS worker after active work finishes. Normal HTTP
cache rules still apply; this does not guarantee eviction of downloaded assets.