Dev.to WebDev ๐Ÿ›  Dev ๐Ÿ‘ 0 ๐Ÿ“– 2 min read

Shipping in-browser WASM background removal without crashing Safari tabs (+ an open real-device latency dataset)

Over the past month I built and shipped remove.ac, an image background remover split into two explicit execution paths: a free in-browser WebAssembly studio where image bytes stay inside the tab, and an optional stateles

Over the past month I built and shipped remove.ac, an image background remover split into two explicit execution paths: a free in-browser WebAssembly studio where image bytes stay inside the tab, and an optional stateless Cloud GPU API (POST /v1.0/removebg) compatible with remove.bg payloads.

Running a 1024px segmentation model (onnxruntime-web WASM + guided-filter hair refinement) inside real users' browsers surfaced a few bugs that never showed up on an M-series MacBook during development. Here is what broke, how we fixed it, and the raw telemetry we collected from 2,000+ production runs.

1. WebKit holds onto offscreen <canvas> memory after unmount

Dropping references to temporary <canvas> elements in React was enough in Chromium, but iOS and macOS Safari kept hundreds of megabytes of backing-store memory pinned across batch runs. Explicitly zeroing dimensions (canvas.width = 0; canvas.height = 0) in teardown routines reclaimed memory immediately and stopped mobile tab reloads during 50-image ZIP batches on /batch.

2. Bounding manual brush undo history to 64 MB

On a 12 MP product photo, storing 10 undo snapshots as raw RGBA ImageData eats ~480 MB on its own. For the local Erase / Restore / Smart Brush and point/box subject selector, we switched to replaying stroke vectors on top of a rolling checkpoint canvas, capping undo history at 12 steps within a 64 MB ceiling.

3. Never silently fall back from local WASM to a backend server

A subtle trust bug in "hybrid" web tools is catching an out-of-memory WASM error and quietly uploading the file to a cloud worker so the task succeeds. If someone picked on-device processing for an ID scan or unreleased product shot, silent fallback violates the whole point. On remove.ac, local failures stay local; Cloud GPU runs only when a signed-in user clicks it or calls the API with an X-Api-Key (rac_live_...).

4. Bypassing serverless ~4 MB gateway caps without storing user files on S3

Standard serverless HTTP gateways choke around 4.5 MB, which fails as soon as a studio photographer outputs a 15 MB lossless PNG. Instead of staging uploads in an object bucket, our zero-dependency SDKs and CLI request a single-use HMAC ticket from POST /v1.0/removebg/ticket (placing a Postgres FEFO credit hold) and stream up to 25 MB / 40 MP directly into volatile GPU worker RAM. If inference errors out or times out, the credit hold releases automatically at zero cost.

Open SDKs (MIT) and Real-Device Latency Dataset (CC BY 4.0)

  • Zero-dependency Node.js & Python SDKs + --watch folder CLI: github.com/szp2005/remove-ac-sdk (includes a 1-line from removebg import RemoveBg drop-in shim).
  • Rolling 90-day real-device WASM benchmark dataset: remove.ac/benchmarks โ€” publishes p50/p95 download, session-init, and inference timings across desktop/mobile CPU buckets (raw JSON and CSV under CC BY 4.0, no cherry-picked single-machine numbers).

If you want to poke at the browser WASM studio (no login wall) or test /v1.0/removebg with the free signup credit, everything is live at https://remove.ac. Happy to share details on the guided-filter worker pipeline or the Postgres FEFO ledger SQL!

๐Ÿ“ฐ Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes โ€” full credit and traffic to the original publisher.