---
title: Remove an image background
url: https://base_url.placeholder/docs/ops/remove-background
group: Concepts
---

# Remove an image background

`remove_bg` cuts the subject out of a photo and hands back a transparent PNG. It is one op of the [catalogue](https://base_url.placeholder/docs/ops), which means one call, a [job handle](https://base_url.placeholder/docs/jobs) you can poll, cancel or subscribe to, and a price you can read before you spend it.

## What it does

A model finds the subject and writes everything else to transparency. The output is a new asset — a PNG with an alpha channel, the size of your input up to the model's input cap — so the original stays where it was and stays readable. No job overwrites the asset it read, so a pipeline can keep both ids.

Reach for it when a program has to make product shots, avatars or stickers usable on any background. Do not reach for it to erase one object from a scene — that is [edit](https://base_url.placeholder/docs/ops/edit), with an instruction. Do not reach for it to trim a uniform border either: that is `trim`, which is deterministic, free on a paid plan and runs while you wait.

## Call it

One op, six surfaces, one vocabulary: the `op` name below is the same string everywhere — the SDKs' named helpers only spell it in their language's case, `ops.removeBg` in JavaScript — because every surface enumerates `GET /api/v1/ops` instead of carrying its own list. The request is the catalogue's own `example` for this op, so it is the one the service has checked.

#### JavaScript

```js
// pnpm add imagestep
const job = await client.ops.removeBg("ast_1a2b", { wait: true });
const [out] = await client.jobs.outputs(job);
```

#### Python

```python
# pip install imagestep
job = client.ops.remove_bg("ast_1a2b", wait=True)
[out] = client.jobs.outputs(job)
```

#### CLI

```sh
imagestep jobs submit --op remove_bg --asset-ids ast_1a2b --wait
```

#### curl

```sh
# "wait" holds the response until the job is done (60 s at most): 200 with the finished job,
# or 202 with the handle — then GET /api/v1/jobs/<id>?wait=30 waits again
curl -sS -X POST https://api.imagestep.dev/api/v1/jobs \
  -H "Authorization: ApiKey $IMAGESTEP_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"op":"remove_bg","assetIds":["ast_1a2b"],"wait":30}'
```

#### MCP

```text
# tool call
transform  {"op":"remove_bg","asset_ids":["ast_1a2b"]}
```

#### n8n

```json
{
  "nodes": [
    {
      "parameters": {
        "resource": "op",
        "operation": "run",
        "op": "remove_bg",
        "inputMode": "assetIds",
        "assetIds": "ast_1a2b"
      },
      "name": "ImageStep",
      "type": "n8n-nodes-imagestep.imageStep",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    }
  ],
  "connections": {}
}
```

The [n8n](https://base_url.placeholder/docs/n8n) tab is a workflow to paste onto the canvas: the **remove_bg** entry of the node's Op dropdown, which is filled from the same catalogue. Full references: [SDKs](https://base_url.placeholder/docs/sdk), [CLI](https://base_url.placeholder/docs/cli), [MCP](https://base_url.placeholder/docs/mcp), [REST](https://base_url.placeholder/docs/api).

## Parameters, model and price

The entry as the catalogue stood when this page was built; `GET https://api.imagestep.dev/api/v1/ops/remove_bg` has it live — the same entry the SDKs, the MCP server and the n8n node enumerate. The rows are fields of the request body. `parameters` goes to the model: its keys are the model's own, listed under `parameters` for each model in `GET /api/v1/ai-models`, and a key the model does not declare, or a value outside its options or bounds, is `400 invalid_param` naming it.

### remove_bg

ai job type ai-edit · typically ~5 s per item · input scaled to ≤ 2048 px on the long edge

Cut the subject out; transparent PNG result.

| Parameter | Type | What it does |
| --- | --- | --- |
| model | string | A model whose categories include 'background_removal' — GET /api/v1/ai-models lists them. Any other model is 400 invalid_param, with the ones that fit in details.allowed. default fal-ai/bria/background/remove |

AI op: per-item USD from the model's price; credits are charged per item. Price a batch with POST /api/v1/jobs?dryRun=true before spending. Default model fal-ai/bria/background/remove: $0.0227 per item.

That is how it is priced. What one request costs — another model, a bigger scale factor, forty images — is the [dry run](https://base_url.placeholder/docs/jobs#price), which prices the exact body you are about to send without creating anything.

## In a workflow

The cutout is rarely the end of the job. Two things follow it often enough to be worth writing down, and both stay one job rather than several round trips:

**Cut out, then put the subject on white** — two steps saved as a preset, one job per batch:

```json
{
  "name": "Packshot",
  "slug": "packshot",
  "description": "Cut the subject out and put it on marketplace white.",
  "steps": [
    {
      "op": "remove_bg"
    },
    {
      "op": "flatten",
      "parameters": {
        "background": "#ffffff"
      }
    }
  ]
}
```

#### JavaScript

```js
import { readFile } from "node:fs/promises";

const preset = await client.presets.create(JSON.parse(await readFile("packshot.json", "utf8")));
console.log(preset.slug, preset.version); // "packshot" 1
```

#### Python

```python
import json

preset = client.presets.create(json.load(open("packshot.json")))
print(preset["slug"], preset["version"])  # "packshot" 1
```

#### CLI

```sh
imagestep preset create -f packshot.json -o json
```

#### curl

```sh
curl -s https://api.imagestep.dev/api/v1/presets -H "Authorization: ApiKey $IMAGESTEP_API_KEY" -H "Content-Type: application/json" -d @packshot.json
```

#### MCP

```text
# tool call — an agent has no disk to read, so the document travels in the call
save_preset  {"name":"Packshot","slug":"packshot","description":"Cut the subject out and put it on marketplace white.","steps":[{"op":"remove_bg"},{"op":"flatten","parameters":{"background":"#ffffff"}}]}
```

#### JavaScript

```js
const job = await client.presets.run("packshot", ["<asset-id>"], { wait: true });
const outputs = await client.jobs.outputs(job);
```

#### Python

```python
job = client.presets.run("packshot", ["<asset-id>"], wait=True)
outputs = client.jobs.outputs(job)
```

#### CLI

```sh
imagestep jobs submit --preset-id packshot --asset-ids <asset-id> --wait -o json
```

#### curl

```sh
# price it first with ?dryRun=true; "wait" holds the response until a one-item job is done (60 s at most)
curl -s https://api.imagestep.dev/api/v1/jobs -H "Authorization: ApiKey $IMAGESTEP_API_KEY" -H "Content-Type: application/json" \
  -d '{"presetId":"packshot","assetIds":["<asset-id>"],"wait":30}'
```

#### MCP

```text
# tool call
run_preset  {"preset":"packshot","asset_ids":["<asset-id>"]}
```

**Cut out once, then every size the storefront needs** — `variants` makes one asset per entry, in one job:

#### JavaScript

```js
const job = await client.ops.run("resize", {"assetIds":["<cutout-id>"],"variants":[{"name":"grid","parameters":{"width":600,"height":600,"fit":"contain"}},{"name":"hero","parameters":{"width":1600}}],"wait":true});
```

#### Python

```python
job = client.ops.run("resize", asset_ids=["<cutout-id>"], variants=[{"name":"grid","parameters":{"width":600,"height":600,"fit":"contain"}},{"name":"hero","parameters":{"width":1600}}], wait=True)
```

#### CLI

```sh
imagestep jobs submit --op resize --asset-ids <cutout-id> --variants '[{"name":"grid","parameters":{"width":600,"height":600,"fit":"contain"}},{"name":"hero","parameters":{"width":1600}}]' --wait -o json
```

#### curl

```sh
curl -s https://api.imagestep.dev/api/v1/jobs -H "Authorization: ApiKey $IMAGESTEP_API_KEY" -H "Content-Type: application/json" \
  -d '{"op":"resize","assetIds":["<cutout-id>"],"variants":[{"name":"grid","parameters":{"width":600,"height":600,"fit":"contain"}},{"name":"hero","parameters":{"width":1600}}]}'
```

#### MCP

```text
# tool call
transform  {"op":"resize","asset_ids":["<cutout-id>"],"variants":[{"name":"grid","parameters":{"width":600,"height":600,"fit":"contain"}},{"name":"hero","parameters":{"width":1600}}]}
```

To hand the result to something outside ImageStep, [publish](https://base_url.placeholder/docs/assets#publish) the output asset: it gets a stable URL on the CDN at full size, which is what an agent or an n8n node passes along. A batch of hundreds is still one job — send every id in `assetIds` (up to 10,000) and subscribe to [the job.completed webhook](https://base_url.placeholder/docs/webhooks) instead of polling.

## Limits

The default model is handed at most 2048 px on the long edge — a larger photo is scaled down first — so that is the largest cutout it returns, whatever the original's size. Hair, glass and motion blur are where every background remover is judged, and where the models in the catalogue differ most — if the default disappoints on your images, try another `model` before concluding the op cannot do it. A busy scene with no obvious subject has no right answer; the model will pick one. Items that fail inside a job fail on their own, carry an [error code and a retryable flag](https://base_url.placeholder/docs/errors#items), and are not charged, so one bad image does not cost you the batch.

## FAQ

**What does the result look like?**

A new asset holding a PNG with an alpha channel — the subject on transparency, at the size of the image the model was handed: your input's own, unless its long edge is over the catalogue's maxInputEdge, which it is scaled down to first. The original is untouched.

**Can I get the cutout back in the same HTTP response?**

Its handle, yes: send wait (up to 60 s) with the submit and a one-image job answers when it is done, the cutout's asset id on its item — typically a few seconds. Not the bytes: remove_bg is an AI op, and every AI op is a job, because a model call needs an owner for its retry and its refund. Deterministic ops (resize, convert, crop) do have a synchronous, bytes-back form.

**How do I put the subject on a white background instead?**

Run remove_bg, then flatten with a background colour. Two ops in a row are a preset — save the pair once and run it by slug as a single job.

**What does it cost?**

Credits per image at the model's published per-image price. The dry run gives the exact number before you spend anything.

**Which model runs it?**

fal-ai/bria/background/remove by default; pass model to pick another background remover — any model whose categories include background_removal (GET /api/v1/ai-models). Another model is 400 invalid_param, with the ones that fit in details.allowed.
