DEV Community

Cover image for High-Volume Background Removal API for Product Catalogs
AI Engine
AI Engine

Posted on Edited on Originally published at ai-engine.net

High-Volume Background Removal API for Product Catalogs

To integrate a background removal API into a product catalog pipeline, read your SKUs and image URLs from a file or database, send them to the API in parallel, and write the clean image URL back to each product. A high-volume background removal API turns thousands of vendor photos, shot on warehouse floors, kitchen tables and brick walls, into one consistent white catalog.

We ran every script below against the live API on 12 real product photos.

Want to try it on your own products? Get a key for the Background Removal API and run the batch script below.

What a high-volume background removal API needs

  • Both input types: image URLs for catalogs that already live online, and file uploads for photos on disk.
  • Parallel requests: a catalog is a batch job. Our run used 10 workers.
  • Marketplace output in one call: a white background without a second compositing step, through the /color-background endpoint.
  • Metadata for your records: every response returns the output image_url with its width, height and size_bytes.

Install the packages: pip install requests tqdm pillow.

Batch a whole catalog concurrently

This script reads a CSV of SKUs and image URLs, runs 10 requests at a time on the /color-background endpoint (opaque white, as Amazon requires for main images), retries transient errors, and writes the results to a new CSV:

import csv
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from tqdm import tqdm

HEADERS = {
    "x-rapidapi-key": "YOUR_API_KEY",
    "x-rapidapi-host": "background-removal-ai.p.rapidapi.com",
}
URL = "https://background-removal-ai.p.rapidapi.com/color-background"

def process(sku, image_url, retries=3):
    """Process one product image, retrying on transient errors."""
    for attempt in range(retries):
        try:
            r = requests.post(
                URL,
                headers={**HEADERS, "Content-Type": "application/json"},
                json={"image_url": image_url, "bg_color": "255,255,255,255"},
                timeout=30,
            )
            r.raise_for_status()
            return sku, r.json()["image_url"], None
        except Exception as e:
            if attempt == retries - 1:
                return sku, None, str(e)

# products.csv has columns: sku, image_url
with open("products.csv") as f:
    products = list(csv.DictReader(f))

results, failures = [], []
with ThreadPoolExecutor(max_workers=10) as pool:
    futures = [pool.submit(process, p["sku"], p["image_url"]) for p in products]
    for fut in tqdm(as_completed(futures), total=len(futures), desc="Removing backgrounds"):
        sku, out_url, err = fut.result()
        if err:
            failures.append((sku, err))
        else:
            results.append((sku, out_url))

print(f"Processed {len(results)} images, {len(failures)} failed")

with open("processed.csv", "w", newline="") as f:
    w = csv.writer(f)
    w.writerow(["sku", "processed_url"])
    w.writerows(results)
Enter fullscreen mode Exit fullscreen mode

We ran it exactly as shown on 12 product photos from Pexels:

Removing backgrounds: 100%|██████████| 12/12 [00:25<00:00,  2.15s/it]
Processed 12 images, 0 failed
Enter fullscreen mode Exit fullscreen mode

The whole run took 26 seconds. max_workers sets how many requests run at once: raise it to go faster, within your plan's rate limit. Any SKU that still fails after the retries lands in failures so you can run it again.

Center and square every product

Vendor photos frame products very differently: a small bottle in the middle of a boardwalk, a watch filling the whole frame. To give every catalog card the same look, take the transparent cutout from /remove-background, crop it to the product, and center it on a white square with the same fill ratio:

import io
from PIL import Image

def catalog_tile(image_url, size=1600, fill=0.85):
    """Cut out the product, then center it on a white square."""
    r = requests.post(
        "https://background-removal-ai.p.rapidapi.com/remove-background",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={"image_url": image_url},
        timeout=60,
    )
    r.raise_for_status()
    png = requests.get(r.json()["image_url"], timeout=60).content
    product = Image.open(io.BytesIO(png)).convert("RGBA")
    product = product.crop(product.getchannel("A").getbbox())

    scale = size * fill / max(product.size)
    product = product.resize(
        (round(product.width * scale), round(product.height * scale)), Image.LANCZOS
    )
    tile = Image.new("RGB", (size, size), "white")
    tile.paste(product, ((size - product.width) // 2, (size - product.height) // 2), product)
    return tile

catalog_tile("https://example.com/product.jpg").save("SKU-001.jpg", quality=92)
Enter fullscreen mode Exit fullscreen mode

Three products before and after: a camera, a steel watch and a leather watch, each centered on a white square

The alpha channel of the cutout gives the exact bounding box of the product, so the crop needs no tuning. All 12 products of our run came out centered on 1600 x 1600 white squares.

Production tips

  • Test on a sample first: run 20 products from your own catalog, then process the full list.
  • Make runs resumable: skip SKUs already present in processed.csv.
  • Keep the files with your catalog: download each result into your own media storage or CDN, next to the SKU.
  • Plug it into new products: call process() from a PIM webhook, a queue, or a nightly cron so new SKUs are cleaned on arrival.

To compare providers, see the background removal API comparison.

Read the full guide with the single call, the new-product pipeline and self-hosting vs API on ai-engine.net.

Top comments (0)