Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Airtable

Connect Bubble to Airtable by adding the free API Connector plugin and pointing it at the Airtable REST API with a Personal Access Token in a Private header. Airtable's 5 requests-per-second rate limit applies across all your app's simultaneous users — cache data in Bubble's database for any page with more than a handful of concurrent visitors rather than fetching live per user.

What you'll learn

  • How to create a scoped Airtable Personal Access Token for read-only or read-write access
  • How to find your Airtable Base ID from the URL
  • How to configure the Bubble API Connector with the correct base URL and Private Authorization header
  • How to set up API calls for listing records, filtering with `filterByFormula`, and paginating with `offset`
  • How to initialize Bubble API Connector calls so Bubble correctly detects Airtable's response schema
  • How to handle Airtable's 5 req/sec rate limit with caching and scheduled syncs
  • How to write records back to Airtable from Bubble workflows using POST and PATCH calls
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner21 min read1–2 hoursDatabase & BackendLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Airtable by adding the free API Connector plugin and pointing it at the Airtable REST API with a Personal Access Token in a Private header. Airtable's 5 requests-per-second rate limit applies across all your app's simultaneous users — cache data in Bubble's database for any page with more than a handful of concurrent visitors rather than fetching live per user.

Quick facts about this guide
FactValue
ToolAirtable
CategoryDatabase & Backend
MethodBubble API Connector
DifficultyBeginner
Time required1–2 hours
Last updatedJuly 2026

Bubble + Airtable: a polished frontend on top of your team's data

Airtable and Bubble are complementary tools that serve opposite ends of a common workflow. Your operations team, marketing team, or product team maintains records in Airtable because the grid interface is familiar and requires no technical knowledge — they can add rows, edit fields, attach files, and manage views without involving a developer. Bubble, on the other hand, renders polished, interactive user interfaces that your customers or internal users interact with. Connecting the two means your non-technical team controls the data, and Bubble controls the experience. The integration is simpler than almost any other Bubble backend connection: Airtable has a public REST API that needs only a Personal Access Token in an Authorization header. There is no plugin to buy, no server to deploy, no SDK to initialize. You configure the API Connector once with your base ID and PAT, define API calls for each table operation, and start binding Airtable data to repeating groups and form submissions. The one critical operational concern is rate limiting: Airtable allows only 5 API requests per second per base, counting requests from all your Bubble app's users combined. A page that fires one Airtable API call when it loads will hit the rate limit if 6 or more users open that page at the same second. The solution is data caching: use a Bubble scheduled workflow to sync Airtable data into Bubble's own database every few minutes, and serve most users from Bubble's fast native database rather than live Airtable API calls. Reserve live Airtable calls for actions where fresh data is essential — form submissions, confirmations, write-backs.

Integration method

Bubble API Connector

The Bubble API Connector (free plugin by Bubble) calls the Airtable REST API at `https://api.airtable.com/v0/{baseId}` with a Personal Access Token in a Private `Authorization` header — no separate plugin or proxy needed.

Prerequisites

  • An Airtable account with at least one base containing the data you want to display or write to in Bubble
  • A Bubble app (any plan — read-only API calls work on the free plan; write operations via Backend Workflows require Starter plan or above)
  • The free API Connector plugin by Bubble installed in your app (Plugins → Add plugins → search 'API Connector')
  • Your Airtable Base ID from the base URL (e.g. `airtable.com/appXXXXXXXXXXXXXX/...` — the segment starting with 'app')
  • An Airtable Personal Access Token scoped to the relevant base with at least `data.records:read` scope (add `data.records:write` if Bubble will create or update records)

Step-by-step guide

1

Step 1 — Create an Airtable Personal Access Token

