Google Sheets Sync: Import, Export & Upsert Datasets avatar

Google Sheets Sync: Import, Export & Upsert Datasets

Pricing

from $0.08 / 1,000 row writtens

Go to Apify Store
Google Sheets Sync: Import, Export & Upsert Datasets

Google Sheets Sync: Import, Export & Upsert Datasets

Export any Apify dataset or actor run to Google Sheets, or import a sheet into a dataset: append, replace, upsert by key or mirror sync, retried through Google's rate limits. Runs after any actor as an integration. Share the sheet once; no Google sign-in. $0.10 per 1,000 rows.

Pricing

from $0.08 / 1,000 row writtens

Rating

0.0

(0)

Developer

CleanPull

CleanPull

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Features

Limited permissions

Share

This Google Sheets sync sends any Apify dataset to Google Sheets, or reads a sheet into a dataset, in every way you need it: append, replace, upsert by key (update rows in place, add new ones), or mirror sync (also remove rows that are gone). Runs wait out Google's rate limits instead of failing, read datasets of any size page by page, and write 30,000 rows in under 10 seconds. Share the spreadsheet once with our address; no Google sign-in, nothing expires. Run it after any actor as an integration, on a schedule or through the API.

How to export a dataset to Google Sheets

  1. Share your spreadsheet with our service account as Editor, once (see Set up in 30 seconds below).
  2. Open Google Sheets Sync on Apify and paste the spreadsheet's URL into Spreadsheet; name a Tab (created if missing).
  3. Choose the data: a Dataset id, a Run, an Actor (its last successful run), a Task (its last successful run), a URL (JSON or CSV) or Raw data.
  4. Pick a Mode: append, replace, upsert or sync. For upsert and sync, list the Key fields (upsert, sync, incremental) that identify a row, such as sku or url.
  5. Start the run. Open the Sheets written view to read each Sheet, Tab, Mode and the rows Added, Updated, Removed and Unchanged. To keep the sheet updated, add Google Sheets Sync as an integration on the actor or task whose results you want (see Sheets export after any actor below).
Google Sheets sync input: spreadsheet, tab, mode upsert, key fields sku, dataset

What the Google Sheets sync gives you

  • "Put every run's results in my sheet." Run it after any actor through Apify integrations; the finished run's dataset is written automatically.
  • "Keep one row per product and update its price." Upsert by sku: changed cells are updated in place, new products added, nothing duplicated. Columns you added by hand are left alone.
  • "Mirror this dataset exactly." Sync adds, updates, and deletes, moves or marks rows that are gone.
  • "A new tab every day," or "one tab per country."
  • "Use my sheet as the input of another actor." Read mode turns a tab into a dataset with typed numbers, booleans and dates.
  • "Only send rows I haven't sent before."

Google Sheets setup

Set up in 30 seconds

  1. Open your spreadsheet → Share → add cleanpull-sheets-1@cleanpull-sheets.iam.gserviceaccount.com as Editor (untick "Notify people").
  2. Paste the spreadsheet's URL into Spreadsheet and choose what to write.

The first run links the spreadsheet to your Apify account with a small hidden tab (_cleanpull, holding only your Apify user id). Runs from other Apify accounts are then refused, so your spreadsheet's URL alone is never enough to write to it.

For heavy use, also share with cleanpull-sheets-2@… and cleanpull-sheets-3@… (same domain) to triple the throughput. Prefer your own credentials? Paste your own service account key, or OAuth client and refresh token, in the optional fields; nothing is then shared with us.

Sync modes

ModeWhat it does
appendAdds rows below the existing data; new fields become new columns at the end
replaceClears the tab and writes the data
upsertMatches rows by keyFields; updates only the cells that changed, adds new keys
syncUpsert, and rows whose key is gone are deleted, moved to a removed tab, or marked with removedAt
readThe tab's rows into the dataset (and the OUTPUT record); header row → field names, values typed
modifyCleans up the tab's own rows (dedupe, columns) in place; backs the tab up first, never clears a tab it can't fully rewrite
backup / restoreSaves a tab's values and formulas to the actor's store; restores them by key
clearEmpties the tab

Google Sheets sync input

