Google Sheet Monitor API - Track Row Changes on a Schedule
Pricing
from $5.00 / 1,000 sheet rows
Google Sheet Monitor API - Track Row Changes on a Schedule
Watch a Google Sheet and get told what moved. Every row comes back stamped added, updated, removed or unchanged against the previous run, so a schedule becomes a change feed for Slack, a webhook or another Actor. Unchanged rows are never billed, so an hourly cron stays affordable.
Pricing
from $5.00 / 1,000 sheet rows
Rating
0.0
(0)
Developer
Blackcube
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 hours ago
Last modified
Categories
Share
Google Sheet Monitor API
The Google Sheets suite
- Google Sheets Scraper API — any sheet as a typed dataset — every tab, SQL-like filters, private sheets, change monitoring
- Google Spreadsheet Scraper API — a whole Google spreadsheet as clean JSON rows, no Google login
- Google Sheets to JSON API — a sheet as a JSON endpoint, with real types and server-side filtering
- Private Google Sheets Reader API — read sheets that are not link-shared, via your own service account
Watch a Google Sheet and get told what moved. Every row comes back stamped against the previous run, so a schedule turns a living spreadsheet into a change feed.
Quick start
-
Open the sheet → Share → General access → Anyone with the link → Viewer.
-
Click Copy link.
-
Paste it into the Sheet URL input and press Start.
-
Leave Monitor for changes on and attach a Schedule (hourly, daily — whatever suits).
The first run classifies everything as added and remembers it. Every run after that reports
only what actually moved.
What you get back
| changeStatus | Meaning | Billed |
|---|---|---|
added | a row that was not there last run | yes |
updated | a row whose cells changed | yes |
removed | a row (or a whole tab) that is gone — the notice carries its last known contents | no |
unchanged | nothing moved | no |
Turn Return only changes on to receive nothing but the movements — the unchanged rows are still counted for you in the free coverage row.
What people use it for
- Alerting. Wire the dataset to Slack, e-mail or a webhook and hear about it when someone edits the sheet.
- Approval and intake queues. A new row in a request sheet starts the rest of the workflow.
- Price and inventory sheets a supplier keeps updating.
- Audit trails. Keep the record of what changed and when, which the spreadsheet itself does not give you in a usable form.
- Watching several sheets at once — put the extra links in More sheet URLs.
Why an hourly schedule is affordable here
Rows that did not change are never billed. A 500-row sheet checked every hour, with a handful of edits a day, costs a few cents a day rather than 500 rows an hour — which is the difference between a schedule you keep and a bill you cancel.
What a row looks like
{"type": "row","spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms","spreadsheetTitle": "Example Spreadsheet","sheetName": "Class Data","gid": 0,"rowNumber": 2,"changeStatus": null,"cells": {"Student Name": "Alexandra","Gender": "Female","Class Level": "4. Senior","Home State": "CA","Major": "English","Extracurricular Activity": "Drama Club"},"scrapedAt": "2026-09-01T00:00:00.000Z"}
Every cell is keyed by its column header. With Typed values on (the default) numbers arrive as
numbers, booleans as booleans and date cells as ISO-8601 strings, so the data is ready for a
database load, a JSON pipeline or an LLM prompt without a cleaning pass. Turn it off and every
value is exactly the text the sheet displays. Duplicate headers are de-duplicated
(Tags, Tags_2), a headerless sheet names its columns with the sheet's own letters
(A, B, …), and the invisible trailing columns Google pads every sheet with are dropped.
Alongside the data rows every run returns free rows you are never billed for: a coverage row per sheet (tabs requested, read and errored; rows read, delivered, unchanged and removed; whether the run was complete) and one summary row with the exact spend.
What it costs
| You pay for | Price |
|---|---|
| Each row delivered | $5.00 per 1,000 rows |
| Each row from a private sheet (service account) | $10.00 per 1,000 rows |
| Each spreadsheet successfully read | $0.015 |
| Optional monthly pass: 30 days with no per-row or per-sync charges, charged once, no automatic renewal | $19.00 |
Free, always: a sheet that could not be read, a tab that failed, error rows, coverage rows, removed-row notices, the metadata row, the run summary — and on a monitoring schedule, every row that did not change. A run that reads nothing costs nothing.
The monthly pass is for busy schedules: turn it on and the run charges it once, right before the first charge would be billed, then every run you start with it on for the next 30 days delivers rows and sheet syncs without per-unit charges. It pays for itself above roughly 3,800 billed rows or 1,300 sheet syncs a month - two sheets on an hourly schedule - and it is never charged silently: a run that reads nothing never charges it. No automatic renewal.
Set Cost ceiling (USD) to stop any run before it passes a number you choose; the free summary row reports what the run actually spent.
FAQ
Do I need a Google account, or to log in?
No. A link-shared sheet is read from its URL alone — no Google sign-in, no OAuth consent screen, no Drive permission prompt, nothing to install in the sheet.
My run failed with "the sheet is not link-shared". What now?
Copying a share link does not share the sheet. Open Share → General access and change Restricted to Anyone with the link → Viewer. If the sheet genuinely cannot be shared, use the service-account route below instead.
Can it read a sheet that is not shared publicly?
Yes. Create a Google Cloud service account, share the sheet with its …iam.gserviceaccount.com
address as a Viewer, and paste its JSON key into Service account JSON. Those rows bill at the
private-sheet rate.
Does my spreadsheet ID have to be a particular length?
No. Google has issued IDs of several lengths over the years and all of them are accepted — paste the whole URL and the ID is taken out of it for you.
Can I read more than one sheet in one run?
Yes. Put the extra share links in More sheet URLs. Every row is stamped with the spreadsheet it came from, and the row budget is split across the sheets so the first one cannot consume it.
Can I filter before I pay for rows?
Yes — the Query input runs a SQL-like filter on Google's side, so rows you filter out are
never delivered and never billed: select A, C where C contains 'active' order by A limit 100.
Will a schedule re-charge me for data I already have?
No. Turn Monitor for changes on and only rows that were added, updated or removed are billed. A quiet sheet on an hourly schedule costs only its per-sheet sync.
What is the monthly pass?
An optional flat fee for heavy schedules. Turn Monthly pass on and it is charged once, right before the first charge of the run would be billed; for the next 30 days every run you start with it on delivers rows and sheet syncs with no per-unit charges. It never renews by itself - it is charged again only when you run with it on after it has expired - and a run that reads nothing never charges it. Keep Cost ceiling (USD) above the pass price.
Do I need a proxy?
No. Everything is handled for you and there is nothing to buy on top.
What happens if one tab is broken?
The other tabs still deliver. The failed tab becomes a free error row that names what went wrong, and the free coverage row tells you exactly how much of the sheet you actually got.
Use it from n8n, MCP, the API or a schedule
Built to be called by a workflow, not only from the Store form. The Actor is vonsensey/google-sheet-monitor-change-tracker-scraper-api; every snippet below sends {}, which runs the defaults shown on the form — replace it with your own input.
n8n
Install the Apify community node (@apify/n8n-nodes-apify under Settings → Community Nodes, or search "Apify" on n8n Cloud). Add Apify → Run Actor with Actor vonsensey/google-sheet-monitor-change-tracker-scraper-api and your input JSON, then Apify → Get Dataset Items on the run's defaultDatasetId and pipe the rows anywhere. For scheduled runs, the On new Apify Event trigger fires when a run of this Actor finishes.
MCP (Claude, Cursor, VS Code, any MCP client)
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=vonsensey/google-sheet-monitor-change-tracker-scraper-api","headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}}}}
Your agent then calls vonsensey/google-sheet-monitor-change-tracker-scraper-api as a tool with the same input the form takes and reads the dataset back.
REST API (one call, rows in the response)
curl -X POST "https://api.apify.com/v2/acts/vonsensey~google-sheet-monitor-change-tracker-scraper-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" -d '{}'
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("vonsensey/google-sheet-monitor-change-tracker-scraper-api").call(run_input={})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row)
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('vonsensey/google-sheet-monitor-change-tracker-scraper-api').call({});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Make, Zapier, LangChain, CrewAI
The Apify app in Make and Zapier has a Run an Actor module: pick vonsensey/google-sheet-monitor-change-tracker-scraper-api. In LangChain and CrewAI the Apify tool wrappers take the same Actor id. A daily schedule needs nothing but the Console: Schedules → Create → this Actor → cron, and the dataset fills on its own.