n8n community node that triggers workflows instantly when Airtable records change — using real Airtable webhooks, not polling.
Originally forked from @vwork-digital/n8n-nodes-instant-airtable-trigger, fully rewritten by D1DX.
- Activate a workflow with this trigger — registers an Airtable webhook on your base
- Airtable sends a notification ping to n8n on every matching change
- The node fetches the webhook payloads with cursor-based pagination
- Payloads are parsed into flat per-record items with field names resolved
- Deactivate the workflow — webhook is automatically deleted
Important: Airtable webhooks expire every 7 days. Use a separate scheduled workflow to refresh them.
- Go to Settings > Community Nodes in your n8n instance
- Click Install a community node
- Enter
@d1dx/n8n-nodes-airtable - Click Install
Or via CLI:
cd ~/.n8n
npm install @d1dx/n8n-nodes-airtable
# Restart n8nAll field names map directly to the Airtable Webhooks API specification.
| Field | Airtable API | Description |
|---|---|---|
| Base | — | Dropdown of all bases (via meta API) |
| Table | — | Dropdown of tables in selected base |
| View | recordChangeScope |
Scope to a specific view. "Add" = entered view, "Remove" = left view. Form/List views not supported. Leave empty for entire table. |
| Change Types | changeTypes |
Add / Update / Remove. Leave empty = all. Sent server-side to Airtable. |
| Field | Airtable API | Description |
|---|---|---|
| Fields to Watch | watchDataInFieldIds |
Only trigger on changes to these fields. Leave empty = all fields. Warning: webhook permanently stops if a listed field is deleted. |
| Include Previous Values | includePreviousCellValues |
Include the previous value alongside current for changed fields. |
| Field | Airtable API | Description |
|---|---|---|
| Fields to Include in Output | includeCellValuesInFieldIds |
Always include these field values, even if unchanged. Select "All fields" to send "all" to API. Safe if a listed field is deleted. |
| Use Field Names | — | Resolve field IDs (e.g. fldABC123) to human names (e.g. Status) in output. |
| Field | Airtable API | Description |
|---|---|---|
| Data Types | dataTypes |
tableData (default), tableFields, tableMetadata. Can combine multiple. |
| From Sources | fromSources |
Filter by source: client, publicApi, automation, formSubmission, formPageSubmission, sync, system, anonymousUser, unknown. Empty = all. |
| Form Submission View ID | sourceOptions.formSubmission.viewId |
Filter form submissions to a specific form view. Only relevant when "Form Submission" is in From Sources. |
| Form Page Submission Page ID | sourceOptions.formPageSubmission.pageId |
Filter interface page submissions to a specific page. Only relevant when "Form Page Submission" is in From Sources. |
| Watch Field Schema Changes | watchSchemasOfFieldIds |
Only trigger on schema changes for these fields. Requires tableFields data type. Warning: webhook stops if field is deleted. |
| Include Previous Field Definitions | includePreviousFieldDefinitions |
Include previous field name/type in field change payloads. Requires tableFields data type. |
You need an Airtable Personal Access Token (PAT):
- Go to airtable.com/create/tokens
- Create a token with these scopes:
webhook:manage— register and delete webhooksdata.records:read— read webhook payloadsschema.bases:read— populate base/table/view/field dropdowns
- Grant access to the bases you want to watch
- In n8n, create an "Airtable API" credential and paste the token
One item per event. All items include eventType, recordId, tableId, source, changedBy, timestamp.
Created:
{
"eventType": "created",
"recordId": "recXXXXXXXXXXXXXX",
"tableId": "tblXXXXXXXXXXXXXX",
"viewId": "viwXXXXXXXXXXXXXX",
"createdTime": "2026-04-05T12:00:00.000Z",
"fields": { "Status": "New", "Name": "Example" },
"source": "client",
"changedBy": { "userId": "usrXXXX", "userName": "John", "userEmail": "john@example.com" },
"timestamp": "2026-04-05T12:00:00.000Z"
}Updated:
{
"eventType": "updated",
"recordId": "recXXXXXXXXXXXXXX",
"tableId": "tblXXXXXXXXXXXXXX",
"changedFields": ["Status"],
"current": { "Status": "Done" },
"previous": { "Status": "Active" },
"unchanged": { "Name": "Example" },
"source": "client",
"changedBy": { "userId": "usrXXXX", "userName": "John", "userEmail": "john@example.com" },
"timestamp": "2026-04-05T12:00:00.000Z"
}Deleted:
{
"eventType": "deleted",
"recordId": "recXXXXXXXXXXXXXX",
"tableId": "tblXXXXXXXXXXXXXX",
"source": "client",
"timestamp": "2026-04-05T12:00:00.000Z"
}| eventType | Key fields |
|---|---|
fieldCreated |
fieldId, name, type |
fieldChanged |
fieldId, current, previous |
fieldDeleted |
fieldId |
| eventType | Key fields |
|---|---|
metadataChanged |
current (name, description), previous |
| eventType | Key fields |
|---|---|
error |
code: INVALID_FILTERS, INVALID_HOOK, or INTERNAL_ERROR |
- View-scoped payloads have different structure. When
recordChangeScopeis a view, Airtable nests records insidechangedViewsByIdinstead of directly on the table. The node handles this transparently. - 10 webhooks per base. Each active workflow uses one webhook. Plan accordingly.
- Webhooks expire in 7 days. Refresh them or they stop silently.
- Field deletion kills the webhook. If a field in
watchDataInFieldIdsorwatchSchemasOfFieldIdsis deleted, the webhook enters a permanent error state. Must deactivate and reactivate. Exception:includeCellValuesInFieldIdsis safe — deleted fields are silently ignored. - Creator permissions required. The PAT owner must have Creator access to register webhooks.
- Community node updates require n8n restart. n8n loads node code at startup, not dynamically.
Hotfix — reverts the cursor change shipped in 2.3.3. Anyone on 2.3.3 should upgrade immediately: that release silently dropped every event from every Airtable trigger.
- Cursor change reverted. Restored
cursor: cursorForNextPayload - 1(the v2.3.2 form). Empirical probe of Airtable's/bases/{base}/webhooks/{id}/payloadsendpoint: whencursorForNextPayload = N,?cursor=Nreturns 0 payloads;?cursor=N-1returns the latest payload. Airtable'scursorForNextPayloadis the cursor of the next-to-be-generated payload, not the next-to-fetch — the v2.3.3 changelog claim was wrong. The- 1fetches the most recent payload as intended. - Bug 2 (delete-error logging) and bug 3 (create-side dedup) from 2.3.3 are kept. Both verified working live during the 2.3.3 deploy cycle (cleaned 2 stale webhooks).
- Known limitation (deferred to 2.4.0): the trigger fetches only the latest payload per fire. If multiple events land between fires, only the most recent is emitted. Source-of-truth move to staticData
lastCursorplus pagination viamightHaveMoreis the planned fix.
Three trigger-node bug fixes uncovered during a flood-rate investigation on a long-running production workflow. Bug-1 fix introduced a regression that silently drops every webhook event; reverted in 2.3.4 above.
- Cursor re-read "fix" was wrong. Changed
cursor: cursorForNextPayload - 1→cursor: cursorForNextPayload. Empirical re-test (post-publish) showed N points to the next-to-be-generated payload, so?cursor=Nreturns 0 rows. Reverted in 2.3.4. The original- 1was correct. delete()no longer fails silently. Previously caught any DELETE error and returnedfalsewith no log line. n8n then proceeded tocreate()and the old webhook stayed live in Airtable alongside the new one — duplicate webhooks accumulated across save cycles. Now logs the error message viaconsole.errorso the failure is diagnosable. Return value stillfalseso the n8n deactivate flow continues to work. (Kept in 2.3.4.)create()is now idempotent. Before POSTing a new webhook, GETs the base's existing webhooks, finds any whosenotificationUrlmatches this n8n endpoint, and DELETEs them first. Stops the duplicate-accumulation pattern at the source. Pre-create dedup also self-heals from situations where priordelete()calls failed silently. (Kept in 2.3.4.)
- Respect Data Types selection when emitting events — schema/metadata events were previously emitted unconditionally.
This package ships pre-built dist/ files. There is no .ts source committed to this repo. Edit dist/nodes/AirtableTrigger/AirtableTrigger.node.js directly and bump the version in package.json. The prepublishOnly script runs node --check against the dist files as a syntax guard before npm publish.
Do not run npm run build — tsc has no source to compile and would clobber the dist files with empty output.
CI: pushing a v* tag triggers .github/workflows/publish.yml, which checks out the tag and runs npm publish with the NPM_TOKEN secret.
Originally created by Jacob Vendramin at vwork Digital as @vwork-digital/n8n-nodes-instant-airtable-trigger (MIT license). Forked and rewritten by D1DX.
MIT — see LICENSE.md