Log in to your Airtable account at airtable.com. In the top-right corner, click your profile avatar and select 'Developer hub,' or navigate directly to airtable.com/create/tokens. Click 'Create token.' Give it a descriptive name like 'Bubble Integration — [Your App Name].' Under 'Scopes,' add `data.records:read` if you only need to display Airtable data in Bubble. If Bubble will also create or update records (for example, a form that writes leads to Airtable), also add `data.records:write`. Under 'Access,' click 'Add a base' and select the specific Airtable base you want to connect — scoping a PAT to only the bases it needs follows the principle of least privilege. Click 'Create token.' Copy the token immediately and save it somewhere secure (a password manager). Airtable shows the token only once — if you lose it, you will need to create a new one. Also note your Base ID: open your Airtable base in the browser and look at the URL, which looks like `airtable.com/appXXXXXXXXXXXXXX/tblXXXXXXXXXXXXXX/viwXXXXXXXXXXXXXX`. The segment starting with 'app' is your Base ID.

airtable-auth-reference.txt
1// Airtable Personal Access Token scope reference
2// Navigate to: airtable.com/create/tokens
3
4// Minimum scope for read-only Bubble integration:
5// data.records:read
6
7// Add these for write operations from Bubble:
8// data.records:write
9
10// Your Base ID is in the URL when viewing your base:
11// https://airtable.com/appXXXXXXXXXXXXXX/tblYYYYYYYYYYYYYY/viwZZZZZZZZZZZZZZ
12// ^^^^^^^^^^^^^^^^^^^
13// This is your baseId
14
15// API base URL pattern:
16// https://api.airtable.com/v0/{baseId}/{tableName}

Pro tip: Create separate tokens for read and write operations. The read-only token (data.records:read only) can be used in client-side Bubble workflows with lower risk if it is ever exposed, because it cannot create or modify records. The write token (data.records:write) should be used only in Bubble Backend Workflows with a Private header. This two-token approach limits blast radius if either token is compromised.

Expected result: You have an Airtable Personal Access Token copied and saved. You have noted your Base ID (starts with 'app') from the Airtable URL. The token appears as a long string beginning with 'pat'.

2

Step 2 — Install the API Connector plugin and configure the Airtable API group

Open your Bubble app editor and click 'Plugins' in the left sidebar. If the API Connector plugin by Bubble does not appear in your installed plugins list, click 'Add plugins,' search for 'API Connector,' and install it (it is free). Return to the Plugins tab and click 'API Connector.' You will see an 'Add another API' button — click it. Name this API group 'Airtable.' In the 'Root URL' field, enter your Airtable base's root endpoint: `https://api.airtable.com/v0/appXXXXXXXXXXXXXX` (replace with your actual Base ID). Under 'Shared headers across all calls,' click 'Add a shared header.' For the key, type `Authorization`. For the value, type `Bearer ` followed by your Personal Access Token (for example: `Bearer patXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX`). Check the 'Private' checkbox next to this header — this is critical. It ensures the PAT is used only server-side on Bubble's servers and never sent to a visitor's browser. Add a second shared header: key `Content-Type`, value `application/json` (no Private checkbox needed). Your API group is now configured. All API calls you add under this group will automatically use these headers for every request.

api-connector-airtable-group.json
1// Bubble API Connector — Airtable group configuration
2{
3 "api_group_name": "Airtable",
4 "root_url": "https://api.airtable.com/v0/appXXXXXXXXXXXXXX",
5 "shared_headers": [
6 {
7 "key": "Authorization",
8 "value": "Bearer patXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
9 "private": true
10 },
11 {
12 "key": "Content-Type",
13 "value": "application/json"
14 }
15 ]
16}

Pro tip: The root URL includes your Base ID — this means all calls in this API group target the same Airtable base. If you need to connect to multiple Airtable bases, create separate API groups in the API Connector, each with its own root URL and PAT. You can name them 'Airtable — [Base Name]' to distinguish them.

Expected result: The Airtable API group appears in your API Connector with the correct root URL and two shared headers (Authorization marked Private, Content-Type). No individual API calls have been added yet.

3

