API

Airtable: Remove Image Backgrounds Automatically with a Run-Script Automation

September 6, 20265 min readBy BG Clear Editorial

Airtable is where a lot of small product catalogues, creator databases and print-on-demand queues live, and its automations can run JavaScript with fetch. That is enough to remove backgrounds without leaving the base: a record gets a photo, the automation sends it to the bgclear API, and the cutout comes back as a second attachment. Below is the per-record automation, a bulk version for an existing table, and the two Airtable quirks (expiring attachment URLs, no secrets store) you need to design around.

In this guide

How it fits together

Airtable attachment fields expose a URL for each file, but those URLs expire a couple of hours after they are generated. The API fetches image_url server-side at request time, so as long as the script reads the URL and calls the API in the same run, expiry never bites. In JSON mode the API returns a hosted result URL (valid 24 hours); writing that URL into an attachment field makes Airtable download and store the file permanently. Two fields are needed on your table: Photo (attachment, the input) and Cutout (attachment, the output).

The automation: trigger + Run script

Automation trigger: "When record matches conditions" — Photo is not empty AND Cutout is empty. Action: "Run script". In the script's Input variables panel add recordId (the triggering record's Airtable record ID) and apiKey (your bgclear key). Airtable has no secret store for automation scripts, so an input variable is the least-bad place; anyone who can edit the automation can read it, so use a key you can rotate from the dashboard.

const { recordId, apiKey } = input.config();
const table = base.getTable("Products");
const record = await table.selectRecordAsync(recordId, { fields: ["Photo", "Cutout"] });

const photo = record?.getCellValue("Photo")?.[0];
const done = record?.getCellValue("Cutout")?.length;
if (!photo || done) { output.set("status", "skipped"); return; }

const res = await fetch("https://www.bgclear.ai/api/v1/remove", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    Accept: "application/json",
    "Content-Type": "application/json",
    "Idempotency-Key": `airtable-${photo.id}`,          // re-runs never double-charge
  },
  body: JSON.stringify({ image_url: photo.url, size: "auto", format: "png" }),
});
const data = await res.json();
if (!res.ok) throw new Error(`bgclear ${res.status} ${data.error?.code}: ${data.error?.message}`);

await table.updateRecordAsync(recordId, {
  Cutout: [{ url: data.url, filename: photo.filename.replace(/\.[^.]+$/, "") + "-cutout.png" }],
});
output.set("status", `done, credits remaining ${data.credits_remaining}`);

Airtable fetches the result URL when it stores the attachment, well inside the 24-hour window. For marketplace-ready white backgrounds, send format: "jpg", bg_color: "ffffff" and name the file .jpg.

Bulk: a scripting-extension run for the whole table

For a table that already has hundreds of photos, run this once from the Scripting extension (Extensions → Scripting). It paces requests under the API's 60-per-minute limit and updates records in batches of 50, which is Airtable's write limit per call.

const apiKey = "bgc_live_PASTE_YOUR_KEY";               // remove before sharing the base
const table = base.getTable("Products");
const query = await table.selectRecordsAsync({ fields: ["Photo", "Cutout"] });
const size = "auto";                                    // "preview" = free dry run

const updates = [];
for (const record of query.records) {
  const photo = record.getCellValue("Photo")?.[0];
  if (!photo || record.getCellValue("Cutout")?.length) continue;

  const res = await fetch("https://www.bgclear.ai/api/v1/remove", {
    method: "POST",
    headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json",
               "Content-Type": "application/json", "Idempotency-Key": `airtable-${photo.id}` },
    body: JSON.stringify({ image_url: photo.url, size, format: "png" }),
  });
  const data = await res.json();
  if (res.status === 429) { await new Promise(r => setTimeout(r, 5000)); continue; }
  if (res.status === 402) { output.text("Out of credits — https://www.bgclear.ai/api-pricing/"); break; }
  if (!res.ok) { output.text(`${record.name}: ${data.error?.message}`); continue; }

  updates.push({ id: record.id, fields: { Cutout: [{ url: data.url, filename: "cutout.png" }] } });
  if (updates.length === 50) { await table.updateRecordsAsync(updates.splice(0)); }
  await new Promise(r => setTimeout(r, 1100));          // ≤60 requests/minute
}
if (updates.length) await table.updateRecordsAsync(updates);
output.text("Done.");

Set size = "preview" first: it is free, returns 800 px results, and shows you edge quality on your own product photos before any credit is spent.

Cost and limits

One credit per full-resolution image — $9 for 100, $39 for 500, $129 for 2,000; credits never expire, previews are free, failed requests are never charged (pricing). Airtable's own limits: automation scripts get 30 seconds of run time (one image fits comfortably; the bulk job belongs in the Scripting extension), and attachments larger than 25 MB should be resized before upload since that is the API's cap. If you previously used a remove.bg-based Airtable script, the JSON body is the same and remove.bg's API ends on 1 December 2026 — what changes. The same pattern works in Google Sheets with Apps Script and in n8n, Zapier and Make.

Frequently asked questions

Can the automation send the file itself instead of the URL?

Airtable automation scripts have no FormData/file access, so the URL route is the one that works — and it is simpler, because the API fetches the attachment directly.

Will the expiring Airtable attachment URL break this?

No, as long as the script reads the URL and calls the API in the same run, which the scripts above do. Do not store attachment URLs for later.

Where should the API key live?

As an automation input variable (per-record automation) or a constant you remove after the bulk run. Anyone who can edit the automation can see it, so rotate it from the API dashboard if the base is shared widely.

How much does a 300-product base cost to process?

300 credits — the $39 pack covers 500 images at $0.078 each, and unused credits never expire.

Ship it with the bgclear API

remove.bg-compatible endpoints, credits from $9 for 100 images, no subscription. Pay, get a key, make your first call in under two minutes.

Get API credits →

Tools for this guide

Background Removal API Free

background removal api free

Cheapest Background Remover API

cheapest background remover api

Clothing Product Background Remover

clothing product background remover

Keep reading

API

Google Sheets: Remove Backgrounds for a Whole Column of Image URLs (Apps Script)

A 40-line Apps Script that reads image URLs from column A, sends each through a background removal API with a white fill, and writes the result URL (and a preview) to column B — resumable, rate-limit aware.

API

Automate Background Removal in n8n, Zapier and Make (No Code)

Exact node-by-node settings to remove backgrounds inside an automation: HTTP Request node in n8n, Webhooks by Zapier, and Make's HTTP module — then send the cutout to Drive, Shopify or Airtable.

API

Shopify: Give Every Product Photo a White Background Automatically (Admin API + Background Removal API)

A script that walks your Shopify catalogue, sends each image through a background removal API with a white fill, and re-attaches the result with productCreateMedia — no app, no manual editing.

API

Bulk Background Removal via API: Async Jobs, Batches of 50 and Webhooks

How to process a catalogue of thousands of images without babysitting a script: batch submission, callbacks instead of polling, credit accounting, and what to do when the queue is full.