Automate website screenshots in Airtable

Capture a website from an Airtable record and save the image as an attachment. Use an automation secret, report errors, and handle temporary screenshot URLs.

Blog post5 min read

Written by

Dmytro Krasun

Published on

If you keep a list of websites in Airtable, whether it’s a design library, a prospect list, or a directory, sooner or later you’ll want a picture of each one next to its URL.

Here is the setup I’d use. A checkbox requests a screenshot, an automation calls ScreenshotOne, and the image lands in an attachment field. If a capture fails, the record says why, and the previous screenshot stays where it was.

If you want to turn the base into a public website afterwards, that’s a separate step. See the Airtable and Launchman directory tutorial.

Set up the table

Create a table called Websites with these fields:

FieldAirtable typePurpose
NameSingle line textYour label for the website
URLURLThe page to capture
CaptureCheckboxTick it to request a new screenshot
ScreenshotAttachmentThe latest successful capture
Captured atDate, including timeWhen the capture was attached
Capture statusSingle line textCapturing, Complete, or Failed
Capture errorLong textWhat went wrong, if anything

Each successful run replaces whatever is in the Screenshot field. If you want a history of captures, create a separate Captures table linked to Websites.

You’ll need an Airtable plan that includes the Run a script automation action, plus a ScreenshotOne access key.

Create the trigger and the secret

Create an automation with the When record matches conditions trigger. Pick the Websites table and add two conditions: Capture is checked and URL is not empty.

Add a Run a script action. Under input variables, add recordId and set it to the triggering record’s ID. Then add a secret called SCREENSHOTONE_ACCESS_KEY with your access key as the value.

In automation scripts, you read secrets with input.secret.SCREENSHOTONE_ACCESS_KEY. That differs from the Scripting extension, so if something doesn’t work, check Airtable’s Run a script documentation.

The script

Paste this into the action:

const table = base.getTable("Websites");
const { recordId } = input.config();
const accessKey = input.secret.SCREENSHOTONE_ACCESS_KEY;
if (!recordId || !accessKey) {
throw new Error("Configure recordId and the SCREENSHOTONE_ACCESS_KEY secret.");
}
async function capture(record) {
try {
const target = new URL(record.getCellValueAsString("URL").trim());
if (!["http:", "https:"].includes(target.protocol)) {
throw new Error("The URL must start with http:// or https://.");
}
// Reset the checkbox so another tick can request a fresh capture.
await table.updateRecordAsync(recordId, {
"Capture": false,
"Capture status": "Capturing",
"Capture error": "",
});
const response = await fetch("https://api.screenshotone.com/take", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Access-Key": accessKey,
},
body: JSON.stringify({
url: target.href,
format: "png",
viewport_width: 1280,
viewport_height: 800,
response_type: "json",
timeout: 20,
}),
});
if (!response.ok) {
throw new Error(`Screenshot request failed: HTTP ${response.status}`);
}
const result = await response.json();
if (typeof result.screenshot_url !== "string" || !result.screenshot_url.trim()) {
throw new Error("The response didn't include a screenshot URL.");
}
await table.updateRecordAsync(recordId, {
"Screenshot": [{ url: result.screenshot_url, filename: `${recordId}.png` }],
"Captured at": new Date().toISOString(),
"Capture status": "Complete",
"Capture error": "",
});
} catch (error) {
const message = error instanceof Error ? error.message : "Capture failed";
await table.updateRecordAsync(recordId, {
"Capture": false,
"Capture status": "Failed",
"Capture error": message.slice(0, 300),
});
throw error;
}
}
const record = await table.selectRecordAsync(recordId);
// Skip records that were deleted or unchecked before the run started.
if (record && record.getCellValue("Capture")) {
await capture(record);
}

A few choices worth explaining:

  • Viewport, not full page. It keeps the first version fast and the attachments small. Switch to full_page: true if you need the whole page, but test a few slow URLs first (see the timeout section below).
  • The checkbox is cleared before the API call. Airtable’s conditions trigger fires when a record enters the matching state, not on every update while it still matches. Clearing Capture lets another tick request a fresh screenshot. Wait for the current run to finish before ticking it again.
  • Errors are rethrown. The record shows the message, and Airtable’s run history marks the run as failed, so you see the problem in both places.

Test it before turning it on

Add a record with a simple public page such as https://example.com/, tick Capture, select it as the trigger’s test record, and run the test.

Then open the record and look at the attachment itself. A successful script run only means Airtable accepted the attachment URL. Airtable downloads the file afterwards, so check that a real image arrived and that Capture is unchecked again.

Next, break it on purpose: enter a malformed URL and tick Capture. The status should change to Failed, the error field should say what happened, and the old screenshot should still be there.

When both cases behave as expected, turn the automation on. Records that already match the conditions won’t trigger just because you enabled it. Untick and re-tick Capture to make them enter the matching state again.

Why the temporary URL is fine here

With response_type: "json", ScreenshotOne returns a temporary screenshot URL that lives for up to four hours. That’s plenty, because the script hands it to Airtable straight away and Airtable copies the file into its own storage. Your API key never ends up in the attachment.

Airtable can only import a URL it can fetch without logging in, which is why it needs the direct image link rather than a page that displays the image. Its attachment troubleshooting page covers the details.

One more catch: Airtable’s own attachment URLs expire too. Don’t paste them into a public website as permanent image links. If you’re building a site from the base, keep a copy of each image in your own storage.

Slow pages and bigger batches

Airtable gives the script’s fetch about 30 seconds. Setting ScreenshotOne’s timeout to 20 seconds leaves some headroom, but a heavy page can still run past the limit.

For that reason, keep this automation to one record per run. Don’t loop over hundreds of records or add long waits inside it. If you have slow pages or large batches, move the capture to an external worker. It can use ScreenshotOne’s async mode with webhooks and write the result back through the Airtable API.

To refresh screenshots on a schedule, add a scheduled automation that ticks Capture on a small batch of records that are due. The capture logic stays in one place, so manual and scheduled refreshes fill in the same fields. Keep an eye on how many automation runs and API calls that creates.

More examples are on the Airtable integration page.

Read more Screenshot rendering

Interviews, tips, guides, industry best practices, and news.

View all posts

Automate website screenshots

Exhaustive documentation, ready SDKs, no-code tools, and other automation to help you render website screenshots and outsource all the boring work related to that to us.