Google Sheets Export & Import avatar

Google Sheets Export & Import

Pricing

from $0.10 / 1,000 row writtens

Go to Apify Store
Google Sheets Export & Import

Google Sheets Export & Import

Send any Apify dataset or JSON to a Google Sheet (append, append only new rows with dedupe, or replace with backup), or import a sheet tab into a dataset. Public sheets import with no credentials. Works as an integration after any scraper.

Pricing

from $0.10 / 1,000 row writtens

Rating

0.0

(0)

Developer

Brandon Ob

Brandon Ob

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Google Sheets Export & Import: Apify dataset ↔ Google Sheets (append, dedupe, replace, import)

Send any Apify dataset or JSON to a Google Sheet. Add it as an integration after your scraper and every finished run lands in your spreadsheet automatically. Three write modes:

  • Append: add all rows below the existing data.
  • Append only new rows (dedupe): skip rows whose key columns (e.g. url, id) are already in the sheet. Perfect for scheduled scrapers that return the same items every day.
  • Replace: overwrite the tab, after saving a backup of the old contents.

It also works the other way: Import reads a sheet tab into a dataset, so a Google Sheet can feed URLs, keywords or product lists into any scraper. Public sheets import with no credentials at all.

Columns are created for you: nested objects become price.value-style columns, lists are joined into one cell, and new fields are added as new columns at the end without disturbing the ones you already have.

Who it's for

  • Anyone running a scraper on a schedule who wants the results in a Google Sheet, not a CSV download.
  • Lead generation and sales teams: scrape leads daily and keep one growing, duplicate-free sheet that a VA or CRM import can work from.
  • Price and SEO monitoring: replace a "latest" tab on every run, or append a dated history.
  • No-code builders: Sheets is the easiest place to hand data to Looker Studio, Zapier, Make, n8n or a client.

Import a Google Sheet into a dataset

  1. Set Operation to Import.
  2. Paste the sheet URL. Copy it from the tab you want, so it ends in #gid=....
  3. If the sheet is shared as Anyone with the link: Viewer, run it. No Google setup is needed. For a private sheet, add a service account key (steps below) and share the sheet with it (Viewer is enough to import).

Row 1 becomes the field names (change Header row if your headers are lower down). Every row below becomes one dataset item. Empty rows are skipped. Blank or repeated headers get safe names (column_3, name_2). Turn on Nest dot-path columns to rebuild nested objects from columns like price.value, the reverse of what Export does. Public sheets are read through Google's CSV export, so plain numbers come back as numbers and everything else as text. The Sheets API path keeps Google's own types and shows dates as formatted text.

Example input:

{
"operation": "import",
"spreadsheet": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit#gid=0"
}

Feed the dataset into another Actor with its Dataset ID input, or call this Actor from your own code and read the rows over the API.

How to use (export)

1. Create a Google service account (one time, about 5 minutes)

A service account is a robot Google account. You give it access to one sheet, and only that sheet.

  1. Open Google Cloud Console, create a project (any name), and enable the Google Sheets API for it.
  2. Go to IAM & Admin > Service Accounts > Create service account. Any name works. Skip the optional role steps.
  3. Open the new service account, go to Keys > Add key > Create new key > JSON. A .json file downloads.
  4. Open the file in a text editor, copy all of it, and paste it into Service account JSON in this Actor. It is stored encrypted.
  5. Copy the client_email from the file (it looks like name@project.iam.gserviceaccount.com).

2. Share your sheet with the service account

Open your Google Sheet, click Share, paste the client_email, choose Editor, and untick "Notify people". Viewer or Commenter access is not enough. If you forget this step, the run fails with a message telling you exactly which email to share with.

3. Run it

  1. Paste the Google Sheet URL (or ID).
  2. Optional: a Sheet (tab) name. A missing tab is created for you.
  3. Pick the source: a Dataset ID, or paste JSON data.
  4. Pick a write mode. For append-new-only, set Key columns (e.g. url).

Use it as an integration after another Actor

  1. Open your scraper (any Actor or task) and go to the Integrations tab.
  2. Add Google Sheets Export as an Actor integration, triggered on Run succeeded.
  3. In its input, fill in the sheet URL, service account JSON, tab and mode. Leave Dataset ID empty (or set it to {{resource.defaultDatasetId}}): the finished run's dataset is exported automatically.

Now every scheduled run of your scraper updates the sheet. Use Append only new rows so re-scraped items are not added twice.

Example input

{
"spreadsheet": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit",
"sheetName": "Leads",
"datasetId": "Hk8sX2vqP4aZr1wTn",
"mode": "append-new-only",
"keyColumns": ["url"],
"excludeColumns": ["html"]
}

Example output

