Skip to main content
POST
The core endpoint for background removal. Send an image or a video; Poof detects the media type from the file content, never from the field name, the file name or the Content-Type of the part.
  • Images are processed synchronously: the response is 200 with the processed image in the body, exactly as before.
  • Videos are processed in the background: the response is 202 Accepted with a job as JSON. Poll the job and download the result from its result_url when it is completed. See Video below.
An animated GIF (two or more frames) is a video: it is accepted with 202 and processed as a job, and format=gif returns a looping GIF. An animated WebP is handled by the image path (the first frame is processed). A still, single-frame GIF also takes the image path and is processed like a PNG, transparency included. A one-frame GIF that carries a looping (NETSCAPE) block, as ffmpeg and many editors write, is detected as animated and processed as a one-frame video job. Each successful image request costs 1 credit regardless of parameters; failed requests are free. Video costs 5 credits per second of source video (10 above 30 fps), charged when the job is accepted and refunded if it fails. Animated GIF input is billed at 5 credits per second whatever its frame rate. See Credits.

Request

Send multipart/form-data with exactly one input: file or url. The other parameters are optional form fields. The same parameter names work for images and videos; each field below says how the accepted values differ.
file
The image or video to process. Images: JPEG, PNG, WebP or a still GIF, up to 20 MB. Videos: MP4, MOV, WebM, M4V, MKV or animated GIF, up to 100 MB (use url for larger files). Required unless url is given.The legacy names image_file (a file part) and image_file_b64 (a base64 string, with or without a data:image/...;base64, prefix, images only) are still accepted and behave exactly like file. When several inputs are sent, file / image_file wins, then image_file_b64, then url.
string
A public https URL to fetch the media from. Poof downloads it server-side (up to 3 redirects, 15 second timeout). Images up to 20 MB, videos up to 500 MB. URLs that resolve to private or internal addresses are rejected with validation_error. If the download fails (an HTTP error, a timeout, an unreachable host or too many redirects), the request is rejected with 400 validation_error, details.field: "url" and, for an HTTP error, the upstream status in details.status; see Validation Error. Required unless file is given.The legacy name image_url is still accepted and behaves exactly like url.
string
Output format. The valid values depend on the media; sending an image format for a video (or the other way round) returns 400 validation_error listing the valid values.Images (default png):
  • png — Lossless with transparency support
  • jpg — Smaller file size, no transparency
  • webp — Best compression with transparency
Videos (default webm):
  • webm — VP9 WebM, transparent with channels=rgba and no bg_color. Best for the web
  • mov — ProRes QuickTime, transparent with channels=rgba and no bg_color. Best for video editors
  • mp4 — H.264 MP4, never transparent: the subject is composited on bg_color (white by default)
  • gif — Looping GIF, transparent with channels=rgba and no bg_color (1-bit transparency, no audio, capped at 1280 px on the longest side, 720p for widescreen, and 50 fps). For stickers, chat and email
See the video formats table for codecs, alpha and audio per combination.
string
default:"rgba"
Output color channels. Same values for images and videos.
  • rgba — Include alpha channel (transparency). Setting bg_color fills the background instead
  • rgb — Opaque output, uses bg_color for background (white by default)
  • alpha — Grayscale alpha mask only: white foreground, black background. For video this is a grayscale matte video with no audio track
string
default:"white"
Background colour. Setting it fills the background, so the result is opaque on that colour, for images and videos in every format (webm, mov and gif included). Without it, channels=rgba output stays transparent where the format supports it, while channels=rgb, format=jpg and format=mp4 are opaque on white. Ignored with channels=alpha. Accepts:
  • Hex: #ffffff, #fff
  • RGB: rgb(255, 255, 255)
  • Named: white, black, green
