Module · A system, a clock or a person
Google Sheets trigger
Lesson 9 of 10 · 3 min
Spreadsheets are where work goes when there is no system for it yet. The event sign-up list, the leads a colleague collected at a conference, the weekly numbers somebody pastes in on Friday.
The Google Sheets trigger treats one of those as an input: a row appears, and a workflow runs.
Three events
| Event | Fires when |
|---|---|
new_row | A row is added. The default, and the common case. |
row_updated | An existing row changes. |
row_deleted | A row is removed. |
new_row
- Fires when
- A row is added. The default, and the common case.
row_updated
- Fires when
- An existing row changes.
row_deleted
- Fires when
- A row is removed.
Configuration
| Field | What it holds |
|---|---|
integration_id | Google Sheets integration to use |
spreadsheet_url | Full URL of the Google Sheet |
spreadsheet_id | ID of the Google Spreadsheet to monitor |
sheet_name | Name of the sheet/tab to monitor Defaults to Sheet1. |
trigger_events | Events that should trigger the workflow |
poll_interval_minutes | How often to check for changes Defaults to 5. |
integration_id
- What it holds
- Google Sheets integration to use
spreadsheet_url
- What it holds
- Full URL of the Google Sheet
spreadsheet_id
- What it holds
- ID of the Google Spreadsheet to monitor
sheet_name
- What it holds
- Name of the sheet/tab to monitor Defaults to
Sheet1.
trigger_events
- What it holds
- Events that should trigger the workflow
poll_interval_minutes
- What it holds
- How often to check for changes Defaults to
5.
sheet_name defaults to Sheet1 — worth setting deliberately, because the tab somebody actually uses is rarely the one Google created.
Reading the row
| Reference | Holds |
|---|---|
{{googlesheetstrigger_1.row_data}} | The row, keyed by column header. |
{{googlesheetstrigger_1.headers}} | The header row itself. |
{{googlesheetstrigger_1.row_number}} | Which row it was. |
{{googlesheetstrigger_1.changed_columns}} | On row_updated, which cells changed. |
{{googlesheetstrigger_1.old_row_data}} | The previous values, for comparison. |
{{googlesheetstrigger_1.row_data}}
- Holds
- The row, keyed by column header.
{{googlesheetstrigger_1.headers}}
- Holds
- The header row itself.
{{googlesheetstrigger_1.row_number}}
- Holds
- Which row it was.
{{googlesheetstrigger_1.changed_columns}}
- Holds
- On
row_updated, which cells changed.
{{googlesheetstrigger_1.old_row_data}}
- Holds
- The previous values, for comparison.
Columns come through by header name: {{googlesheetstrigger_1.row_data.Email}}. That is convenient and it is also the fragile part.
A spreadsheet is a shared document, and renaming a column silently breaks the workflow. Somebody tidies “Email” to “Email Address” and every run afterwards reads an empty value — no error, because the reference simply resolves to nothing. Spreadsheet inputs need either a header row people know not to touch, or a workflow that checks the field is non-empty before using it.
Polling, and what it costs
poll_interval_minutes defaults to 5. Nothing pushes a change to Expedify — the trigger checks the sheet on that interval, so five minutes is also the worst-case delay between a row appearing and your workflow running.
Shortening the interval makes it fresher and makes the check run more often. For most spreadsheet work — leads to follow up, records to import — five minutes is invisible, and there is rarely a good reason to go lower.
Is a spreadsheet the right input?
This trigger is genuinely useful and it is also a bridge, not a destination. A sheet is easy to start with, and it has no validation, no permissions worth the name, and no protection against somebody sorting the rows.
- Good fit — a one-off import, a list from an event, a partner who will only ever send a spreadsheet.
- Better replaced — anything ongoing and business-critical. A webhook or a form writing straight to the CRM removes a whole class of “someone edited the sheet” problems.
Both directions exist. This is the trigger. There is also a Google Sheets action that writes rows, covered in the Actions path — a common pairing is reading rows here and writing results back there, so the sheet stays the shared surface people look at.
Try it
- Connect a Google integration and point the trigger at a test sheet and tab.
- Leave it on
new_row, write{{googlesheetstrigger_1.row_data}}into a note, and add a row. - Time how long it takes to fire — that is your polling interval, felt rather than read.
- Now rename a column and add another row, and watch the reference come back empty. Better to see it here than in production.
Next: the Click trigger — the last of the ten, and the only one a person starts on purpose.

