Skip to content

Google Sheets

Read from and write to Google Sheets.

Before you use this connector, you need three things:

  1. A Google Cloud project with the Sheets API enabled.
  2. A service account with a JSON key file.
  3. The target spreadsheet shared with the service account’s email address.

Create a service account in the Google Cloud Console, download the JSON key file, and store its contents in an environment variable.

Terminal window
# Store the service account key
export GOOGLE_SERVICE_ACCOUNT_KEY="$(cat service-account.json)"

Then reference it in your node config:

auth:
type: service_account
credentials_env: GOOGLE_SERVICE_ACCOUNT_KEY

Share the spreadsheet with the service account email (it looks like name@project.iam.gserviceaccount.com). Give it Editor access if the pipeline writes to the sheet.

FieldRequiredDefaultDescription
spreadsheet_idYesGoogle Sheets document ID (from the URL).
sheet_nameYesTab name within the spreadsheet.
rangeNoEntire sheetCell range, e.g. A1:E100.
credentials_envYesEnvironment variable holding the service account JSON key.
write_modeWrite onlydedicateddedicated or shared.
key_columnShared modeColumn used for row matching in upserts.
owned_columnsShared modeColumns Radhflow may write to.

Pull a sheet into a Table. The first row is treated as column headers.

flow.yaml
read-leads:
type: source
op: sheets.read
params:
spreadsheet_id: 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms
sheet_name: Leads
range: A1:E100
credentials_env: GOOGLE_SERVICE_ACCOUNT_KEY
outputs:
leads:
type: Table
schema:
name: { type: string }
email: { type: string }
score: { type: number }

If you omit range, the entire sheet is read.

Push results back to a sheet. In dedicated mode (the default), Radhflow creates and owns a separate tab, clearing and rewriting it on each run. Other tabs are untouched.

write-scores:
type: deterministic
op: sheets.write
params:
spreadsheet_id: 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms
sheet_name: "RF: Scored Leads"
write_mode: dedicated
credentials_env: GOOGLE_SERVICE_ACCOUNT_KEY
inputs:
data: { type: Table, from: ref(score-leads.scored) }

The RF: prefix signals a machine-managed tab.

In shared mode, Radhflow writes to specific columns in an existing sheet. Human-managed columns are preserved. Rows are matched by a key column for upsert.

write-enriched:
type: deterministic
op: sheets.write
params:
spreadsheet_id: 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms
sheet_name: Leads
write_mode: shared
key_column: email
owned_columns: [score, enriched_company, enriched_title]
credentials_env: GOOGLE_SERVICE_ACCOUNT_KEY
inputs:
data: { type: Table, from: ref(enrich.results) }

Only owned_columns are written. Notes, tags, and status fields that humans added stay intact.

Permission denied (403). The service account email doesn’t have access to the spreadsheet. Open the spreadsheet’s sharing settings and add the service account email with Editor permissions.

Rate limits (429). Google Sheets API allows 300 requests per minute per project. If you’re reading or writing many sheets in a single pipeline, add retry configuration or split the workload across runs.

Empty sheet. If the sheet has no data, the read node produces an empty Table (zero rows, headers from the first row if present). Downstream nodes that expect data should handle this case. Use a conditional node or set a minimum row count check.