Step 3 — Add the 'List Records' API call and initialize it

Inside the Airtable API group you just created, click 'Add call.' Name this call 'List [TableName] Records' (replace TableName with your actual Airtable table name, for example 'List Products Records'). Set the method to GET. In the endpoint URL field, type `/{tableName}` — replacing tableName with the exact name of your Airtable table as it appears in Airtable (case-sensitive, spaces are URL-encoded automatically by Bubble, for example `/Products` or `/Blog Posts`). Add URL parameters: click 'Add parameter' and add `maxRecords` with an example value of `100` (the API maximum per page; leave the value flexible so you can pass it from workflows). Optionally add `filterByFormula` (example: `{Status}='Published'`) and `sort[0][field]` with `sort[0][direction]` for sorting. Leave 'Use as' set to 'Data' — this tells Bubble the response should be mappable to a list data type. Now, critically: before clicking 'Initialize call,' make sure your Airtable table has at least one record with real data. Airtable returns an empty `records: []` array for empty tables, and Bubble cannot detect field names from an empty array — it will show no fields to map. With a record in the table, click 'Initialize call.' Bubble fires a real GET request to Airtable using your PAT. If the PAT is valid and the base ID is correct, Airtable returns the first page of records and Bubble displays the detected fields (id, createdTime, fields.FieldName, etc.). Click 'Save.'

airtable-list-records-call.json
1// GET call: List records from an Airtable table
2// Endpoint (appended to root URL): /{tableName}
3// Full URL example: GET https://api.airtable.com/v0/appXXXXX/Products
4
5// Query parameters:
6{
7 "maxRecords": "100",
8 "filterByFormula": "{Status}='Published'",
9 "sort[0][field]": "Name",
10 "sort[0][direction]": "asc",
11 "fields[]": "Name", // optional: request only specific fields
12 "offset": "<dynamic>" // for pagination (from previous page's response)
13}
14
15// Airtable response structure:
16{
17 "records": [
18 {
19 "id": "recXXXXXXXXXXXXXX",
20 "createdTime": "2024-01-15T10:30:00.000Z",
21 "fields": {
22 "Name": "Product A",
23 "Status": "Published",
24 "Price": 49.99,
25 "Category": "Electronics"
26 }
27 }
28 ],
29 "offset": "recYYYYYYYYYYYYYY" // present only if more pages exist
30}

Pro tip: Airtable column names are case-sensitive and must match exactly in `filterByFormula` expressions. If your column is named 'Product Name' (with a space), use `{Product Name}` in the formula. Spaces in column names are fine — Airtable handles them in curly-brace filter syntax. In Bubble's API response mapping, fields with spaces in their names appear as-is and Bubble handles them correctly.

Expected result: The 'List [TableName] Records' call is initialized with a green checkmark. Bubble shows detected fields including `records body list of record`, and within each record the `fields` object with your Airtable column names. The call is set to 'Use as: Data.'

4

Step 4 — Add Create and Update API calls for writing data to Airtable

If your Bubble app needs to write data back to Airtable (from form submissions, button clicks, or workflow triggers), add two more API calls in the Airtable group. First, click 'Add call' and name it 'Create [TableName] Record.' Set method to POST, endpoint to `/{tableName}`. In the Body section, set type to JSON and add the body structure: `{"fields": {"FieldName": "{{value}}", "AnotherField": "{{otherValue}}"}}`. Replace FieldName and AnotherField with your actual Airtable column names — they must match exactly. The values in double curly braces are dynamic placeholders that Bubble will fill in from workflow inputs. Set 'Use as' to 'Action' (since this call creates a record, not fetches data). Second, add another call named 'Update [TableName] Record.' Set method to PATCH, endpoint to `/{tableName}/{recordId}` (add `recordId` as a URL parameter). Body: `{"fields": {"FieldName": "{{newValue}}"}}`. PATCH in Airtable updates only the fields you specify — unspecified fields keep their current values. Set 'Use as' to 'Action.' For the Initialize call on both POST and PATCH, you will need to provide real example values in the body parameters that match your field types — Airtable returns the created or updated record on success. Click 'Initialize call' to verify the response shape, then save.

