Google Sheets
The node that gets your data in front of people who will never open Expedify. Eleven operations, four of which turn a sheet into something you can update rather than only append to.
Some of what a workflow produces has to leave the product. A finance team that works in spreadsheets, a partner who wants a weekly list, a colleague who will not be given a login for one report a month. A sheet is where that lands.
The obvious use is appending: something happened, add a row. That works and it is what most people build. The more useful half of this node is the four operations that match on a value first — because a sheet you can update is a shared record, and a sheet you can only append to is a log that gets stale the moment anything changes.
Eleven operations, in four groups
| Group | Operations | What they are for |
|---|---|---|
read_range · lookup_rows · list_spreadsheets | Pull data back out. lookup_rows finds by value rather than by position. | |
write_range · append_rows · clear_range | Put data at a place you name. Append is the one everybody starts with. | |
update_matching_rows · append_or_update · delete_matching_rows | Find rows by a key and change them. This is where the node stops being a log. | |
create_spreadsheet · add_sheet | Make the file or the tab before you write to it. |
- Operations
read_range·lookup_rows·list_spreadsheets- What they are for
- Pull data back out. lookup_rows finds by value rather than by position.
- Operations
write_range·append_rows·clear_range- What they are for
- Put data at a place you name. Append is the one everybody starts with.
- Operations
update_matching_rows·append_or_update·delete_matching_rows- What they are for
- Find rows by a key and change them. This is where the node stops being a log.
- Operations
create_spreadsheet·add_sheet- What they are for
- Make the file or the tab before you write to it.
| Field | What it holds |
|---|---|
operation | Google Sheets operation to perform One of: read_range · write_range · append_rows · create_spreadsheet · add_sheet · clear_range · list_spreadsheets · lookup_rows · update_matching_rows · append_or_update · delete_matching_rows Defaults to read_range. |
spreadsheet_config | — |
data_config | — |
match_config | Row-matching config for lookup_rows, update_matching_rows, append_or_update and delete_matching_rows (VLOOKUP-style: find rows by a column value, then read/update/delete them). |
sheet_name | Sheet tab to operate on (chosen via the tab selector). Used by range and match operations. Defaults to Sheet1. |
operation
- What it holds
- Google Sheets operation to perform One of:
read_range · write_range · append_rows · create_spreadsheet · add_sheet · clear_range · list_spreadsheets · lookup_rows · update_matching_rows · append_or_update · delete_matching_rowsDefaults toread_range.
spreadsheet_config
- What it holds
- —
data_config
- What it holds
- —
match_config
- What it holds
- Row-matching config for lookup_rows, update_matching_rows, append_or_update and delete_matching_rows (VLOOKUP-style: find rows by a column value, then read/update/delete them).
sheet_name
- What it holds
- Sheet tab to operate on (chosen via the tab selector). Used by range and match operations. Defaults to
Sheet1.
Those config objects group what the operation needs. spreadsheet_config says which file and where in it. data_config carries what you are writing. match_config is the one that matters for the third group — which column is the key, what value to look for, and what to do when several rows match.
A worked example
One row per contact, kept current. The contact changes in the CRM and the sheet follows — updating the existing row if the email is already there, adding one if it is not.
append_or_update, keyed on email
Two nodes, and the whole idea is in match_config.
Read match_config first. match_column is Email — the header of the column, not a letter. That is the VLOOKUP key, and it is why the sheet's first row has to hold real headers and header_row has to point at it. Get that wrong and every match fails silently, because a key that matches nothing is indistinguishable from a contact you have not seen before.
match_mode is set to case-insensitive here, which for email addresses is the only correct answer — people type their address in whatever case they like and exact would create a duplicate row for each variant. match_position decides what happens when several rows match; first is the safe choice while you are learning, because all will happily rewrite twenty rows.
The values are a stringified two-dimensional array. This is the node's own warning and it is the thing people get wrong on their first attempt. Not an object, not a list of fields — a JSON string containing an array of rows, each row an array of cells, in column order. One row is still an array inside an array.
The setting that quietly corrupts data
value_input_option defaults to USER_ENTERED, which means Sheets interprets what you write exactly as if a person had typed it. A phone number beginning with a plus becomes a formula and errors. An order reference like 1/2 becomes a date. A leading zero on a postcode disappears. A long id becomes scientific notation. None of that raises anything — the write succeeds and the value in the cell is not the value you sent.
Set it to RAW for anything that is an identifier rather than a number: phone numbers, references, postcodes, ids, product codes. The workflow above uses RAW for exactly this reason. Use USER_ENTERED deliberately, when you want a date to be a date or a number to be summable — not by default.
What comes back
| Reference | What you get |
|---|---|
{{alias.data}} | The rows a read or lookup returned. An array of arrays, unless headers were included. |
{{alias.row_count}} | How many rows were read, written or matched. The number to check when you suspect a match found nothing. |
{{alias.spreadsheet_id}} | Useful after create_spreadsheet — it is the only place the new file's id appears. |
{{alias.data}}
- What you get
- The rows a read or lookup returned. An array of arrays, unless headers were included.
{{alias.row_count}}
- What you get
- How many rows were read, written or matched. The number to check when you suspect a match found nothing.
{{alias.spreadsheet_id}}
- What you get
- Useful after create_spreadsheet — it is the only place the new file's id appears.
What breaks
Watch out: operation is an enum (read_range/write_range/append_rows/…); write values go in data_config.values as a stringified 2-D array.
A failed match is not an error. Ask update_matching_rows to update a row that is not there and nothing happens, successfully. append_or_update is usually what you meant — it writes the row either way — but if you genuinely want an update-only operation, read {{alias.row_count}} and branch on zero.
Sheets are not a database and this node cannot make them one. Two runs matching on the same key at the same moment will both find the row and both write to it, and there is nothing here to prevent that. For a sheet updated a few times an hour it does not matter. For a high-frequency sync it does, and the answer is to write to your CRM and export on a schedule instead.
The sheet's shape is a contract nobody enforces. Somebody inserts a column on Monday and every write_range built on positions is now writing into the wrong cells — silently, because a range is just coordinates. The match-based operations survive this, since they work from header names. That is the strongest practical argument for using them.
Try it
- Make a sheet with headers in row 1 and connect a Google account. Run
read_rangeoverA1:E10and look at the shape of{{alias.data}}— arrays inside an array. - Append one row with
append_rows. Get the stringified 2-D array right; this is the step that fails first. - Write a phone number starting with
+using the defaultUSER_ENTERED, then the same number withRAW. Compare the two cells. This is the lesson. - Switch to
append_or_updatekeyed on an email column, run it twice with the same contact, and confirm you have one row rather than two. - Now change that contact's status in the CRM and let the workflow fire. The row should change in place.
Next: Google Docs — the same integration family when the output is prose rather than rows, and somebody has to read it.
Related lessons
Base rates — what a piece of evidence is actually worth
A face-recognition system that is 99.9% accurate and almost entirely wrong, and a number that sent an innocent woman to prison. Both are the same arithmetic, and it is the arithmetic that decides what any piece of evidence is worth.
ReadConfirmation and survivorship — what you never looked for
Two questions about evidence you did not go looking for. One is a rule you have to discover, and one is a pattern in five famous people — and in both, the thing that would have told you the truth is the thing nobody checks.
ReadLoss aversion, sunk cost and regression — what it costs you
Four questions you answer about yourself rather than about a scenario, and your own answers are the finding. Then the pattern that makes praise look useless and criticism look like it works, whatever you actually do.
Read
