Dataset to Google Sheets - Reliable Writer (Validate, Upsert) avatar

Dataset to Google Sheets - Reliable Writer (Validate, Upsert)

Pricing

$5.00 / 1,000 cells writtens

Go to Apify Store
Dataset to Google Sheets - Reliable Writer (Validate, Upsert)

Dataset to Google Sheets - Reliable Writer (Validate, Upsert)

Write Apify datasets or JSON rows to Google Sheets with fewer failed runs: preflight validation catches bad input before any charge, batching respects Google quotas, append/replace/upsert modes, readable errors, free dry run.

Pricing

$5.00 / 1,000 cells writtens

Rating

0.0

(0)

Developer

Constantine

Constantine

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

0

Monthly active users

6 days ago

Last modified

Share

Dataset to Google Sheets — Reliable Writer

Send your Apify datasets or JSON rows straight into Google Sheets — with validation that catches bad input before it costs you a failed run.

Most Sheets integrations fail after they start writing: they hit a quota mid-run, choke on an oversized cell, or die on an auth error — leaving you with a half-filled sheet and a generic FAILED. This actor is built the other way around. It checks everything first, tells you exactly what's wrong in plain language, and only then writes — in quota-safe batches. Broken input costs you nothing.


Why this actor

This actorTypical Sheets integration
AuthYour own Google service account — nothing sharedShared OAuth app (subject to "This app is blocked" and expiring tokens)
Bad inputCaught in a free preflight with row numbersFails mid-write with a generic error
Large syncsBatched & paced under Google's quotasOften dies partway through
Column safetyMatched by name; refuses ambiguous headersPositional writes can silently shift data
BillingPay only for cells actually writtenOften charged per run regardless of outcome

Features

  • 🔐 Your own service account. You authenticate with a Google service account you control — no shared app that Google can block, no refresh tokens that expire on you. Two-minute setup below.
  • 🧪 Free preflight validation. Bad spreadsheet URL, empty dataset, missing upsert keys, cells over Google's 50,000-character limit — all reported before any write and any charge, with the exact row numbers.
  • 📦 Quota-aware batching. Writes are split under Google's request-size limits and paced under the per-minute write quota, so large jobs are built to finish instead of stopping at row 30,000.
  • 🔁 Three write modes. append (add rows), replace (overwrite the sheet), and true upsert (update rows matching your key columns, append the rest).
  • 🧭 Header safety. Columns are matched by name, never by position. If your data has columns the sheet doesn't — or the sheet's headers are blank/duplicated — the actor stops with a clear message instead of scrambling your columns.
  • 💬 Actionable errors. A 403 becomes "share the spreadsheet with your-account@…iam.gserviceaccount.com (Editor) and retry" — not a stack trace.
  • 💸 Fair pricing. One metered event: per 1,000 cells actually written. Stop at a budget limit and every charged cell was written — nothing beyond it. replace verifies your budget covers the whole write before it clears anything.
  • 🔗 Pipeline-friendly. Reads the run's default dataset when chained after a scraper, and pushes a machine-readable report you can monitor or feed to the next actor.

Setup: Google service account (one time, ~2 minutes)

  1. Open the Google Cloud Console and create a project (or use an existing one). Billing is not required.
  2. Enable the Google Sheets API: APIs & Services → Library → Google Sheets API → Enable.
  3. Create a service account: IAM & Admin → Service Accounts → Create. Skip the optional roles — none are needed.
  4. Open the new account → Keys → Add Key → Create new key → JSON. A JSON file downloads. This is your googleServiceAccountKey.
  5. Copy the account's email (looks like name@project-id.iam.gserviceaccount.com) and Share your spreadsheet with it as an Editor.

That's it — the same key works for every spreadsheet you share with that email.


Input