FieldKeyWhat it does
SpreadsheetspreadsheetThe sheet URL or id; a URL with #gid= targets that tab. Empty: a free preview of the rows a run would write
TabtabTab name, created if missing; {date}, {datetime}, {runId}, {value} placeholders
ModemodeSee Sync modes (append by default)
Key fields (upsert, sync, incremental)keyFieldsField(s) that identify a row, such as sku or url; needed for upsert and sync
Rows that are gone (sync)onRemovedDelete (the default), move to a removed tab, or mark with removedAt
Dataset, Run, Actor (its last successful run), Task (its last successful run), URL (JSON or CSV), Raw data, Key-value recorddatasetId, runId, actorId, taskId, url, rawData, keyValueRecordThe data: a dataset, a run, an actor's or task's last successful run, a JSON or CSV URL, rows in the input, or a stored record
More targetstargetsSeveral spreadsheet / tab / mode sets in one run
Split into tabs by fieldsplitByFieldOne tab per value of a field
Only rows not sent before, Remove duplicates, Maximum items, Skip itemsincremental, dedupe, limit, offsetOnly rows not sent before; remove duplicates; how many
ColumnscolumnsChoose, order and rename columns (price: Price (USD))
Columns firstcolumnsOrderFields to put first, in this order, when the actor creates the header; every other field follows
Nested fields as columns, Nested field separator, Lists, List separatorflatten, flattenSeparator, arrays, arraySeparatorNested fields as columns (joined with "." by default); lists joined or kept as JSON
Add a syncedAt columnaddSyncedAtA timestamp column with the run's time
Values, Formula columnsvalueInput, formulaColumnsStore values as given, or let Google type them (with formula columns for =IMAGE() and =HYPERLINK())
Freeze the header row, Bold header, Fit column widthsfreezeHeader, boldHeader, autoResizeFormatting, on by default
Back up before replacing or syncing, Backup to restorecreateBackup, backupKeyBack up before replace or sync; restore a backup
Header row (read), Public sheet (read without sharing)headerRow, publicSheetRead: the header row; read a published sheet without sharing
Your service account key (optional), OAuth client id (optional), OAuth client secret, OAuth refresh tokenserviceAccountJson, oauthClientId, oauthClientSecret, oauthRefreshTokenOptional: your own Google credentials
History storestateStoreNameOptional. A key-value store in your account where the actor keeps the rows already written (for Only rows not sent before) and its backups. Empty: its own store, "cleanpull-sheets-sync". Pick one when you run it with a scoped API token

Example inputs

Upsert a dataset of products into the Products tab by sku:

{
"spreadsheet": "https://docs.google.com/spreadsheets/d/1AbC…/edit",
"tab": "Products",
"mode": "upsert",
"keyFields": ["sku"],
"datasetId": "aBcD1234eFgH5678"
}

Read a tab into a dataset:

{
"spreadsheet": "https://docs.google.com/spreadsheets/d/1AbC…/edit",
"tab": "Suppliers",
"mode": "read"
}

Sheets export after any actor

In the actor or task whose results you want in Sheets: Integrations → Connect Actor or Task → Google Sheets Sync, with this input:

{
"spreadsheet": "https://docs.google.com/spreadsheets/d/…/edit",
"datasetId": "{{resource.defaultDatasetId}}",
"mode": "upsert",
"keyFields": ["url"]
}

Every time that actor finishes, its results land in your sheet.

Existing Sheets inputs

Inputs, tasks and integrations you already use for Sheets imports keep working: paste the same input and run.

  • Keys it understands:
    • spreadsheetId, datasetId, rawData (objects, or a table with the header row first), limit, offset;
    • deduplicateByField, deduplicateByEquality, columnsOrder, range (its tab is used), createBackup, publicSpreadsheet;
    • the modes append, replace, modify, read and load backup (restores the latest backup of the tab).
  • Your sheets keep their layout: with those inputs, nested fields keep hobbies/0 style column names, and read also saves the rows as the OUTPUT record.
  • No Google sign-in: share the spreadsheet with this actor's address as Editor, once. There are no tokens to expire and nothing to reconnect.
  • Good to know:
    • transformFunction is not run, because custom code is not executed. Use dedupe, columns, columnsOrder and limit instead.
    • Dedupe removes duplicates among the rows being sent. To skip rows already in the sheet, use upsert with keyFields.
    • Rows always start at the tab's first column and row.
    • columnsOrder applies when the header is created; an existing header keeps its order.

Google Sheets sync output

Google Sheets sync output: Sheets written view with sheet, tab, mode, rows added, updated, removed and unchanged, columns

