Google Sheets

Turn any Google Sheet into a typed REST endpoint. Public sheets and service-account-shared sheets both work.

Two ways to authenticate

The connector picks one path based on how you've shared the sheet. We do not silently fall back between paths — if the path you implicitly chose fails, the error tells you exactly what to fix.

Public sheet (recommended for read-only public data)

In Google Sheets: Share → General access → Anyone with the link → Viewer. We then read the published CSV. No auth headers needed; rate limits are Google's.

Service-account auth (recommended for private data)

Share the sheet with our service account email. The connect wizard shows the exact email — copy it, then in Google Sheets: Share → Add people → paste the email → Viewer. Authenticated reads give you faster fetches and access to sheets that aren't link-shared.

Configuring the source

The connect wizard asks for these fields:

  • spreadsheet_id or full URL — the connector parses the ID from the URL automatically.
  • tab — sheet/tab name. Defaults to the first tab if blank.
  • header_row — 0-indexed row that contains your column headers. Use 0 for the first row, 2 if you have a title row plus a blank row before headers.
  • start_row / end_row — restrict to a slice of rows. Optional.

Auto-detection guesses the header row by looking for the first row of mostly non-numeric strings. If your headers are off, override with header_row.

In the sheet's settings modal, this is the Header field: pick Header row and set the row number, or No header (A, B, C…) for sheets with no header row at all — every row is then treated as data and columns are named by their spreadsheet letter.

There's also a Row number column setting. It defaults to Don't include; switch it to Include as _row to add each record's 1-indexed row number as a real field in the response. Turning it on adds a key to every record, which changes the endpoint's ETag — off by default so existing consumers aren't affected until you opt in.

Sections and multi-tab sheets

For workbooks that mix multiple tables on one tab, use section_name + start_row/end_row to slice. For multi-tab sheets, create one source per tab — each becomes its own entity that you can join on the canvas.

Type inference

Per-column types are inferred from the values:

  • All values match true/false → boolean
  • All values parse as numbers (commas allowed) → number
  • All values match YYYY-MM-DD (or ISO datetime) → date
  • Otherwise → string

Mixed-type columns fall back to string. If a column has empty cells mid-data, the non-empty subset drives the type.

Common errors

If you see…Try this
Service-account auth failed; share the sheet with <sa-email>, or set general access to "Anyone with the link"The sheet isn't shared with our service account and isn't link-public. Pick one of the two auth paths above.
Couldn't detect any columns. Make sure the header row is selected correctlyThe header row index is pointing at a blank or merged-title row. Set header_row explicitly to the 0-indexed row that contains column names — or, in the settings modal, set Header to Header row and pick the row. If the sheet has no header row at all, switch Header to No header (A, B, C…) instead.
Tab 'Sheet1' not foundThe named tab doesn't exist. Open the sheet in Google Sheets and copy the exact tab name (case-sensitive, including spaces).
Spreadsheet not foundThe spreadsheet ID is wrong, or the sheet was deleted. Paste the full URL — the connector extracts the ID for you.

Sync cadence

Sheets resync on the schedule defined per source (default: every 60 minutes). Each sync writes a sync_logs entry with row counts and any errors — viewable from the source detail panel. Failed syncs surface a redacted error message.

Sample row

What the deployed endpoint returns for a 3-column sheet:

{
  "page": 1,
  "total": 842,
  "data": [
    { "email": "[email protected]", "name": "Ava Ramírez", "plan": "pro" },
    ...
  ]
}
See also: Getting started · REST API