read_range from yesterday reads rows from the Sheet. Now after every lab session you want to append a new row — date, what you did, status — without opening the spreadsheet. How does the append action work?
GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND — the name implies it appends values. Takes the sheet ID, a range to define where to append, and the row values as a list.
Exactly. The values param is a list of rows — each row is a list of strings. APPEND finds the first empty row after the existing data in the given range and writes there. You don't need to know which row number to use:
new_row = ["2026-04-12", "Reviewed 50 survey responses", "On track"]
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{"spreadsheet_id": "sheet-id", "range": "Sheet1!A:C", "values": [new_row]}
)
print(f"Appended to: {result.get('updates', {}).get('updatedRange', '')}")values: [[new_row]] — why a list inside a list? I expected just the row as a list.
The API accepts multiple rows at once — values is a list of rows, each row a list. [["date", "desc", "status"]] is one row. [[row1], [row2]] appends two rows in one call. Single-row appends always need the outer wrapper:
def append_row(sheet_id: str, range_a1: str, values: list) -> dict:
before = read_range(sheet_id, range_a1)
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{"spreadsheet_id": sheet_id, "range": range_a1, "values": [values]}
)
print(f"Appended row. Sheet had {len(before)} rows before.")
return resultI could run this from the command line as I walk out of the lab. Thirty seconds and the shared Sheet is updated.
The fastest update is the one that happens before you put your laptop away.
I called read_range first to show the sheet state before appending. That's the lookup-before-write habit from the Calendar and Tasks lessons.
APPEND uses smart range detection — it finds the last populated row and writes after it. If your sheet has blank rows in the middle, APPEND may write to an unexpected position. Keep your progress sheet clean — no blank rows between entries — or specify a more precise range like "Sheet1!A100:C100" if you know the last row.
Params:
| Param | Type | Example |
|---|---|---|
spreadsheet_id | str | Sheet ID from URL |
range | str | "Sheet1!A:C" |
values | list of lists | [["date", "desc", "status"]] |
[values] not valuesThe API accepts multiple rows. Wrap a single row in an outer list: [row] → [["2026-04-12", "...", "..."]].
Finds the first empty row after existing data — no row number needed. This means you can call append_row repeatedly and data always lands at the bottom without overwriting.
Returns a dict with updates.updatedRange showing which cells were written. Check this to confirm the write succeeded.
read_range from yesterday reads rows from the Sheet. Now after every lab session you want to append a new row — date, what you did, status — without opening the spreadsheet. How does the append action work?
GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND — the name implies it appends values. Takes the sheet ID, a range to define where to append, and the row values as a list.
Exactly. The values param is a list of rows — each row is a list of strings. APPEND finds the first empty row after the existing data in the given range and writes there. You don't need to know which row number to use:
new_row = ["2026-04-12", "Reviewed 50 survey responses", "On track"]
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{"spreadsheet_id": "sheet-id", "range": "Sheet1!A:C", "values": [new_row]}
)
print(f"Appended to: {result.get('updates', {}).get('updatedRange', '')}")values: [[new_row]] — why a list inside a list? I expected just the row as a list.
The API accepts multiple rows at once — values is a list of rows, each row a list. [["date", "desc", "status"]] is one row. [[row1], [row2]] appends two rows in one call. Single-row appends always need the outer wrapper:
def append_row(sheet_id: str, range_a1: str, values: list) -> dict:
before = read_range(sheet_id, range_a1)
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{"spreadsheet_id": sheet_id, "range": range_a1, "values": [values]}
)
print(f"Appended row. Sheet had {len(before)} rows before.")
return resultI could run this from the command line as I walk out of the lab. Thirty seconds and the shared Sheet is updated.
The fastest update is the one that happens before you put your laptop away.
I called read_range first to show the sheet state before appending. That's the lookup-before-write habit from the Calendar and Tasks lessons.
APPEND uses smart range detection — it finds the last populated row and writes after it. If your sheet has blank rows in the middle, APPEND may write to an unexpected position. Keep your progress sheet clean — no blank rows between entries — or specify a more precise range like "Sheet1!A100:C100" if you know the last row.
Params:
| Param | Type | Example |
|---|---|---|
spreadsheet_id | str | Sheet ID from URL |
range | str | "Sheet1!A:C" |
values | list of lists | [["date", "desc", "status"]] |
[values] not valuesThe API accepts multiple rows. Wrap a single row in an outer list: [row] → [["2026-04-12", "...", "..."]].
Finds the first empty row after existing data — no row number needed. This means you can call append_row repeatedly and data always lands at the bottom without overwriting.
Returns a dict with updates.updatedRange showing which cells were written. Check this to confirm the write succeeded.
Create a free account to get started. Paid plans unlock all tracks.