One record per spreadsheet target, in the Sheets written view. In read mode, the dataset holds the sheet's rows. RUN_SUMMARY in the key-value store gives the outcome (COMPLETE, PARTIAL, EMPTY, PREVIEW, FAILED), rows written and read, requests, retries after rate limits, and charges.

Example rows

Illustrative: the target row of the first example input above, for a dataset of 1,200 products of which 250 changed and 200 were new:

{
"recordType": "target",
"url": "https://docs.google.com/spreadsheets/d/…/edit#gid=123",
"tab": "Products",
"mode": "upsert",
"appended": 200,
"updated": 250,
"removed": 0,
"unchanged": 750,
"columns": 7,
"warnings": []
}

A target that could not be written has its reason in error and its kind in errorKind; a backup's key is in backupKey.

Rows and billing

RowBilled
target (one per spreadsheet target)Not per row: the rows it added, updated or removed are
Read mode: a sheet row in the datasetOne row read
preview: true (no spreadsheet)Free
unreadable (a missing source, with why)Free

Google Sheets sync reliability

Measured on a live spreadsheet:

RunResult
Append 30,000 rows × 8 columns8.7 s, 12 requests
Upsert 1,200 rows (250 changed, 200 new)5.6 s; 750 unchanged rows untouched and free
Sync with mark (29,000 rows gone)10.2 s
Read 30,200 rows back1.0 s
90 writes at once against Google's per-minute limitAll 90 succeed: the run waits and retries

