Skip to content

Google Sheets Integration

Bridge Town integrates with Google Sheets through a secure, Picker-based workflow: select a Sheet through Google’s OAuth Picker so Bridge Town gains access to exactly that Sheet, import it as an immutable snapshot using ingest_data_source, then build models against the snapshot and write results back with write_gsheet. Claude can also create new Sheets on your behalf as part of a write_gsheet call — no separate tool required.

The connection is two-way: Bridge Town reads the tabs you sync, and when asked, it can write run outputs back to the same sheet. Access is limited to the files you explicitly select — Bridge Town uses drive.file scope only and cannot browse or access other spreadsheets in your Drive.

  • A Bridge Town account with at least one project
  • Access to the Bridge Town web app at app.bridgetown.builders
  • A Google account with access to the sheet(s) you want to import

Step 1 — Connect your Google account and select a Sheet

Section titled “Step 1 — Connect your Google account and select a Sheet”

Before Claude can import a Google Sheet, you must select the Sheet through the Bridge Town web app. This is a one-time step per sheet — Bridge Town stores your Google connection so you can add more sheets without re-authenticating.

  1. Open app.bridgetown.builders and go to Data Sources (/data).
  2. Click Connect Google Sheet on the Google Sheet card to open the four-step connection wizard.
  3. Step 1 — Google account: Connect your Google account or continue with an existing connection. The wizard shows exactly what access is being granted before any redirect. If your account authorization has expired, click Reconnect instead to reauthorize.
  4. Step 2 — Choose spreadsheet: Click Open Google file picker and select the Sheet you want to connect. If Picker cannot open (popup blocker or load failure), paste the Sheet URL as a fallback.
  5. Step 3 — Configure: Review real tab names, row counts, and column counts. Select the tabs to sync, confirm the source name (prefilled from the Sheet title) and project, and choose a refresh schedule (Manual, Hourly, or Daily).
  6. Step 4 — Done: Bridge Town connects the Sheet and shows the registered tables with a sample query_data call you can use immediately.

Once authorised, Bridge Town stores an encrypted OAuth refresh token. You will not need to re-authenticate unless you revoke access in your Google account settings or the token expires (the web app shows a Needs attention pill and Reconnect action when that happens).

Ask Claude to import the connected sheet, or call ingest_data_source directly using the source_name assigned when you connected the sheet in Step 1:

{
"name": "ingest_data_source",
"arguments": {
"project_name": "revenue-model",
"spec": {
"kind": "google_sheet_snapshot",
"source_name": "revenue_model_actuals",
"tab_names": ["Sales", "Costs"]
}
}
}

Omit tab_names to import all tabs. Supply schedule_interval_minutes to enable automatic refresh:

{
"name": "ingest_data_source",
"arguments": {
"project_name": "revenue-model",
"spec": {
"kind": "google_sheet_snapshot",
"source_name": "revenue_model_actuals",
"schedule_interval_minutes": 60
}
}
}

The tool reads each tab, converts it to CSV, and uploads it to Bridge Town’s data store as an immutable Parquet snapshot.

ErrorCauseFix
OAuth credentials missingWeb app OAuth not completedComplete Step 1
Data source not foundsource_name does not match a connected sheetCall list_data_sources to see connected sheet names
Tab not foundTab name is case-sensitiveVerify exact tab name in Google Sheets
Google API rate limitToo many requestsWait 60 seconds and retry

The ingest_data_source response includes row counts and the snapshot_taken_at timestamp:

{
"project_name": "revenue-model",
"source_name": "revenue_model_actuals",
"source_type": "google_sheets",
"data_source_id": "uuid",
"tables": ["revenue_model_actuals_Sales", "revenue_model_actuals_Costs"],
"row_count": 120,
"snapshot_taken_at": "2026-04-09T17:00:00+00:00"
}

To explore the imported data, use query_data with SQL — Google Sheet snapshots are queryable alongside uploaded Parquet files. Each tab is exposed as a DuckDB table named {source_name}_{tab_name} (non-alphanumeric characters in the tab name are replaced with underscores). For example, source revenue_model_actuals, tab Q1 Sales → table revenue_model_actuals_Q1_Sales.

SELECT product_line, SUM(revenue) AS total
FROM revenue_model_actuals_Sales
GROUP BY product_line
ORDER BY total DESC

The sources field in the query_data response includes snapshot_taken_at for each Google Sheets source so you can verify freshness. Call ingest_data_source again with the same source_name to refresh the snapshot before querying when current data is needed.

Alternatively, generate a model that reads from the snapshot at runtime via read_csv() for more complex transformations.

Once data is imported, use create_file to create a model file, then patch_file or update_file to implement logic that reads from the snapshot at runtime.