airtable-write-calls.json
1// POST call: Create a new record in Airtable
2// Endpoint: /{tableName}
3// Method: POST
4// Use as: Action
5
6// Request body:
7{
8 "fields": {
9 "Name": "{{name}}",
10 "Email": "{{email}}",
11 "Status": "New",
12 "Created Date": "{{created_date}}"
13 }
14}
15
16// Airtable response on success (200):
17{
18 "id": "recXXXXXXXXXXXXXX",
19 "createdTime": "2024-01-15T10:30:00.000Z",
20 "fields": {
21 "Name": "John Doe",
22 "Email": "john@example.com",
23 "Status": "New",
24 "Created Date": "2024-01-15"
25 }
26}
27
28// PATCH call: Update specific fields on an existing record
29// Endpoint: /{tableName}/{recordId}
30// Method: PATCH
31// Use as: Action
32
33// Request body (only include fields to update):
34{
35 "fields": {
36 "Status": "{{new_status}}",
37 "Updated Date": "{{updated_date}}"
38 }
39}

Pro tip: Airtable date fields expect ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss.sssZ). In Bubble workflows, use the ':formatted as' operator on date fields to format them as ISO 8601 before passing to the API call. Number fields must be actual numbers, not strings — Airtable will return a 422 Unprocessable Entity error if you pass '49.99' (string) instead of 49.99 (number).

Expected result: The Airtable API group now has three calls: List Records (GET, Use as Data), Create Record (POST, Use as Action), and Update Record (PATCH, Use as Action). All three are initialized with green checkmarks.

5

Step 5 — Bind Airtable data to a Bubble repeating group

With your API calls initialized, you can now display Airtable records in Bubble's UI. In the Bubble editor, drag a Repeating Group element onto your page. In the Repeating Group's settings panel, set 'Type of content' to 'Airtable List [TableName] Records record' (or similar — Bubble names the type based on the API call name). Set 'Data source' to 'Get data from an external API' → select 'Airtable - List [TableName] Records.' Pass any parameters Bubble asks for (like maxRecords or filterByFormula). Inside the Repeating Group's first cell, add text elements, image elements, and other UI components. To bind an element's value to an Airtable field: click the text element → click 'Insert dynamic data' → 'Current cell's Airtable List [TableName] Records record's fields Name' (or whatever field you need). Airtable field names with spaces appear in the dropdown as-is. If a field does not appear in the dropdown, re-initialize the API call after ensuring that field has a value in at least one record. Repeat this for each field you want to display. To implement a filtered view, add a dropdown or search input on the page. Set the Repeating Group's data source to include the filter: in the 'filterByFormula' parameter, reference the dropdown's value using Bubble's dynamic expression builder. The Repeating Group will re-query Airtable when the filter value changes.

repeating-group-airtable-binding.txt
1// Bubble Repeating Group setup (conceptual, configured in Bubble editor)
2// Type of content: Airtable - List Products Records - record
3// Data source: Get data from an external API
4// API: Airtable
5// Call: List Products Records
6// Parameters:
7// maxRecords: 100
8// filterByFormula: AND({Status}='Published', {Category}=Input Category Filter's value)
9// sort[0][field]: Name
10// sort[0][direction]: asc
11
12// Inside repeating group first cell:
13// Text element: Current cell's record's fields Name
14// Text element: Current cell's record's fields Price :formatted as $#,###.##
15// Image element: Current cell's record's fields Image URL
16// Button: On click → Call Airtable 'Update Products Record'
17// recordId: Current cell's record's id
18// new_status: 'Archived'

