Google Sheets Import & Export - No OAuth, API & AI Agents avatar

Google Sheets Import & Export - No OAuth, API & AI Agents

Pricing

from $2.00 / 1,000 sheet synceds

Go to Apify Store
Google Sheets Import & Export - No OAuth, API & AI Agents

Google Sheets Import & Export - No OAuth, API & AI Agents

Append, replace, upsert or read Google Sheets with a service account: no OAuth popup, works from the API, schedules and AI agents (MCP).

Pricing

from $2.00 / 1,000 sheet synceds

Rating

0.0

(0)

Developer

TRUONG VAN HOA

TRUONG VAN HOA

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

4 hours ago

Last modified

Share

Google Sheets Import & Export — no OAuth, works with the API & AI agents

Sync any data into Google Sheets, or export a tab out of it, using a Google service account — no interactive OAuth login, no popup that can fail or expire. That makes it work reliably from the Apify API, from Scheduled runs, from Integrations, and from AI agents through the Apify MCP server, none of which can click through a browser consent screen.

  • append — add rows below the existing data, mapping incoming keys onto existing columns by name.
  • replace — clear the tab and rewrite it (with an automatic backup of the old values).
  • upsert — update rows that match a key, insert the rest.
  • read — export a tab to the dataset as clean JSON.

Why a service account instead of "Login with Google"?

An OAuth login button only works when a human is present in a browser to click "Allow". It cannot run unattended on a schedule, cannot be called from the Apify API, and stops working the moment a token expires or a permission screen changes. A service account is a robot Google identity that you create once, in your own Google Cloud project: it authenticates with a signed key that never expires and never shows a popup, so this Actor works identically whether you start it by hand, on a schedule, through an Integration, or from an AI agent.

Setup: create a service account (5 minutes, one-time)

  1. Create a Google Cloud project — go to console.cloud.google.com, click the project dropdown (top bar) → New Project → give it a name → Create.
  2. Enable the Google Sheets API — with your project selected, go to APIs & Services → Library, search for "Google Sheets API", open it, click Enable.
  3. Create a service account — go to APIs & Services → Credentials → Create Credentials → Service account, give it a name (e.g. "sheets-sync"), click Create and Continue, then Done (no roles needed).
  4. Create a JSON key — open the service account you just created → tab Keys → Add Key → Create new key → type JSON → Create. A .json file downloads — open it and copy the whole content.
  5. Share the spreadsheet — open your Google Sheet → Share → paste the service account's client_email (looks like sheets-sync@your-project.iam.gserviceaccount.com, also visible inside the JSON key) → give it Editor access → Share.

Paste the full JSON file content into the Service account key input. That's it — no further authorization step, ever, for this key.

Modes

ModeBeforeAfter
appendTab has 100 rows, columns id, name, emailYour new rows are added below; a new key like phone becomes a new column on the right, existing rows get a blank phone cell
replaceTab has last week's exportTab is cleared and rewritten with this run's data; last week's values are saved as JSON to the key-value store record BACKUP
upsert (keyColumns: ["id"])Row with id=42 existsThat row's columns are updated in place (columns not present in the incoming item are left untouched); rows with unmatched ids are appended
readTab has dataEvery row becomes one dataset item, keyed by the header row

Input