A summary row in the dataset and an OUTPUT record in the key-value store:

{
"sheetUrl": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit#gid=184019232",
"sheetName": "Leads",
"mode": "append-new-only",
"rowsInSource": 1250,
"rowsWritten": 312,
"rowsSkippedDuplicates": 936,
"rowsSkippedEmptyKey": 2,
"newColumnsAdded": ["company.linkedinUrl"],
"totalColumns": 18,
"tabCreated": false,
"firstRowWritten": 4821,
"lastRowWritten": 5132,
"backupKey": null,
"chargeLimitReached": false
}

How rows and columns are written

  • Row 1 is the header. The first run writes it; later runs match fields to it by name.
  • Automatic columns: every field in the data, in first-seen order. {"price": {"value": 9}} becomes a price.value column. ["a", "b"] becomes a, b (change the separator in Array separator). Lists of objects are written as JSON text. Fields starting with # (Apify hidden fields) are skipped.
  • Explicit columns: set Columns to write only those, in that order.
  • New fields in later runs are added as new columns at the end. Existing columns are never reordered, renamed or removed.
  • Values are written as-is (RAW) by default, so scraped text that starts with = is never run as a formula. Choose USER_ENTERED if you want Google to parse dates and formulas.
  • Cells longer than Google's 50,000-character limit are cut off with ….

Reliability

  • Batched writes, 500 rows per request by default.
  • Automatic retries with exponential backoff on Google rate limits (429) and server errors (5xx), respecting Retry-After. After the first batch, rows go to exact row numbers, so a retried request can't create duplicate rows.
  • Checks the 10,000,000-cell limit before writing anything. Google counts every cell in every tab, empty ones included. If the export would not fit, the run stops with nothing written and tells you how to fix it.
  • Never clears your sheet unless you choose replace. Replace saves a backup of the old tab (formulas included) to the run's key-value store as BACKUP-<tab>-<time>, writes the new data, and only then trims leftover rows and columns.
  • Empty source = no change. If the scraper returned 0 items, nothing is written, even in replace mode, so a failed scrape can't wipe your sheet.
  • Clear errors, for example:
    • Permission denied ... Open the spreadsheet, click Share, and add bot@my-project.iam.gserviceaccount.com as Editor
    • The Google Sheets API is not enabled for your Google Cloud project. Enable it at https://console.cloud.google.com/apis/library/sheets.googleapis.com?project=...
    • This file is an Excel (.xlsx) file stored in Google Drive, not a Google Sheet. Open it and use File > Save as Google Sheets

Pricing

Pay per event:

EventPrice
Actor start$0.001 per run
Row written$0.0001 per row ($0.10 per 1,000 rows), for rows written to a sheet (export) or to the dataset (import)

Only rows actually written are charged. Duplicates skipped by dedupe are free, and so are dry runs: turn on Dry run (or run without credentials) to preview the rows and columns that would be written without touching the sheet. A daily scraper that adds 200 new rows costs about $0.02 per day. Set a maximum cost per run in Apify: the Actor writes as many rows as fit within it, stops cleanly, and reports how many were left out.

Why another Sheets Actor?

Pushing scraper results into Google Sheets is usually a scheduled, unattended job, so the export has to work every time and say clearly what went wrong when it can't. This Actor is built for that: one job (dataset to sheet), retries for Google's rate limits, a cell-limit check before any write, a backup before any overwrite, and dedupe by key columns so scheduled runs don't fill your sheet with copies. It does one thing and tries to do it reliably.

FAQ

Why a service account and not "Sign in with Google"? A service account works in scheduled and integration runs without anyone signing in, never expires because a browser session ended, and only sees the sheets you share with it. If you already have an OAuth app, you can use the OAuth client ID, secret and refresh token fields instead (the refresh token must have the https://www.googleapis.com/auth/spreadsheets scope).

Can it import a Google Sheet into a dataset? Yes. Set Operation to Import. Public sheets need no credentials; private sheets need a service account with Viewer access.

What does dedupe compare? The values in your key columns, as text, against every row already in the tab, plus earlier rows in the same run. Rows where all key columns are empty are skipped (and counted in rowsSkippedEmptyKey), because they can't be told apart and would be added again on every run.

Can I use a key column that is nested? Yes, use the dot path, e.g. product.sku.

Will it change my formatting, formulas or extra columns? Append modes only add rows at the bottom and new header cells at the end of row 1. Replace mode rewrites the whole tab, including columns you added by hand, so keep formulas on a separate tab.

My data has more than 10 million cells. Google Sheets can't hold it. Split by tab or spreadsheet, choose fewer columns, or use replace instead of an ever-growing append.

Something broke or you need a feature? Open an issue on the Issues tab. I usually reply within a day.