Pro tip: The Airtable API returns a maximum of 100 records per page. If your table has more than 100 records, you need to implement pagination using the `offset` field returned in each response. The offset is an opaque string — pass it as the `offset` parameter in the next API call to get the next page. Bubble does not handle pagination automatically; you need to store the offset value in an app state and trigger subsequent API calls from a 'Load more' button.

Expected result: The Repeating Group on your Bubble page displays data from your Airtable base. Each row in the repeating group corresponds to an Airtable record. Bubble's UI previewer shows the records in real time when you run the app.

6

Step 6 — Implement a scheduled sync to handle rate limits at scale

Airtable's 5 requests-per-second rate limit applies across all users of your Bubble app simultaneously, not per user. If your page makes one Airtable API call on load and 6+ users open it at the same moment, you will hit the limit and receive HTTP 429 errors, which appear as empty repeating groups or silent failures in Bubble. The production-safe pattern is to cache Airtable data in Bubble's own database. Create a Bubble data type that mirrors your Airtable table structure (for example, a 'Product' data type with fields matching your Airtable columns, plus an 'airtable_record_id' text field to track the Airtable record ID). Enable Backend Workflows in your Bubble app (Starter plan or above required). Create a Backend Workflow named 'Sync Airtable Products.' Inside it, add an API call step: Airtable - List Products Records (with maxRecords=100 and filterByFormula for active records). For each record in the response, use 'Search for Products where airtable_record_id = [record id]': if found, update the existing Bubble Product; if not found, create a new one. Finally, schedule this Backend Workflow to run on a recurring schedule (every 15 or 30 minutes) using Bubble's 'Schedule API workflow (recurring)' action, triggered on page load or from an admin button. Once the sync runs, change your UI repeating groups to use 'Search for Products' from Bubble's database instead of the live Airtable API call. Users now get fast, database-speed responses, and Airtable is only called by the scheduled sync workflow — typically once every 15 minutes regardless of user count. If RapidDev's team can help you design this sync architecture for your specific Airtable schema, reach out for a free scoping call at rapidevelopers.com/contact.

airtable-sync-workflow.txt
1// Bubble Backend Workflow: 'Sync Airtable Products'
2// Triggered: Recurring schedule (every 15 minutes)
3// Requires: Starter plan (Backend Workflows)
4
5// Step 1: Call Airtable API
6// API call: Airtable - List Products Records
7// Parameters: maxRecords=100, filterByFormula={Status}='Published'
8
9// Step 2: For each record in Step 1's response records list
10// (Use 'Schedule API workflow on a list' → 'Upsert Single Product' sub-workflow)
11
12// Sub-workflow 'Upsert Single Product' (parameter: record = one Airtable record):
13// Search for Products where airtable_record_id = input record id
14// If found (count > 0):
15// Make changes to thing: update Product fields from input record fields
16// If not found (count = 0):
17// Create new thing: Product with airtable_record_id = input record id
18// and all fields from input record fields
19
20// Result: Bubble database stays in sync with Airtable
21// UI repeating groups: use 'Search for Products' (Bubble DB, fast, no rate limits)
22// not 'Get data from external API' (live Airtable, rate-limited)

Pro tip: For tables with more than 100 records, chain multiple sync calls using Airtable's `offset` pagination. After the first sync step, check if the response includes an `offset` field. If it does, schedule a second 'Sync Airtable Products - Page 2' workflow immediately with the offset value as a parameter to fetch the next 100 records. Repeat until no offset is returned. This daisy-chain approach handles unlimited record counts within Bubble's workflow system.

Expected result: A recurring Backend Workflow syncs your Airtable data into Bubble's database every 15 minutes. Your UI pages use Bubble's native database for display (fast, no rate limits) and call Airtable directly only for write-back actions (form submissions, status updates) where fresh data is required.

Common use cases

Ops-managed content directory rendered in Bubble