How:

  • Few large writes (about 1.5 MB each, under Google's recommended 2 MB), paced under Google's per-minute limit.
  • Retries with exponential backoff that honour Google's Retry-After. A write that is not safe to repeat is never retried blind: after a server error, an append is checked against the sheet before anything is sent again, so rows are never doubled, and a row deletion stops the sync (which is safe to run again).
  • Datasets read in pages, so any size works.
  • Progress kept per tab across platform restarts, so a resumed run continues where it stopped.
  • Access checked before writing, with the exact address to share with.
  • Scraped text that looks like a formula stays text.
  • Cells over Google's 50,000-character limit are cut and counted.

Pricing

EventFree and BronzeSilverGold
Row written (added, updated or removed)$0.10$0.09$0.08
Row read (read mode)$0.05$0.045$0.04

Per 1,000 rows. Unchanged rows in upsert and sync are free; modify rewrites, and is charged for, every row it keeps. backup, restore and clear write no billed rows. Each run also has a $0.00005 start fee. A daily sync of 2,000 rows costs $0.20 on the Free and Bronze plans for its first run, which writes every row; after that, only the rows added, updated or removed are charged: a day with 100 changed rows costs $0.01, about $0.30 a month.

Limits

  • Google's cell limit counts the whole spreadsheet. When it is reached, the run fills the sheet to the limit, stops cleanly and says so. Write the rest to a new spreadsheet (another target), or use replace or sync so the sheet keeps its size.
  • Our service accounts cannot create new spreadsheets (Google gives service accounts no storage): create the sheet, then share it.
  • Upsert and sync read the tab once to compare, so very large tabs (over about 500,000 rows) take longer.
  • Formatting is limited to the header row and column widths; number formats come from Google when values are typed.
  • "Only rows not sent before" works with append (upsert already skips unchanged rows, for free). Sync takes the whole dataset: no limit or skip, since rows left out would be removed.
  • Rows without a key value are skipped in upsert and sync (they cannot be matched); rows in the sheet without a key are left as they are.
  • The spending limit is respected before each write: a run that reaches it writes what fits, is charged for exactly that, and stops.
  • Try it without a spreadsheet (preview): a run with no spreadsheet writes nothing and charges nothing: the dataset shows the rows it would write (up to 100, marked preview: true), from your data or, with nothing filled in, four example rows. Add your spreadsheet's URL to write them. Your data is only ever written to the spreadsheet you name.
  • Nothing found: when the data or the sheet is not there (a missing run or record, a sheet not shared with us, a missing tab or backup), the run still succeeds and says why: a free recordType: "unreadable" row for a missing source, or the target row's error and errorKind; nothing is charged. The run fails only when every target ended with an error, nothing was written or read, and at least one error is not one of these misses (an unexpected error from Google). When only some targets end with an error, the outcome is PARTIAL and the run succeeds. A run near its time limit stops starting targets and ends with what it wrote.

FAQ

How much does it cost to export a dataset to Google Sheets?

$0.0001 per row written on the Free and Bronze plans: 1,000 rows are $0.10, 30,000 rows $3. In upsert and sync, only rows added, updated or removed are charged, so a daily sync of 2,000 rows costs $0.20 on its first run and then $0.01 on a day with 100 changed rows. Reading a sheet into a dataset is $0.00005 per row. A preview (no spreadsheet), backup, restore and clear write no billed rows; each run also has the $0.00005 start fee, and higher Apify plans pay less (see Pricing above).

How often should I sync a dataset to Google Sheets?

As often as the data changes: add it as an integration on the actor or task, so every finished run is written (see Sheets export after any actor above). With upsert or sync, a run where nothing changed writes nothing and costs only the start fee; with append, turn on Only rows not sent before so repeated rows are skipped.

What is the difference between append, upsert and sync?

Append adds every row below the existing data. Upsert matches rows by Key fields (upsert, sync, incremental), updates only the cells that changed and adds new keys, so each product has one row. Sync is upsert plus rows that are gone: Rows that are gone (sync) deletes them, moves them to a removed tab or marks them with removedAt. Replace clears the tab and writes the data.

Why are some rows not in my sheet?

  • No key: rows without a key value are skipped in upsert and sync.
  • Sent before: with Only rows not sent before, rows already written to the tab are skipped.
  • Duplicates or limits: Remove duplicates, Maximum items and Skip items leave rows out on purpose.
  • Cell limit: Google's cell limit counts the whole spreadsheet; the run fills it to the limit and says so.
  • Spending limit: the run writes what fits and stops, with a warning on the target row.
  • Not shared or no spreadsheet: a sheet not shared with our address has the reason in the target row's error; with no Spreadsheet, the run only previews.

Do I need to sign in to Google?

No. Share the spreadsheet once with cleanpull-sheets-1@cleanpull-sheets.iam.gserviceaccount.com as Editor; there are no tokens to expire. The first run links the sheet to your Apify account through a hidden _cleanpull tab, so runs from other accounts are refused. To use your own Google account instead, fill Your service account key (optional) or the OAuth fields; they are secret inputs.

Can I use Google Sheets sync through the API?

Yes. Start runs through the Apify API or an API client with the same input as the form; inputs that use spreadsheetId and the related keys work unchanged. Read the Sheets written view, the sheet's rows (read mode, also in the OUTPUT record) or RUN_SUMMARY with the outcome, rows written and read, retries and charges.

Does it work with Make, Zapier or Claude?

Yes. It runs after any Apify actor or task as an integration, and Make, Zapier and n8n can start it through Apify's connectors. From Claude, the MarketMage plugin sends the results of a run or a watchlist to a Google Sheet in a chat: append, replace, or keep a sheet in sync by a key such as SKU or URL.

Is my spreadsheet data safe?

The actor writes only to the spreadsheet and tabs you name, and a run with no spreadsheet writes nothing. A shared sheet is linked to your Apify account, so its URL alone is never enough for another account to write to it. Your own service account key and OAuth fields are secret inputs. How you use the data, and following the laws and terms that apply to you, is your responsibility. This is not legal advice.

Other CleanPull actors for monitoring:

  • Alerts Sender: send results to email, Slack, Discord, Teams or a webhook.
  • Watch Digest: one scheduled digest of price, stock, rank and review changes.
  • Shopify Scraper: every product and variant from any Shopify store, with stock and sales estimates.

Use it from Claude

The MarketMage plugin runs these actors from a Claude chat.

Found it useful? A rating on the Store helps others find it.

Changelog

  • 0.1.x, reliability (2026-10-24): no spreadsheet means a free preview of the rows a run would write (the empty-input example is now previewed too, no longer written to the demo spreadsheet); a missing source, an unshared sheet or a missing tab ends SUCCEEDED with the reason instead of FAILED; runs stop starting targets before their time limit. Prices unchanged.
  • 0.1.7 (October 2026): existing Sheets inputs work unchanged (spreadsheetId and related keys, more modes, table-format raw data, hobbies/0 columns, OUTPUT on read); new modify mode, columnsOrder and flattenSeparator.
  • 0.1.6 (October 2026): an empty input runs an example on the demo spreadsheet instead of failing.
  • 0.1 (October 2026): append, replace, upsert, sync, read, backup, restore and clear; datasets of any size; integration payloads; several targets; tabs per field value and per date; only-new rows; pacing, retries and resume; service-account sharing with per-user linking; your own service account or OAuth.