📗 Google Sheets Import & Export — Read Public Sheets, No OAuth
Pricing
from $1.00 / 1,000 row writtens
📗 Google Sheets Import & Export — Read Public Sheets, No OAuth
Read any link-shared Google Sheet with ZERO setup — no API key, no OAuth, no Google Cloud project. Add a service account key to write: append, replace or upsert with deduplication, straight from any Apify dataset. Built for scheduled syncs that must not break. $1 per 1,000 rows.
Pricing
from $1.00 / 1,000 row writtens
Rating
0.0
(0)
Developer
David González
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Google Sheets to Apify and Back — Read Public Sheets With Zero Setup, No OAuth
The reliable Apify to Google Sheets integration. This Actor moves data both ways between Apify and Google Sheets: read a sheet into a dataset, or push any Actor's results into a spreadsheet — appending, replacing, or upserting with deduplication.
Reading a sheet needs no credentials at all. If the spreadsheet is shared as "Anyone with the link", paste the URL and run — no Google Cloud project, no API key, no consent screen. For private sheets and for every write, it authenticates with a Google Cloud service account instead of OAuth, so there is no access token that silently expires and kills your scheduled runs. You pay per row actually delivered, and failed runs charge no row events at all.
Unofficial — this Actor is not affiliated with or endorsed by Google. Google Sheets™ is a trademark of Google LLC.
Why use this Google Sheets integration?
- ⚡ Zero setup for public sheets. Leave the key field empty and it reads any link-shared spreadsheet immediately — no Google Cloud project, no API key, no consent screen. Ideal for public datasets, shared price lists, community trackers, and one-off imports.
- 🔐 No OAuth, ever. OAuth tokens expire, refresh flows break, and your 3 a.m. scheduled sync starts failing until a human clicks "re-authorize". A service account key does not expire on its own: paste it once, share the sheet with its email, forget it.
- 🛡️ Built for scheduled runs that must not fail. Bad inputs fail fast before touching Google, connection is verified before anything is charged, and large jobs are batched to stay well under Google's rate limits.
- 💬 Errors that tell you what to do. Every failure prints a machine-readable code plus numbered fix steps — a 403 quotes the exact email address you need to share the spreadsheet with. No cryptic stack traces.
- 🧪 Dry run mode. Validate credentials, access, and tab, and see exactly what would happen — without writing a single cell and without paying per-row events.
Use cases
- Apify scraper users — you already run a scraper on Apify and your team lives in spreadsheets. Point
datasetIdat any run's dataset and its results land in Google Sheets, on a schedule if you want. Works with every Actor in the Store. - Automation builders — keep a master sheet in sync with
upsert+ a deduplication key: matching rows get updated in place, new rows get appended, and re-running never creates duplicates. Idempotent by design. - AI agents — give an agent a stable, structured read/write interface to spreadsheets, with machine-readable error codes it can act on and a dry-run mode for safe probing.
Sample output
Read mode — one dataset item per sheet row (row 1 is the header):
{"rowNumber": 2,"email": "ada@example.com","name": "Ada Lovelace","score": 42}
Write modes — one summary item per run:
{"mode": "upsert","sheetName": "Customers","dryRun": false,"rowsWritten": 25,"rowsUpdated": 18,"rowsAppended": 7,"headerCreated": false,"newColumns": "last_seen","finishedAt": "2026-08-07T15:20:11.000Z"}
You can download the dataset in JSON, CSV, Excel, or HTML.
Input
To read a publicly shared sheet, one field is enough:
{"mode": "read","spreadsheetId": "https://docs.google.com/spreadsheets/d/1BxiMVs0.../edit"}
To write (or to read a private sheet), add the key:
{"mode": "upsert","spreadsheetId": "https://docs.google.com/spreadsheets/d/1BxiMVs0.../edit","serviceAccountJson": "…full content of your JSON key file…","deduplicationKey": "email","datasetId": "nWFncsBooi3djDanM"}
| Field | Type | Required | Description |
|---|---|---|---|
spreadsheetId | string | yes | Spreadsheet ID or the full sheet URL copied from the browser. |
serviceAccountJson | string (secret) | writes only | Full content of the service account JSON key file. Stored encrypted by Apify. Leave empty to read a link-shared sheet. |
sheetName | string | no | Tab name (case-sensitive). Defaults to the first tab. |
mode | select | no | read (default), append, replace, or upsert. |
deduplicationKey | string | upsert only | Column that uniquely identifies a row, e.g. email. |
data | array | write modes | Inline rows: array of JSON objects, one per row. |
datasetId | string | write modes | Apify dataset whose items should be written (alternative to data — provide one, not both). |
dryRun | boolean | no | Validate credentials + access and report what would happen, without writing a cell. |
Setup
Public sheet (read): none. Open the spreadsheet → Share → General access → Anyone with the link → Viewer. Paste the URL, leave the key field empty, run.
Private sheet, or any write — one-time setup (~3 minutes)
- In Google Cloud Console, enable the Google Sheets API (APIs & Services → Library).
- Under IAM & Admin → Service accounts, create a service account and download a JSON key (Keys → Add key → JSON).
- Share your spreadsheet with the service account's email (the
client_emailvalue inside the JSON) — Editor for writing, Viewer for reading. Paste the JSON into the Actor's key field. Done.
Modes and data handling
- read — every data row becomes a flat JSON object in the run's dataset.
- append — adds rows after the last used row, reusing the existing header order; new columns are added at the end automatically.
- replace — clears the tab, then writes a fresh header and all rows.
- upsert — matches incoming rows by
deduplicationKey: matches are updated in place (cells you don't send are kept), the rest are appended.
Keys become column headers; nested objects flatten to dot-notation columns (user.city); arrays are stored as JSON strings; values are written raw, so a string like =SUM(A1) stays text — nothing is ever executed as a formula.
Pricing
| Event | Price | When it's charged |
|---|---|---|
| Task start | $0.005 | Once, only after the connection to your spreadsheet succeeds. |
| Row written | $0.001 / row | Only rows actually written (updated or appended). Header rows are free. |
| Row read | $0.001 / row | Only rows actually delivered to the dataset. |
1,000 rows ≈ $1. Failed runs charge no row events, and a dry run charges only the task start ($0.005). No subscription, no minimum.
FAQ
How do I export an Apify dataset to Google Sheets automatically?
Set mode to append or upsert, put the dataset ID from your scraper run into datasetId, and schedule this Actor to run after the scraper. Every run pushes the fresh results into your sheet.
Why does my Google Sheets integration keep failing with a 403 error?
The spreadsheet isn't shared with the service account. This Actor's SPREADSHEET_ACCESS_DENIED error quotes the exact email address to share it with — share once, and it works from then on.
Can I read a Google Sheet without any credentials?
Yes, as long as the sheet is shared as "Anyone with the link". Leave serviceAccountJson empty and the Actor downloads the tab straight from Google's public CSV endpoint. Nothing to configure, nothing to expire. Writing always needs the service account key — public link sharing never grants write access to anonymous callers.
Do Google service account keys expire like OAuth tokens?
No. OAuth access tokens expire and rely on refresh flows that can break; a service account JSON key keeps working until you revoke it. That's why this Actor uses service accounts only.
How do I sync data to Google Sheets without creating duplicates?
Use upsert mode with a deduplicationKey (e.g. email). Existing rows are updated in place, new rows are appended, and re-running the same sync never duplicates anything.
Is it safe to paste a service account key into Apify?
The field is marked secret, so Apify stores it encrypted and hides it in logs. The Actor never writes the key anywhere, and Apify's log library censors credentials.
Can I test the connection without touching my spreadsheet?
Yes — enable dryRun. It validates the key, the spreadsheet access, and the tab, then reports exactly what would happen without writing a single cell.
Limitations (honest ones)
- The first row of the tab is always treated as the header; there is no support for headerless sheets or headers on another row.
- Column matching is case-sensitive and exact —
Emailandemailare different columns. - Google's limits apply: 10 million cells per spreadsheet, 50,000 characters per cell, and ~300 API requests/min per project (large jobs are batched to stay well under this).
- Write sources are capped at 100,000 rows per run.
replaceclears values but keeps cell formatting; it does not delete extra tabs.- Credential-free reading works only on link-shared sheets, is read-only, caps at 25 MB per tab, and returns every cell as text (Google's CSV export carries no type information). Use the service account key if you need numbers typed as numbers.
- No OAuth login option — service account only. That is the point.
🤖 For AI Agents & MCP
This Actor is public on the Apify platform, so AI agents can invoke it through the Apify MCP server like any other tool: structured JSON input, structured JSON output, and machine-readable error codes (CREDENTIALS_REJECTED, SPREADSHEET_ACCESS_DENIED, SHEET_TAB_NOT_FOUND…) that an agent can parse and act on — including re-trying with corrected input. The dryRun flag lets an agent verify access safely before committing writes.
More actors by srd836
- YouTube Transcript Scraper — extract transcripts and subtitles from YouTube videos.
- Shopify Store Spy — AliExpress Price Match — analyze Shopify stores and match products to AliExpress prices.
- Naukri Jobs Scraper — extract job listings from Naukri.com.
Support
Found a bug or need a feature? Open the Issues tab of this Actor and include the error code from the log (e.g. CREDENTIALS_REJECTED). Every issue is read and answered, usually within a few days.
This Actor helps you export Apify dataset to Google Sheets automatically, set up an Apify to Google Sheets integration without OAuth, import Google Sheets data into Apify, sync scraper results to a spreadsheet on a schedule, upsert rows into Google Sheets without duplicates, and connect AI agents to Google Sheets using a service account instead of expiring OAuth tokens.