Your team maintains a directory of resources, products, or listings in Airtable — adding new rows, updating statuses, and tagging records without any developer involvement. A Bubble scheduled workflow syncs Airtable records into Bubble's database every 15 minutes. Bubble renders a searchable, filterable directory from its native database, serving users quickly without hitting Airtable's rate limit. When a new record is manually added in Airtable, it appears in Bubble at the next sync cycle.

Bubble Prompt

Every 15 minutes, run Backend Workflow: search Airtable for all records in 'Resources' table where Status is 'Published', create or update matching Bubble Resource records, and delete Bubble Resource records not found in the Airtable sync result

Copy this prompt to try it in Bubble

Bubble form writes back to Airtable as a CRM intake

A Bubble landing page captures lead information via a form. On submission, a Bubble workflow fires an API Connector POST call to create a new record in an Airtable 'Leads' table. The sales team immediately sees the new lead in Airtable's grid view, can assign owners, change status, and add notes — all without touching Bubble. The Bubble form serves as the data entry front end while Airtable is the CRM.

Bubble Prompt

When Submit button is clicked and Form is valid, call Airtable API 'Create Lead Record' with fields: Name = Input Name's value, Email = Input Email's value, Source = 'Website Form', Created = Current date/time

Copy this prompt to try it in Bubble

Airtable-powered event or course catalog

A non-technical team manages an events or courses catalog in Airtable, including dates, descriptions, image links, pricing, and capacity. Bubble fetches this data and renders a card-based catalog with filtering by category, date range, and price. Users can register for events via Bubble, which writes a registration record back to Airtable and updates remaining capacity using a PATCH call.

Bubble Prompt

On page load, call Airtable 'Get Events' with filterByFormula: AND(IS_AFTER({Date}, TODAY()), {Status}='Published'), sort by Date ascending, display results in repeating group, filter by Category dropdown selection

Copy this prompt to try it in Bubble

Troubleshooting

Bubble's 'Initialize call' returns no fields or shows an empty response from Airtable

Cause: The Airtable table has no records, or the `filterByFormula` example value you provided during initialization matches zero records. Airtable returns `{"records": []}` for an empty result, and Bubble cannot detect field names from an empty array.

Solution: Before initializing, ensure your Airtable table has at least one real record with values in the fields you want to use. Temporarily remove or relax the `filterByFormula` parameter during initialization. After Bubble detects the field schema, you can re-add the filter to the call's parameters. Re-initialize by clicking 'Initialize call' again after adding a record.

Airtable returns HTTP 429 errors and Bubble repeating groups appear empty or show an error state

Cause: Your app's users are collectively exceeding Airtable's 5 requests-per-second rate limit for your base. This happens when multiple users load a page simultaneously and each page load triggers an Airtable API call.

Solution: Implement the scheduled sync pattern from Step 6: cache Airtable data in Bubble's database every 15–30 minutes and serve UI from Bubble's database instead of live Airtable calls. For pages that must show live Airtable data, add Bubble's 'When API Call returns an error' event to show a user-friendly message and retry after a 1-second pause using a scheduled workflow.

Bubble API Connector returns 401 Unauthorized when calling Airtable

Cause: The Personal Access Token is invalid, expired, or was not entered correctly in the Authorization header. Common mistakes: missing the 'Bearer ' prefix (with a space), the token was truncated when copied, or the token was revoked in Airtable's developer hub.

Solution: Open Airtable's developer hub at airtable.com/create/tokens and verify the token still exists and has not been revoked. If in doubt, create a new token. In Bubble's API Connector, click the Airtable group, find the Authorization shared header, and re-paste the full token value: `Bearer patXXXXXXXXXXXXXX...` (with 'Bearer ' including the space before the token string). Click Initialize call to verify the fix.

typescript
1// Correct Authorization header format:
2// Key: Authorization
3// Value: Bearer patXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4// ^ ^
5// | The actual token (starts with 'pat')
6// 'Bearer ' with a space after it

A POST call to create an Airtable record returns 422 Unprocessable Entity