string
default:"full"
Output size preset. Same preset names for images and videos. For images it is a megapixel cap, ignored when width or height is set. For videos it caps the longest side of every frame, aspect ratio kept.To get 1080p from a 4K video, pass size=hd: the file is smaller and the job finishes faster.
crop, padding, crop_margin, width, height and fit below are image-only. Sending any of them with a video returns 400 validation_error with details.field naming the parameter.
boolean | string
default:"false"
Crop the output to the subject bounds, removing empty space around the subject. Pass true/false, or an aspect ratio like 1:1, 4:3, 16:9 to crop to that ratio around the subject.
string
default:"10%"
Padding around the subject when crop is enabled, added to each side as a fraction (0.1) or percentage (10%) of the subject’s size on that axis. Defaults to 10%; ignored unless crop is set.Pass one value for both axes, or two comma-separated values as horizontal,vertical to pad the axes differently — e.g. 10%,7.5% produces a canvas 120% of the subject’s width and 115% of its height.Padding is applied before any aspect-ratio expansion from crop. If the padded area extends beyond the original image, it is filled with transparent pixels.
string
remove.bg compatibility alias for padding, used only when padding is absent. Percentages map directly (10%; CSS shorthand 5% 10% becomes 10%,5%). Pixel values such as 10px cannot be honoured and are ignored.
integer
Output width in pixels, 1–6000. On its own, the height follows the image’s aspect ratio. Together with height, the image is fitted into a width × height canvas according to fit.The aspect ratio is always preserved — the image is never stretched or squeezed. Images smaller than the target are upscaled unless fit is scale-down. Applied after crop, and overrides size.
integer
Output height in pixels, 1–6000. On its own, the width follows the image’s aspect ratio. Together with width, the image is fitted into a width × height canvas according to fit.
string
default:"contain"
How to fit the image into width/height. The image is never stretched.
  • contain — scale the image to fit inside the canvas and centre it. The remaining area is transparent, or filled with bg_color (white for jpg).
  • cover — scale the image to fill the canvas and crop the overflow, keeping the subject centred.
  • scale-down — like contain, but never enlarges: an image smaller than the target keeps its native size (centred on the canvas when both dimensions are set).
contain and cover only differ when both width and height are set.

Response

Images

For an image the API returns 200 with the processed image directly in the response body. Check the response headers for metadata:

Videos

For a video the API returns 202 Accepted with Content-Type: application/json and a job object. The video is probed before it is accepted, so the response already tells you the duration, frame count and the credit charge. Poll status_url until status is completed, then download result_url. The full job object is described on Get Job; the 202 always has status: "queued", progress: 0 and result_url: null.

Examples

Basic Usage

Remove background and save as PNG with transparency:

White Background

Get a JPEG with a white background (great for e-commerce):

Alpha Mask Only

Get just the grayscale alpha mask (white = foreground, black = background) — useful for custom compositing pipelines:

Cropped Thumbnail

Get a small, cropped preview:

Consistent Product Shots

Crop to the subject, then add 10% horizontal and 7.5% vertical padding (a 120% × 115% canvas) so every image has the same margins:

Fixed Output Size

Resize every result to exactly 500 × 500 — ideal for marketplace listings and product grids. The subject is cropped, padded, then fitted into the square canvas without distortion:
Use fit=cover to fill the canvas edge to edge instead (the overflow is cropped around the subject), and add bg_color to fill the padded area with a colour:
Set only width (or only height) to scale to that dimension and let the other follow the aspect ratio. Use fit=scale-down if small images should keep their native size rather than being enlarged to the target:

WebP for Web

Optimal format for web delivery:

Video

Video background removal

The job flow, limits and credits in one page

Transparent video

WebM with alpha for the web, ProRes 4444 for editors, looping GIF

Green screen video

MP4 on #00ff00 for any editor’s chroma key
Send a video clip to the same endpoint and it is accepted with 202 Accepted and processed in the background. The same matting model that powers image removal is run on every frame, with a motion-aware temporal stabiliser so the matte does not flicker between frames. Use it for product clips, talking-head videos, social content, overlays, and anything else that needs a transparent or solid-background video. The flow is: submit → poll GET /jobs/{id} every 2 to 5 seconds until status is completed (or failed) → download result_url. result_url is a direct CDN link that needs no API key and stays valid for 24 hours (expires_at).
The Python (poofbg 0.3.0+) and TypeScript (@poof-bg/js 1.2.0+) SDKs return a job from the same remove_background() / removeBackground() call and ship wait_for_job / waitForJob helpers; the MCP server exposes remove_video_background. The examples below use the raw API.

Limits

Output formats