After a model run completes, write its outputs back to Google Sheets with write_gsheet. Use spec.mode to choose the operation.

Target the linked sheet by source_name (the name shown in list_data_sources) — this is the preferred approach because it works naturally with the connected- sheet workflow and avoids manual ID copy/paste.

spec.mode="replace" writes to a targeted A1 notation range. Only cells within the specified range are overwritten — content outside is preserved.

{
"name": "write_gsheet",
"arguments": {
"project_name": "revenue-model",
"spec": {
"mode": "replace",
"run_id": "uuid-from-run",
"output_name": "forecast.json",
"source_name": "revenue_model_actuals",
"cell_range": "Forecast!A1"
}
}
}

spec.mode="append" adds rows after existing content without overwriting.

{
"name": "write_gsheet",
"arguments": {
"project_name": "revenue-model",
"spec": {
"mode": "append",
"run_id": "uuid-from-run",
"output_name": "monthly_actuals.json",
"source_name": "revenue_model_actuals",
"sheet_name": "Actuals Log"
}
}
}

write_gsheet also supports spec.mode="clear" and spec.mode="batch" (write explicit values to multiple ranges in one call).

If you want to publish model output to a brand-new Google Sheet, pass target.kind="new_spreadsheet" in the spec instead of source_name. Bridge Town creates the Sheet in your Drive, registers it as a project data source, and writes the output — all in one call. No additional Google prompt is required if you already have an active Google connection.

{
"name": "write_gsheet",
"arguments": {
"project_name": "revenue-model",
"spec": {
"mode": "replace",
"run_id": "uuid-from-run",
"output_name": "forecast.json",
"cell_range": "Forecast!A1",
"target": {
"kind": "new_spreadsheet",
"source_name": "q2_forecast_board",
"title": "Q2 Forecast Board",
"initial_tabs": ["Forecast", "Assumptions", "Variance"]
}
}
}
}

The response includes the new sheet’s spreadsheet_id, source_name, and URL. Subsequent calls can reference the same sheet by source_name.

After writing data, apply an opinionated formatting preset with format_gsheet. This auto-detects the data bounds and applies header styling, borders, and (for variance reports) conditional colouring in a single call.

{
"name": "format_gsheet",
"arguments": {
"project_name": "revenue-model",
"preset": "financial_table",
"source_name": "revenue_model_actuals",
"tab_name": "Forecast"
}
}

Available presets: financial_table (general tables), kpi_dashboard (two-column key/value), variance_report (actuals vs budget with red/green variance), audit_log (append/journal tabs with timestamps and alternating row bands). Call format_gsheet(spec={"kind":"list_presets"}) to see all presets and their parameters.

If you’re in Claude.ai, you can ask Claude to walk you through the entire connection process using the built-in connect_google_sheets skill:

“Help me connect my Google Sheet to Bridge Town and set up a model.”

Claude will check whether the sheet is connected, discover the source_name via list_data_sources, run the import using ingest_data_source, verify the data, and suggest next steps — all in one conversation.

To keep your snapshots current without manual intervention, set a refresh interval when connecting:

"schedule_interval_minutes": 1440

Common values: 60 (hourly), 1440 (daily), 10080 (weekly). To change the schedule on an existing connection, call ingest_data_source again with the same source_name and the new interval — this updates the stored schedule without re-importing.

  • drive.file scope only — Bridge Town can only access Sheets you explicitly selected through Picker or that Bridge Town created for you. It cannot browse or access other spreadsheets in your Drive.
  • Encryption at rest — OAuth refresh tokens are encrypted with AES-256-GCM before storage. The encryption key is held in AWS Secrets Manager, not in the database.
  • No client exposure — refresh tokens are never returned in API responses or MCP tool output. They are decrypted in-memory only, within the MCP server process, for the duration of each API call.
  • Revocation — To disconnect a sheet, delete the data source in the web app under Data Sources. This removes the stored credentials immediately.
Guide / ToolDescription
Multi-Model PipelinesChain models with PIPELINE and /upstream transport — Google Sheets are for external I/O at the edges, not intra-run transport
ingest_data_sourceImport a connected sheet as a CSV snapshot (or upload a CSV/Excel file)
list_data_sourcesDiscover connected sheets and their source_name for write-back
write_gsheetWrite model output to a connected sheet or create a new Sheet as the write target
modify_gsheet_structureUnified structure tool (ensure tab, insert/delete rows)
format_gsheetUnified formatting tool (presets, borders, validation, etc.)
format_gsheet(spec={"kind":"list_presets"})Discover available formatting presets
query_dataQuery snapshots (uploaded files and linked sheets) with SQL
create_fileCreate a model file in the project
patch_fileApply targeted model edits from instructions
update_fileReplace model source with full updated code