Cause: One or more field values in the request body do not match the expected type in Airtable. Common causes: sending a number field as a quoted string, sending a date in the wrong format, or using a field name that does not exactly match the Airtable column name (case-sensitive).

Solution: Check the error response body in Bubble's Logs tab — it will specify which field failed and why. Verify that number fields receive numeric values (not quoted strings), date fields receive ISO 8601 format (YYYY-MM-DD), and that field names in your POST body exactly match the Airtable column names including capitalization and spaces. Field names are case-sensitive: 'Product Name' is different from 'product name'.

typescript
1// Common type fixes for Airtable POST body:
2// Date field: use Bubble's ':formatted as' → Custom → 'YYYY-MM-DD'
3// Number field: ensure value is not wrapped in quotes in the JSON body
4// Linked record field: pass an array of record IDs ["recXXXXXXXX"]
5// Multi-select: pass an array of option strings ["Option A", "Option B"]

Linked record fields in Airtable show record IDs like 'recXXXXXXXX' instead of the linked record's actual content

Cause: Airtable's API returns linked record fields as arrays of record IDs (internal Airtable identifiers), not the content of the linked records. This is expected API behavior — the linked record data requires a separate API call to retrieve.

Solution: For each linked record you need to display, make a second API call: GET `/{LinkedTableName}/{recordId}` to retrieve the linked record's fields. In Bubble workflows, use the linked record IDs to trigger additional API calls and store the fetched data. Alternatively, use Airtable's 'Lookup' field type to pull specific values from linked records into the current table as a flat field — these appear directly in the records response without a second API call.

