Google Sheets Safe Upsert (Validated Diff)
Pricing
from $0.02 / verified write
Google Sheets Safe Upsert (Validated Diff)
Upsert JSON rows into a Google Sheets tab safely: typed schema validation, a cell-by-cell diff preview, and only the approved diff is written. Same operationId sent 10 times = written once. Made for AI agents, MCP clients and automations.
Pricing
from $0.02 / verified write
Rating
0.0
(0)
Developer
Kumo Data Tools
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
What does Google Sheets Safe Upsert do?
Google Sheets Safe Upsert writes JSON rows into a Google Sheets tab without breaking it. Every row is checked against your typed schema, you get a cell-by-cell diff preview, and only the approved diff is written. Re-sending the same operationId never writes twice — not even 10 times in parallel.
It is made for AI agents, MCP clients and automations (Make, n8n, Zapier, your own scripts) that produce tables — inventory, prices, KPIs, product feeds, reports — and must not corrupt the sheet a human relies on.
- ✅ Typed validation, all-or-nothing —
string,number,integer,boolean,date, plusrequired,enum,min/max,minLength/maxLength,pattern. One bad cell or unknown field → zero cells written, and you get every error with its row and column. - 🔍 Diff preview —
mode: planreturns inserts and updates (before → after for each cell) plus aplanHash. Nothing is written. - 🔐 Approved diff only —
mode: applywithapprovedPlanHashwrites only if the current diff is exactly the approved plan (same cells, same values, same schema). If the sheet or the input changed, nothing is written and you get the new plan. - ♻️ Idempotent upserts — the same
operationIdis applied once; later runs returnduplicatewith the original result. Runs on the same tab are serialized with a lock (tested: 10 parallel runs of one operation → 1 write, 9 duplicates). - ⚛️ Atomic write + read-back check — data, ledger entry and lock release go out in one atomic Google Sheets batch, and the tab is compared again right after. A run only succeeds, and is only charged, when that check passes.
- 🧱 Nothing outside your schema is touched — other columns stay as they are, rows are never deleted, and text such as
=IMPORTXML(...)is stored as plain text, never executed as a formula.
How to write JSON to Google Sheets safely
Try it first: the prefilled input runs a read-only plan against our example sheet, so you can see the output before any setup. The example sheet can never be written to.
- Share your spreadsheet with this service account as Editor:
sheets-writer@kumo-sheets-writer.iam.gserviceaccount.com - Allow your Apify account: add a tab named
kumo_accessand put your Apify user ID in cell A1 (Apify Console → Settings → API & Integrations; or just run the Actor once — the error message prints your ID). This stops other Apify users from writing to a sheet you shared with the same service account. - Make sure row 1 of your target tab contains the column names from your schema, or leave the tab empty and the Actor writes the header.
- Run with
mode: plan, check the diff, then run withmode: apply, theplanHashand anoperationId. AI agents can do it in one call:mode: apply,skipApproval: true,operationId(validation, idempotency and read-back still apply).
The Actor creates one hidden tab, _kumo_ledger, that remembers operation IDs, and a short-lived hidden lock tab (_kumo_lock_…) while it writes. Don't edit them.
How much does it cost to write to Google Sheets?
Pay per event — platform usage is included, you only pay for these events:
| Event | When | Price |
|---|---|---|
diff-apply | A run that wrote changes and passed the read-back check | $0.02 per run |
diff-plan | A run that returned a plan, or an apply with nothing to write / a duplicate | $0.002 per run |
| Actor start | Every run (Apify standard) | $0.00005 |
One diff-apply covers up to 1,000 rows. So writing 1,000 rows costs about $0.02, and a plan + apply cycle about $0.022. Runs rejected by validation, access checks or a changed plan are not charged for either event.
Input example
{"spreadsheet": "https://docs.google.com/spreadsheets/d/1AbC.../edit","sheetName": "Inventory","mode": "plan","keyColumns": ["sku"],"columns": [{"name": "sku", "type": "string", "pattern": "[A-Z]{3}-\\d{3}"},{"name": "qty", "type": "integer", "min": 0},{"name": "price", "type": "number", "min": 0},{"name": "active", "type": "boolean"},{"name": "updated", "type": "date"}],"rows": [{"sku": "ABC-001", "qty": 5, "price": 9.5, "active": true, "updated": "2026-10-21"},{"sku": "ABC-002", "qty": 0, "price": 12, "active": false, "updated": "2026-10-20"}]}
To write it, send the same input with "mode": "apply", "operationId": "inventory-2026-10-21" and "approvedPlanHash": "<planHash from the plan run>".
Output example
The key-value store record OUTPUT holds the full result:
{"status": "applied","verified": true,"writtenCells": 7,"message": "Applied {'insert': 1, 'update': 2, ...}. Read-back check: the sheet now matches the input.","plan": {"planHash": "404ae3e2…","summary": {"insert": 1, "update": 2, "delete": 0, "unchanged": 0, "unkeyedSheetRowsLeftAlone": 0},"changes": [{"op": "update", "row": 2, "key": {"sku": "ABC-001"},"cells": [{"column": "qty", "before": 4, "after": 5}]},{"op": "insert", "key": {"sku": "ABC-002"},"values": {"sku": "ABC-002", "qty": 0, "price": 12, "active": false, "updated": "2026-10-20"}}]}}
status is one of planned, applied, noop, duplicate (run succeeds) or plan_changed, rejected, unverified, error (run fails, nothing charged). The dataset shows a preview of the first 100 changes or validation errors; the complete list is always in OUTPUT.
FAQ
Can an AI agent use this through MCP?
Yes. Call the Actor with mode: apply, skipApproval: true and a unique operationId per logical write. If the agent retries after a timeout, the retry returns duplicate instead of writing again. Use mode: plan first when a human should approve the change.
What happens if two runs write to the same tab at the same time?
They are serialized: the second waits for the first (up to about 2.5 minutes) and then works on the updated tab. If it cannot get its turn, it fails with nothing written.
Can someone edit the sheet while the Actor writes?
The lock keeps runs of this Actor apart, but it cannot stop a person typing into the same rows during the one or two seconds of a write. If that happens, the read-back check fails, the run fails and it is not charged — check the tab.
Does it delete rows?
No. This version only inserts and updates. Rows that are not in your input stay as they are.
What are the limits?
Up to 1,000 rows and 1 MB of row data per run (measured: 1,000 inserts with read-back ≈ 2.5 s of Google time). One tab per run. Keys must be unique in the input and in the sheet. Integers must be within ±9,007,199,254,740,991 — store longer IDs as string. date values are YYYY-MM-DD and are written as real dates; times are not supported yet (use a string column). The service account shares Google's per-minute request budget across all users; under heavy load a run waits and retries automatically.
What if I delete rows from _kumo_ledger?
Then the deleted operationIds can be written again. Leave the ledger alone if you rely on idempotency.
How is my data handled?
- The Actor reads and writes only the spreadsheet you name, and only after the
kumo_accesscheck passes. Users not listed there never see your tab names or data. - Your rows pass through the run and are stored only in your Apify run storage (dataset and
OUTPUT) under your Apify retention settings. The developer does not copy them elsewhere. - Google access uses a service account whose key is stored as an encrypted Apify secret. No Google password or OAuth token of yours is collected. Remove the share at any time to revoke access.
- Anything shared with the service account is technically reachable by whoever holds its key (the developer). The developer does not open shared sheets outside your runs. Share only the spreadsheet you want this Actor to write to.
- Data is not used for advertising or training and is not shared with third parties beyond Google (which processes the API calls) and Apify (which runs the Actor).
How do I get help?
Open an issue on the Issues tab. Issues are answered within 14 days, usually much sooner.
Google Sheets is a trademark of Google LLC. This Actor is not affiliated with or endorsed by Google.