FieldRequiredDescription
spreadsheetFull Google Sheets URL or the bare spreadsheet ID.
googleServiceAccountKeyfor real writesService account JSON key (stored encrypted). Not needed for a dry run.
modeappend (default), replace, or upsert.
keyColumnsfor upsertColumn names that uniquely identify a row.
datasetIdDataset to read. Omit to use the run's default dataset.
rowsInline JSON rows — an alternative to datasetId.
sheetNameTarget tab. Defaults to the first sheet; created if missing.
valueInputOptionRAW (default) stores values as-is; USER_ENTERED parses dates/formulas.
dryRuntrue = validate and plan only, no writes, no charge.

Example — append a dataset

{
"spreadsheet": "https://docs.google.com/spreadsheets/d/YOUR_ID/edit",
"mode": "append",
"datasetId": "YOUR_DATASET_ID",
"googleServiceAccountKey": { "type": "service_account", "client_email": "…", "private_key": "…" }
}

Example — upsert by id

{
"spreadsheet": "https://docs.google.com/spreadsheets/d/YOUR_ID/edit",
"mode": "upsert",
"keyColumns": ["id"],
"rows": [
{ "id": 1, "status": "updated in place" },
{ "id": 999, "status": "new row, appended" }
],
"googleServiceAccountKey": { "type": "service_account", "client_email": "…", "private_key": "…" }
}

Example — validate for free

{
"spreadsheet": "https://docs.google.com/spreadsheets/d/YOUR_ID/edit",
"datasetId": "YOUR_DATASET_ID",
"dryRun": true
}

Output

Every run pushes one machine-readable report to the dataset. A successful sync:

{
"type": "sync_report",
"status": "SUCCEEDED",
"sheetTitle": "Sheet1",
"mode": "upsert",
"rowsAppended": 1,
"rowsUpdated": 1,
"cellsWritten": 6,
"writeRequests": 2,
"durationMs": 1840
}

A validation failure instead returns a preflight_report (with the failing checks and row numbers) or an error_report (with a code, message, and a hint on how to fix it) — and charges nothing.

Error reference

CodeMeaningWhat to do
INVALID_SPREADSHEET_REFURL/ID not recognizedPass the full docs.google.com/spreadsheets/d/… URL
EMPTY_DATANothing to writeCheck datasetId / rows
MISSING_KEY_COLUMNS · KEY_COLUMN_NOT_IN_DATA · EMPTY_UPSERT_KEYUpsert misconfiguredList key columns that exist and are filled in your data
CELL_TOO_LARGECell over 50,000 chars (Google's limit)Trim the listed rows
SHEET_CELL_LIMITWould exceed the 10M-cell spreadsheet limitSplit across spreadsheets
HEADER_MISMATCH · SHEET_HEADER_BLANK · SHEET_HEADER_DUPLICATESheet headers can't safely receive this dataFix the header row or use mode=replace
PERMISSION_DENIEDSheet not shared with the service accountShare with the email shown in the error
BUDGET_TOO_SMALL_FOR_REPLACERun budget doesn't cover a full replaceRaise the budget — nothing was cleared
SPREADSHEET_NOT_FOUNDWrong or deleted spreadsheetCheck the URL

Pricing

One pay-per-event charge: $0.005 per 1,000 cells written (rounded up per batch). Dry runs, validation failures, and permission errors are free — you pay only when data lands in your sheet.

FAQ

Why a service account instead of "Sign in with Google"? A service account is a robot identity you own. It can't be blocked as part of a shared app, and its access never silently expires — the two most common reasons Sheets integrations break. The trade-off is one extra step: sharing the sheet with the account's email.

Is my key safe? The key is marked as a secret input and stored encrypted by Apify. It only grants access to spreadsheets you explicitly share with the account — nothing else in your Google account.

Which permissions does it need? Just the Google Sheets API and Editor access on the specific spreadsheets you share. No Drive-wide access, no IAM roles.

How much will a run cost? Cells × $0.005 / 1000. A 10,000-row sheet with 8 columns = 80,000 cells ≈ $0.40. Validate first with dryRun to see the exact cell count for free.

Does it work with any scraper? Yes. Chain it after any actor and omit datasetId to pick up that run's default dataset, or point datasetId at a specific dataset.

What if my data has nested objects? Nested objects and arrays are written as JSON strings, and the run reports how many cells that affected.