# Airtable Automation Watch - Find Broken Automations (`mdcurt/airtable-automation-watch`) Actor

Finds broken Airtable automations - text in date fields, deleted fields, dead dropdown options, secrets in scripts - and shows what changed since the last run and which edit broke it. Read-only, one token scope.

- **URL**: https://apify.com/mdcurt/airtable-automation-watch.md
- **Developed by:** [Matthew Curtis](https://apify.com/mdcurt) (community)
- **Categories:** Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $35.00 / 1,000 base checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Airtable Automation Watch - Find Broken Automations

**Find the Airtable automations that are quietly broken, and the edit that broke them.** Automation Watch reads every automation in a base, checks each step against the base's real structure, and compares it with the last run. Leave the token empty and press **Start** to see a worked example on a bundled sample base; it is free and needs no account details.

- **Finds problems Airtable does not show.** Text written into a date field, a step writing to a deleted or computed field, a trigger waiting for a dropdown option that no longer exists, a secret pasted into a script, a formula or lookup that has stopped calculating.
- **Points at the edit that caused it.** When a problem is new since the last run, the change that introduced it is linked and raised to the same severity.
- **Sees the whole base.** Automations, view filters and sorts, interface dashboards and formulas, so a deleted field comes with the list of everything that used it.
- **Read-only, one scope.** A personal access token with `schema.bases:read` and nothing else. It never reads a record and never changes anything.

#### What does it check?

Rows are written worst first.

| Severity | Check | What it catches |
| --- | --- | --- |
| `critical` | Writes to / reads a deleted field | A step still maps a field that no longer exists, so runs fail. |
| `critical` | Trigger or step table deleted | The automation points at a table that is gone. |
| `critical` | Computed field stopped working | A formula, rollup, lookup or count Airtable marks invalid. |
| `high` | Text in a date or number field | For example `{Appointment Date} + 2 days` written into a date field. Airtable does no arithmetic there. |
| `high` | Writes to a computed field | Formula, rollup and similar fields cannot be written. |
| `high` | Trigger can never fire | It waits for a dropdown option that was deleted. |
| `high` | Sets a deleted dropdown option | The step picks an option that no longer exists. |
| `high` | Secret in a script | An API key or token written into a Run script step. |
| `high` | Script uses a missing table or field name | `getTable("…")` or `getCellValue("…")` with a name that does not exist. |
| `high` | Invalid setup or deployment error | Airtable itself reports the automation as broken. |
| `medium` | Hard-coded linked record | Every run links the same record by name. |
| `medium` | Unpublished edits | The draft differs from what actually runs. |
| `low` | Automation off / creates blank records | Housekeeping. |

And between runs:

| Severity | Change |
| --- | --- |
| `critical` | A field an automation uses was deleted (with every automation, view and dashboard it affects) |
| `high` | An automation was turned off or deleted, a step was removed, a trigger now watches another table, a field an automation uses changed type, a dropdown option an automation uses was deleted, or a field or table was renamed while a script still uses the old name |
| `medium` | A field mapping, trigger condition, step setting or script changed (scripts come with a line-by-line diff), or a step or automation was added |
| `low` | A field an automation uses was renamed (Airtable automations follow renames; tools outside Airtable may not) |

#### How to use it

1. Leave **Airtable personal access token** empty and press **Start** to see the sample report.
2. To check your own base, create a token at [airtable.com/create/tokens](https://airtable.com/create/tokens) with only the **`schema.bases:read`** scope, and add your bases under **Access**.
3. Paste the token, list your base IDs (or base URLs), and press **Start**.
4. Schedule it daily or weekly. The first run of a base saves a baseline and already reports problems; every run after that also shows what changed.

#### Input

| Field | What it does |
| --- | --- |
| **Airtable personal access token** | Read-only token with only `schema.bases:read`. Leave empty for the free sample run. |
| **Bases** | Base IDs (`app...`) or whole base URLs, one per line. Empty = every base the token was granted. |
| **Minimum severity** | Drop findings and changes milder than this (default: low). |
| **Snapshot store name** | Named key-value store holding one snapshot per base for the next comparison. One name per schedule. |
| **Write a shareable report** | One self-contained HTML page per base (default: on). |
| **Maximum bases** | Stop after this many bases (default: 50). |

#### Output

- **Dataset**: one row per finding or change, with severity, the automation and step, what is wrong, how to fix it, before and after values, the edit that introduced it, and what it affects.
- **Report**: a self-contained web page per base, linked from each row. It needs no Airtable access to read, so you can send it to whoever owns the base.
- **OUTPUT** record and a **bases** dataset: one summary per base with counts by severity.

#### Sample row

```json
{
  "rowType": "finding",
  "severity": "high",
  "title": "Puts text into a date field (new)",
  "automation": "Create Follow-Up Task for Completed Appointments",
  "where": "step 1 (createRecord)",
  "message": "Step 1 (createRecord) writes \"{Appointment Date} + 2 days\" into Tasks & Follow-Ups.Due Date, a date field. Airtable does not do date arithmetic here, so the value is rejected or the text is dropped.",
  "remediation": "Calculate the date in a formula field (for example DATEADD) and map that field instead.",
  "introducedBy": "Field mapping changed: Step 1 (createRecord) sets Tasks & Follow-Ups.Due Date differently.",
  "baseName": "Hasta OS (sample)"
}
```

#### How much does it cost?

Pay per event, at the price shown on this page: one event per base checked, charged only after that base's results are written. The sample run is free. A base that cannot be read (wrong ID, not granted to the token) is not charged. A failed run charges nothing. The run stops cleanly at your maximum cost per run.

#### Speed

The sample run finishes in under a second. A live base costs about one read per table plus one per automation, paced under Airtable's limit of five requests a second, so a 26-table base with 4 automations takes roughly half a minute.

#### Monitoring recipe

Schedule it daily or weekly with the same **Snapshot store name**. Each run compares with the previous snapshot, so the dataset becomes a changelog of your automations. To get alerted only on new rows, point [Dataset Diff Monitor](https://apify.com/mdcurt/dataset-diff-monitor) at this Actor.

#### Limitations

- Reads what Airtable's API exposes. Script steps are checked for table and field names and pasted secrets, not executed.
- View filters and interface settings are read for impact lists; they are not linted on their own yet.
- A base's first run has no history, so the "changed" section starts on the second run.
- Rows are not charged; the price is per base checked.

#### Changelog

- 1.0 (2026-10-31): first release. Automation lint, change tracking with the edit that introduced each new problem, impact across views, interfaces and formulas, HTML report, free sample run.

#### FAQ

**Is my token safe?** It is a secret input: Apify encrypts it and it is never written to the dataset, reports or log. It is only sent to Airtable. With `schema.bases:read` alone it cannot read or change a record.

**Does it change anything in my base?** No. Every call it makes is a read.

**Does it need a paid Airtable plan?** No. It works on every plan. Script steps only exist on paid plans, so script checks apply there.

**Why are there no changes on my first run?** The first run saves a baseline to compare with. Problems in the current base are reported straight away.

**Does it use AI?** No. Every check is a fixed rule, so the same base always gives the same result.

# Actor input Schema

## `airtableToken` (type: `string`):

A read-only token with only the <code>schema.bases:read</code> scope. Create one at <a href='https://airtable.com/create/tokens' target='_blank'>airtable.com/create/tokens</a> and add each base under <b>Access</b>.<br><br><b>Leave empty to see a free worked example</b> on a bundled sample base.

## `baseIds` (type: `array`):

Airtable base IDs (app...), one per line. Whole base URLs work too; the ID is taken out of them.

## `minSeverity` (type: `string`):

Drop findings and changes milder than this. Reports are sorted worst first either way.

## `snapshotStoreName` (type: `string`):

Named key-value store that keeps one snapshot per base, so each run can compare with the last. Use a different name per schedule.

## `includeHtmlReport` (type: `boolean`):

A self-contained web page per base, linked from that base's summary row.

## `maxBases` (type: `integer`):

Stop after this many bases.

## Actor input object example

```json
{
  "baseIds": [],
  "minSeverity": "low",
  "snapshotStoreName": "airtable-automation-watch-snapshots",
  "includeHtmlReport": true,
  "maxBases": 50
}
```

# Actor output Schema

## `findings` (type: `string`):

One row per finding or change: severity, automation and step, what is wrong, how to fix it, before/after, the edit that introduced it, and what it affects. Each row links its base's HTML report.

## `summary` (type: `string`):

OUTPUT record: one summary per base (counts by severity, baseline or compared-with time, report link) and any skipped bases.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("mdcurt/airtable-automation-watch").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("mdcurt/airtable-automation-watch").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call mdcurt/airtable-automation-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mdcurt/airtable-automation-watch"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Fd7QXSZUb3DwTNQ1g/builds/WjX0aroIMfURWve5U/openapi.json