FieldExampleNotes
serviceAccountKey(paste JSON)Secret input, encrypted by Apify, never logged
spreadsheet"https://docs.google.com/spreadsheets/d/1AbC.../edit#gid=0" or a bare IDAny ID length; a URL's gid selects a tab unless sheetName is set
sheetName"Leads"Default: first tab (or the URL's gid tab). Created automatically for write modes if missing
mode"append" | "replace" | "upsert" | "read"Default append
keyColumns["id"]Required for upsert
backupBeforeReplacetruereplace only, default true
datasetId"{{resource.defaultDatasetId}}"One of datasetId/rawData, write modes only
rawData[{"id":1,"name":"Ann"}]Array of objects, or array of arrays with a header row first
offset, limit0, 5000datasetId paging
fields["id", "address.city"]Keep only these columns, dotted paths reach into nested objects
omitFields["password"]Drop these columns
flattentrueNested objects → a.b.c columns; arrays of primitives joined with , ; arrays of objects → JSON string
deduplicateBy["email"]Drop incoming duplicates before writing, keep the last
valueInputOption"RAW" | "USER_ENTERED"USER_ENTERED lets Sheets parse dates/formulas like typing
allowFormulasfalseWith USER_ENTERED, values starting =, +, -, @ are escaped unless this is true (formula-injection guard)
readRange"Sheet1!A1:F200"read only
maxItems5000read only
dryRunfalseValidate + compute the plan without touching the sheet; not charged

Example: append a scraper's output

Chain after any Actor via Integrations, setting datasetId to {{resource.defaultDatasetId}}:

{
"serviceAccountKey": "{{secrets.GOOGLE_SA_KEY}}",
"spreadsheet": "1AbCDefGhIjKlmNoPQRstuVWxyz0123456789ABCDEfg",
"mode": "append",
"datasetId": "{{resource.defaultDatasetId}}"
}

Example: upsert from an API call

curl "https://api.apify.com/v2/acts/YOUR_USERNAME~google-sheets-sync/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"serviceAccountKey": "...",
"spreadsheet": "1AbCDefGhIjKlmNoPQRstuVWxyz0123456789ABCDEfg",
"mode": "upsert",
"keyColumns": ["order_id"],
"rawData": [{"order_id": "A1002", "status": "shipped"}]
}'

Example: from an AI agent (Apify MCP)

An agent that already has data in hand (no dataset to point to) can pass it directly as rawData:

{ "spreadsheet": "1AbC...", "mode": "append", "rawData": [{"task": "Follow up", "done": false}] }

Output

OUTPUT (key-value store record):

{
"mode": "upsert",
"spreadsheetId": "1AbCDefGhIjKlmNoPQRstuVWxyz0123456789ABCDEfg",
"spreadsheetUrl": "https://docs.google.com/spreadsheets/d/1AbCDefGhIjKlmNoPQRstuVWxyz0123456789ABCDEfg",
"sheetName": "Leads",
"rowsRead": 0,
"rowsAppended": 3,
"rowsUpdated": 12,
"rowsSkippedDuplicate": 1,
"newColumns": ["phone"],
"totalCellsAfter": 4200,
"warnings": [],
"dryRun": false
}

For mode: "read", the exported rows are pushed to the dataset (one row = one item). For write modes, one summary item matching OUTPUT is also pushed to the dataset, so calling run-sync-get-dataset-items returns the result directly.

Pricing

Pay per event, charged only once the sheet write/read actually succeeds — a failed run costs nothing:

EventPriceWhen
sheet-sync$0.002Once per successful run
rows-1000$0.005Per started block of 1,000 rows written or read

Examples: a daily sync of 500 rows costs $0.007 per run, about $0.21 a month. An hourly sync of 500 rows is about $5 a month. A one-off import of 50,000 rows costs $0.252.

If a run would exceed Max total charge, it writes only the rows it can afford and says so in warnings — it never leaves your spreadsheet half-written past the point your budget allows further charges.

FAQ

Is my key safe? serviceAccountKey is an Apify secret input: encrypted at rest, never shown in logs, and used only in memory for the duration of the run. Nothing is stored by this Actor. Revoke the key any time from Google Cloud Console → your service account → Keys, with zero code changes needed here.

What stops someone injecting a formula into my sheet through the data? With the default valueInputOption: "RAW", Sheets never interprets cell content as a formula. If you opt into USER_ENTERED (to get automatic date/number parsing), any incoming string starting with =, +, - or @ is automatically prefixed with an apostrophe so it is stored as text, not evaluated — unless you explicitly set allowFormulas: true.

What are the limits? Google Sheets caps a spreadsheet at 10,000,000 cells total (across every tab) and a cell at 50,000 characters; this Actor checks the cell limit before writing and fails with the exact row count that would fit, and truncates any single oversized cell with a warning rather than a silent data-loss error. Sheets' write quota is 60 requests/minute/user; this Actor paces itself under that automatically and retries 429/5xx responses with backoff.

Can I use any spreadsheet ID length? Yes — this Actor accepts an ID of any length, or a full Sheets URL (the ID and gid are parsed out for you).

Is this affiliated with Google? No. This is an independent tool that uses the official public Google Sheets API with your own service-account credentials in your own Google Cloud project.

Something wrong or missing? Open an issue on the Actor's Issues tab.