# Generating Product Shots with Transparent Backgrounds

Source: https://docs.prodia.com/workflows/generating-product-shots-with-transparent-backgrounds/

This Workflow generates a studio product photograph and removes its background in a single API call, returning a transparent PNG ready to drop into a website or marketing asset.

| Generated by Flux Schnell                                                                                                                                                 | Background removed                                                                                                                                                             |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| ![Studio product photograph of a stainless-steel coffee tumbler on a white background](https://docs.prodia.com/llms/assets/aecd3aae04bd-workflow-product-shot-before.jpg) | ![Same coffee tumbler with the background removed, leaving just the product on transparency](https://docs.prodia.com/llms/assets/d064a981e8be-workflow-product-shot-after.png) |

### Project Setup

```bash
# Create a project directory.
mkdir prodia-product-shots-workflow
cd prodia-product-shots-workflow
```

### prodia-js

Install Node (if not already installed):

### macOS

```bash
brew install node
# Close the current terminal and open a new one so that node is available.
```

### Linux

```bash
apt install node
# Close the current terminal and open a new one so that node is available.
```

### Windows

```bash
winget install -e --id OpenJS.NodeJS.LTS
# Close the current terminal and open a new one so that node is available.
```

Create project skeleton:

```bash
# Requires node --version >= 18
# Initialize the project with npm.
npm init -y

# Install the prodia-js library.
npm install prodia --save
```

### requests

Install Python (if not already installed):

### macOS

```bash
brew install python
# Close the current terminal and open a new one so that python is available.
```

### Linux

```bash
apt install python3 python3-venv python-is-python3
# Close the current terminal and open a new one so that python is available.
```

### Windows

```bash
winget install -e --id Python.Python.3.12
# Close the current terminal and open a new one so that python is available.
```

```bash
# Requires python --version >= 3.12
python -m venv venv
source venv/bin/activate
pip install requests
```

### curl

Install curl (if not already installed):

### macOS

```bash
brew install curl
# Close the current terminal and open a new one so that curl is available.
```

### Linux

```bash
apt install curl
# Close the current terminal and open a new one so that curl is available.
```

### Windows

```bash
# NOTE: Windows 10 and up have curl installed by default and this can be
# skipped.
winget install -e --id cURL.cURL
# Close the current terminal and open a new one so that curl is available.
```

```bash
# Export your token so it can be used by the main code.
export PRODIA_TOKEN=your-token-here
```

> note:
>
> Your token is exported to an environment variable. If you close or switch your
> shell you'll need to run `export PRODIA_TOKEN=your-token-here` again.

Create a main file for your project:

### prodia-js

```js title="main.js"
const { createProdia } = require("prodia/v2");

const prodia = createProdia({
    token: process.env.PRODIA_TOKEN // get it from environment
});
```

### requests

Create the following `main.py`

```python title="main.py"
from requests.adapters import HTTPAdapter, Retry
import os
import requests
import sys


prodia_token = os.getenv('PRODIA_TOKEN')
prodia_url = 'https://inference.prodia.com/v2/job'

session = requests.Session()
retries = Retry(allowed_methods=None, status_forcelist=Retry.RETRY_AFTER_STATUS_CODES)
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))
session.headers.update({'Authorization': f"Bearer {prodia_token}"})
```

### curl

```bash title="main.sh"
set -euo pipefail
```

You're now ready to make some API calls!

### Generate and remove the background

The chain has two jobs: a text-to-image generation, then `inference.remove-background.v1` which replaces the background with transparency.

The remove-background processor returns *two* outputs — `foreground` (the transparent PNG you want) and `mask` (the binary alpha map). The Prodia SDK gives you the foreground automatically. For Python and curl, you need a multipart parser to pull `foreground` from the response — examples below.

### prodia-js

```javascript title="main.js"
const { createProdia } = require("prodia/v2");
const fs = require("node:fs/promises");

const prodia = createProdia({
  token: process.env.PRODIA_TOKEN,
});

(async () => {
  const job = await prodia.job({
    type: "workflow.serial.v1",
    config: {
      jobs: [
        {
          type: "inference.flux-fast.schnell.txt2img.v2",
          config: {
            prompt: "studio product photograph of a stainless-steel coffee tumbler on a plain white seamless background, soft even lighting, centred composition",
            seed: 42,
          },
        },
        {
          type: "inference.remove-background.v1",
        },
      ],
    },
  }, {
    accept: "image/png",
  });

  const image = await job.arrayBuffer();
  await fs.writeFile("product.png", new Uint8Array(image));
  // open product.png
})();
```

```bash
node main.js
```

### requests

```bash
pip install requests-toolbelt
```

```python title="main.py"
from requests.adapters import HTTPAdapter, Retry
from requests_toolbelt.multipart.decoder import MultipartDecoder
import os
import requests
import sys


prodia_token = os.getenv('PRODIA_TOKEN')
prodia_url = 'https://inference.prodia.com/v2/job'

session = requests.Session()
retries = Retry(allowed_methods=None, status_forcelist=Retry.RETRY_AFTER_STATUS_CODES)
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))
session.headers.update({'Authorization': f"Bearer {prodia_token}"})

headers = {
    'Accept': 'multipart/form-data; image/png',
}

job = {
    'type': 'workflow.serial.v1',
    'config': {
        'jobs': [
            {
                'type': 'inference.flux-fast.schnell.txt2img.v2',
                'config': {
                    'prompt': 'studio product photograph of a stainless-steel coffee tumbler on a plain white seamless background, soft even lighting, centred composition',
                    'seed': 42,
                },
            },
            {
                'type': 'inference.remove-background.v1',
            },
        ],
    },
}

res = session.post(prodia_url, headers=headers, json=job)
print(f"Request ID: {res.headers['x-request-id']}")
print(f"Status: {res.status_code}")

if res.status_code != 200:
    print(res.text)
    sys.exit(1)

# remove-background returns two outputs (foreground + mask) — pick the foreground.
for part in MultipartDecoder.from_response(res).parts:
    cd = part.headers[b'Content-Disposition'].decode()
    if 'filename="foreground"' in cd:
        with open('product.png', 'wb') as f:
            f.write(part.content)
        break
```

```bash
python main.py
```

### curl

```bash title="main.sh"
set -euo pipefail

cat <<EOF > job.json
{
  "type": "workflow.serial.v1",
  "config": {
    "jobs": [
      {
        "type": "inference.flux-fast.schnell.txt2img.v2",
        "config": {
          "prompt": "studio product photograph of a stainless-steel coffee tumbler on a plain white seamless background, soft even lighting, centred composition",
          "seed": 42
        }
      },
      {
        "type": "inference.remove-background.v1"
      }
    ]
  }
}
EOF

curl -sSf --retry 3 \
  -H "Authorization: Bearer $PRODIA_TOKEN" \
  -H 'Accept: multipart/form-data; image/png' \
  -H 'Content-Type: application/json' \
  --data-binary @job.json \
  --output response.bin \
  --dump-header response.headers \
  https://inference.prodia.com/v2/job

# remove-background returns two outputs (foreground + mask) — extract the foreground.
python3 - <<'PY'
import re
boundary = re.search(r'boundary=(\S+)', open('response.headers').read()).group(1).strip()
raw = open('response.bin', 'rb').read()
for part in raw.split(('--' + boundary).encode())[1:-1]:
    part = part.lstrip(b'\r\n')
    head_end = part.find(b'\r\n\r\n')
    head = part[:head_end].decode()
    body = part[head_end+4:].rstrip(b'\r\n')
    if 'filename="foreground"' in head:
        open('product.png', 'wb').write(body)
PY
```

```bash
bash main.sh
```

### macOS

```bash
open product.png
```

### Linux

```bash
xdg-open product.png
```

### Windows

```bash
start product.png
```

### Tips

- *Prompt for a clean background.* Phrases like "plain white seamless background" or "studio backdrop" give the cut-out crisper edges than busy or photographic backgrounds.
- *Output is always PNG.* `inference.remove-background.v1` requires PNG output to preserve the alpha channel — JPEG would flatten it onto an opaque background.
- *Need only the mask?* The chain still works if you read the `mask` part instead of `foreground` from the multipart response. See [Removing Backgrounds](https://docs.prodia.com/guides/removing-backgrounds/) for using the mask alone.
