Write any Apify dataset, pasted JSON or CSV/Excel file to a Google Sheet (append, append only new rows, update by key, replace), or read a sheet into a dataset. Runs after your scraper as an integration. Your own Google service account: no OAuth app to get blocked.
Versions follow MAJOR.MINOR.PATCH (src/version.py); Apify shows MAJOR.MINOR from .actor/actor.json.
Every run logs its version and records it in the RUN_STATS key-value record.
0.1.1 (2026-11-04)
Integrations: set Rows to write: Apify dataset to {{resource.defaultDatasetId}}. The README and field help said
to leave it empty, but Apify gives a limited-permissions run access only to the dataset named there. A run refused
access now names the fix in its status.
No change to output fields or price.
0.1.0 (unreleased)
First release.
Read: a Google Sheet's rows become dataset items keyed by the header row (headerRow for a table under a title).
Without a key, from the sheet's own CSV/Excel export (sheets shared as "Anyone with the link" or published to the
web); with a service account key, through the Sheets API v4 (private sheets, formatted or unformatted values).
Write: append, appendNew (skip keys already in the sheet), upsert (update by key, add the rest) and replace
(overwrite in place, then clear what's left; an empty source leaves the sheet untouched), from an Apify dataset,
an integration's dataset, pasted rows or a CSV/JSON/JSONL/Excel file URL. The header row is kept and new fields
become new columns; nested data flattens to a.b columns; a missing tab is created; the grid grows before wide
writes; Google's 10-million-cell limit is checked before writing.
Values are written RAW by default, so scraped text is never run as a formula; userEntered on request.
Auth: the user's own Google Cloud service account key (secret input), RS256-signed token request to Google's fixed
token endpoint; nothing of ours. Google's refusals become instructions (share with the account's email, enable
the Sheets API at the link Google gives, wrong key type).
Appends aren't retried after an unconfirmed answer (a 5xx or a lost connection), only after a 429; fixed-range
writes are idempotent and retried.
Charged per row: row-written per row added or updated, apify-default-dataset-item per row read (and the write
summary row). maxRows and the max cost per run stop the run cleanly.
Sources checked 2026-10-14: the Sheets API v4 is Google's public API for this use
(https://developers.google.com/sheets/api ); sheets.googleapis.com answers robots.txt with 4xx (allow all);
docs.google.com's robots.txt allows /spreadsheet (the export path).