format picks the container and codec, channels picks what the pixels contain. Every combination is valid. Setting bg_color turns any channels=rgba output into the channels=rgb column, on that colour:
  • channels=alpha is the matte as luma: white foreground, black background. Use it with format=mp4 for the smallest, most widely decodable matte.
  • format=gif loops forever, keeps the source frame rate up to 50 fps and is capped at 1280 px on the longest side (720p for widescreen) whatever size says, because GIF has no inter-frame compression and files grow fast (256 colours per frame). Use it where a transparent WebM cannot play (stickers, chat, email) and pass size=preview for sticker-sized files; WebM keeps the soft matte, the full resolution and the audio.
  • bg_color makes any video opaque on that colour, transparent formats included; without it rgb and mp4 are on white. Pass bg_color=#00ff00 for a chroma-key green screen. Leave it out for a transparent WebM, MOV or GIF.
  • Frame rate, duration and aspect ratio are preserved. Output resolution is the source resolution up to 4K (4096 px on the longest side, so UHD 3840 × 2160 and DCI 4096 × 2160 are kept as is), or smaller with size.
  • 4K jobs take about 1.5 times as long as 1080p. If you do not need 4K, pass size=hd for 1080p output.
  • The result file is served with Content-Disposition: attachment; filename=result.<ext>.

What to expect

The model extracts the main salient subject or subjects in each frame, the same way it does for images. Best results come from a clearly separated subject and steady lighting. The matte is predicted at a fixed internal resolution and upscaled with edge refinement, so 4K output keeps the full source detail; very fine hair at 4K may look softer than the surrounding pixels. Known limitations:
  • Crowds and partial subjects. Crowds, people only partially visible at the frame edge, and small background objects may be dropped from the matte.
  • Overlays. Burned-in captions, logos and watermarks are often kept as foreground. Strip overlays before processing and add them back afterwards.
  • Touching objects. Objects that touch or overlap the subject (poles, laptop edges, hand-held items) can be included in some frames and not others.
  • Black or white frames. Fully black or fully white frames, such as fade-ins and fade-outs, produce an empty matte by design.
  • Fine edges and motion. Hair and fur edges are soft. The temporal stabiliser reduces edge flicker on static parts of the frame but does not eliminate it on fast motion.

Credits

The credit charge does not depend on format, channels, size or resolution. A 12.4 second clip at 29.97 fps is billed as 13 seconds, so 65 credits. One credit equals one image or 0.2 seconds of video at up to 30 fps (0.1 seconds above 30 fps). Animated GIF input is billed at 5 credits per second whatever its frame rate. Credits are charged when the job is accepted, and the 202 response tells you the exact amount in credits. If the job fails, the credits are refunded automatically. Rejected submissions (4xx errors) are never billed. If the remaining credits do not cover the whole clip, the request is rejected with 402 payment_required. The check covers one request at a time, so clips submitted at the same moment can together exceed the remaining credits. Polling the job and downloading the result are free.

Video examples

Submit a clip with file, poll the job every few seconds, and download the transparent WebM from result_url:
The examples below only show the submit step. Poll and download exactly as above.

Opaque MP4 on a Solid Colour

An H.264 MP4 with the subject composited on bg_color. The default is white; pass bg_color=#00ff00 for a green screen:

ProRes for Video Editors

A transparent QuickTime file (ProRes 4444) that drops straight into Premiere, Final Cut, DaVinci Resolve or After Effects:

Alpha Matte Video

Get just the grayscale matte (white foreground, black background) as a small MP4 for custom compositing pipelines. There is no audio track:

Transparent GIF

A looping GIF with 1-bit transparency, for stickers, chat and email. GIF output is capped at 1280 px on the longest side (720p for widescreen) and 50 fps; size=preview (640 px) keeps the file sticker-sized. There is no audio track:
An animated GIF works as input too: send it as file or url and choose any video format for the output.

From a URL

Let Poof fetch the video from a public https URL (up to 500 MB) instead of uploading it:

Error Responses

All errors return a flat JSON body ({ "code", "message", "details"?, "request_id", "doc_url" }) and carry an X-Request-ID header. Failed and rejected requests are not billed. A video that is accepted but fails during processing does not produce an error response: the job ends with status: "failed" and an error object, and its credits are refunded automatically. See Get Job. See API Error Codes for detailed troubleshooting.