read_range from yesterday reads existing rows. Today you write a new one. You track hours in a Google Sheet. Right now you open the tab, scroll to the last row, and type the date, client name, hours, and note. How often do you forget?
More than I want to admit. Sometimes I reconstruct hours from my calendar at the end of the month.
GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND appends a row the moment you finish a session. Pass the spreadsheet ID, the range to append into, and the values as a list of one row — a list inside a list:
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{
"spreadsheetId": sheet_id,
"range": "A:D",
"values": [["2026-04-12", "Acme", "2.5", "Review round 2"]]
}
)So a row in Sheets is just a list of strings. That is all it ever was.
It was always a list. Now Python knows that too.
The values parameter is a list of lists — one inner list per row. Why not just pass the row directly?
Append supports multiple rows in one call. The outer list holds all the rows; each inner list is one row's values. Passing a single-row list [[...]] is the common case. The API shape stays consistent whether you append one row or a hundred:
def append_row(sheet_id: str, range_a1: str, values: list) -> dict:
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{"spreadsheetId": sheet_id, "range": range_a1, "values": [values]}
)
print(f"Appended row to {range_a1}")
return resultMy end-of-session log is now a one-liner. No more reconstructing hours from calendar.
One note: append always adds after the last row with data. If you want to insert in a specific position, use update. For a time log where new entries go to the bottom, append is exactly right.
GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND adds one or more rows after the last filled row in the specified range:
result = toolset.execute_action(
action=Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
params={
'spreadsheetId': sheet_id,
'range': range_a1,
'values': [values]
}
)values shapevalues is a list of rows — each row is a list of cell values: [[date, client, hours, note]]. The outer list allows appending multiple rows in one call.
Read before write: call read_range first to verify the sheet shape matches what you are about to append. A mismatched column count will shift data into wrong columns silently.
read_range from yesterday reads existing rows. Today you write a new one. You track hours in a Google Sheet. Right now you open the tab, scroll to the last row, and type the date, client name, hours, and note. How often do you forget?
More than I want to admit. Sometimes I reconstruct hours from my calendar at the end of the month.
GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND appends a row the moment you finish a session. Pass the spreadsheet ID, the range to append into, and the values as a list of one row — a list inside a list:
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{
"spreadsheetId": sheet_id,
"range": "A:D",
"values": [["2026-04-12", "Acme", "2.5", "Review round 2"]]
}
)So a row in Sheets is just a list of strings. That is all it ever was.
It was always a list. Now Python knows that too.
The values parameter is a list of lists — one inner list per row. Why not just pass the row directly?
Append supports multiple rows in one call. The outer list holds all the rows; each inner list is one row's values. Passing a single-row list [[...]] is the common case. The API shape stays consistent whether you append one row or a hundred:
def append_row(sheet_id: str, range_a1: str, values: list) -> dict:
result = toolset.execute_action(
Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
{"spreadsheetId": sheet_id, "range": range_a1, "values": [values]}
)
print(f"Appended row to {range_a1}")
return resultMy end-of-session log is now a one-liner. No more reconstructing hours from calendar.
One note: append always adds after the last row with data. If you want to insert in a specific position, use update. For a time log where new entries go to the bottom, append is exactly right.
GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND adds one or more rows after the last filled row in the specified range:
result = toolset.execute_action(
action=Action.GOOGLESHEETS_SPREADSHEETS_VALUES_APPEND,
params={
'spreadsheetId': sheet_id,
'range': range_a1,
'values': [values]
}
)values shapevalues is a list of rows — each row is a list of cell values: [[date, client, hours, note]]. The outer list allows appending multiple rows in one call.
Read before write: call read_range first to verify the sheet shape matches what you are about to append. A mismatched column count will shift data into wrong columns silently.
Create a free account to get started. Paid plans unlock all tracks.