Best practices

  • Use a read-only PAT (`data.records:read` scope only) for Bubble workflows that display Airtable data, and a separate write-scoped PAT (`data.records:write`) for workflows that create or update records — store both in the API Connector with the Private checkbox enabled
  • Cache Airtable data in Bubble's database with a scheduled sync workflow (every 15–30 minutes) for any page with more than a handful of concurrent users — Airtable's 5 req/sec per base rate limit is reached quickly at real user volumes
  • Use Airtable's `filterByFormula` parameter to filter records server-side before they reach Bubble, rather than fetching all records and filtering in the Bubble workflow — this reduces API call size and lowers rate limit pressure
  • Add an `airtable_record_id` text field to Bubble data types that mirror Airtable tables — this enables your sync workflow to distinguish between records to create versus update, preventing duplicates
  • Apply Bubble's Data tab → Privacy rules to any data type that stores synced Airtable records, ensuring that users can only see records they are permitted to access — the Airtable PAT controls Airtable access, but Bubble's privacy rules control what each user sees in your app
  • Handle Airtable pagination explicitly: the API returns a maximum of 100 records per request, with an `offset` field in the response when more pages exist — your sync workflow must chain calls using the offset until no more pages remain
  • Monitor Airtable API call WU consumption in Bubble's Logs tab → Workflow logs when using Backend Workflows for sync operations — each API call in a workflow consumes Workload Units, and syncing large Airtable tables frequently can become expensive on Bubble's paid plans
  • Create dedicated Airtable views (using Airtable's filter and sort settings) and reference them by view ID in your API calls using the `view` parameter — this lets your non-technical team control which records appear in Bubble by managing Airtable view filters, without requiring any Bubble code changes

Alternatives

PostgreSQL (via Supabase)

Supabase exposes PostgreSQL via a REST API with built-in Row Level Security, has no per-request rate limit comparable to Airtable's 5 req/sec ceiling, and supports millions of records with full SQL join power. Choose Supabase when your data volume is large, your team is comfortable with structured schemas, or you need relational queries Airtable cannot express. Choose Airtable when your non-technical ops or marketing team is already managing the data in Airtable and the grid UI is part of their workflow.

Notion

Notion's database API offers similar no-code data management with richer content blocks (text, embeds, kanban) alongside the database rows. Airtable is stronger for pure tabular data with calculated fields, linked records, and Gantt/calendar views; Notion excels when the data involves long-form documentation. Notion's API rate limit is also more restrictive than Airtable's. If your team uses Notion for project management and wikis, the Notion API may suit content-heavy Bubble pages.

Firebase Firestore

Firebase Firestore offers real-time data sync via the Zeroqode plugin, scales to millions of documents, and has no record caps. It requires a paid Zeroqode plugin and has a steeper setup curve compared to Airtable's simple REST API. Choose Firestore when your Bubble app needs real-time updates (live chat, collaborative editing, live dashboards) or when your data volume exceeds Airtable's plan limits. Choose Airtable when your team needs to manage the data visually in a spreadsheet-like interface.

Frequently asked questions

Can I use the Airtable integration on Bubble's free plan?

Yes, for reading data. Bubble's free plan supports client-side API Connector calls, so you can display Airtable records in repeating groups and data elements. The limitation is for write operations: POST and PATCH calls should go through Backend Workflows (which require a Starter plan or above) to avoid exposing your write-scoped PAT in browser DevTools. Read-only integrations using a read-scoped PAT with the Private header flag work on the free plan.

Airtable's rate limit is 5 requests per second — does that mean 5 users per second?

Not quite. The 5 req/sec limit applies to the total number of API requests your application makes to that base per second — across all users. If 5 users each trigger one Airtable API call at the same moment, that is 5 simultaneous requests and you are at the limit. If 6 users do the same, the 6th request fails with HTTP 429. This is why caching Airtable data in Bubble's database (updated by a scheduled sync) is essential for any app with meaningful user traffic — the sync workflow makes one API call per sync cycle regardless of how many users are viewing the data.

How do I display Airtable linked record values instead of just the record IDs?

Airtable's API returns linked record fields as arrays of record IDs (for example, `["recXXXXXXXXXXXXXX"]`). To display the linked record's actual field values, you need to make a second API call to `GET /{linkedTableName}/{recordId}` for each linked record. An easier alternative is to add a 'Lookup' field in Airtable that pulls specific field values from the linked table into the current table as a plain text or number field — lookup values appear directly in the records response without any additional API calls from Bubble.

Do I need to handle Airtable pagination in Bubble?

Yes, if your table has more than 100 records. Airtable returns a maximum of 100 records per API call. If there are more records, the response includes an `offset` field (a string). To fetch the next page, make the same API call with `offset` set to that value as a query parameter. In Bubble, implement pagination by storing the offset in an app state and triggering a new API call (via a 'Load more' button or automatically) that passes the stored offset. Continue until the response has no `offset` field, indicating you have reached the last page.

Can Airtable send real-time updates to Bubble when records change?

Yes, using Airtable Webhooks. Create a webhook subscription via `POST /v0/bases/{baseId}/webhooks` with the URL of a Bubble Backend Workflow endpoint. Airtable will POST a payload to that endpoint whenever records in your base are created, updated, or deleted. Set up the Backend Workflow in Bubble under Settings → API → enable Workflow API, then create a Backend Workflow with 'Detect request data.' Use the Backend Workflow endpoint URL (without the `/initialize` suffix for production) as the webhook destination in Airtable. Note that Airtable webhook subscriptions expire after 7 days of inactivity and require renewal — plan for automatic renewal in your Bubble workflow. Airtable Webhooks require an Airtable Team plan or above.

My Airtable field names have spaces and special characters — will that cause problems in Bubble?

No, Bubble handles field names with spaces correctly. When Bubble's API Connector initializes an Airtable call, it maps all detected field names exactly as returned by the API, including names with spaces (for example, 'Product Name', 'Created Date'). These appear in Bubble's dynamic data dropdown with their original names. The only place to be careful is in `filterByFormula` expressions: always wrap field names in curly braces, even if they have no spaces — `{Name}`, `{Product Name}`, `{Created Date}` — and the Airtable API will handle them correctly.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.