This connects Claude to Google Sheets through the v4 API, so you can read, write, append, and batch update spreadsheet data directly from conversations. It handles the usual operations like reading ranges, updating cells, clearing data, and creating new sheets or entire spreadsheets. The skill documentation is solid with curl examples for everything from single cell updates to batch operations, plus clear guidance on A1 notation and URL encoding. Most useful when you're building workflows that need to pull data from or push results to Sheets without leaving your terminal or chat. The 300 requests per minute quota is reasonable for most automation tasks, and the batch operations help you stay well under that limit.
npx -y skills add vm0-ai/vm0-skills --skill google-sheets --agent claude-codeInstalls into .claude/skills of the current project.
If requests fail, run zero doctor check-connector --env-name GOOGLE_SHEETS_TOKEN or zero doctor check-connector --url https://sheets.googleapis.com/v4/spreadsheets --method GET
Base URL: https://sheets.googleapis.com/v4/spreadsheets
Finding your Spreadsheet ID:
The spreadsheet ID is in the URL: https://docs.google.com/spreadsheets/d/{SPREADSHEET_ID}/edit
Get information about a spreadsheet (sheets, properties):
curl -s "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" | jq '{title: .properties.title, sheets: [.sheets[].properties | {sheetId, title}]}'
Read a range of cells:
curl -s "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values/Sheet1%21A1:D10" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" | jq '.values'
Read all data from a sheet:
curl -s "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values/Sheet1" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" | jq '.values'
Update a range of cells.
Write to /tmp/gsheets_request.json:
{
"values": [
["Name", "Email", "Status"]
]
}
Then run:
curl -s -X PUT "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values/Sheet1%21A1:C1?valueInputOption=USER_ENTERED" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" --header "Content-Type: application/json" -d @/tmp/gsheets_request.json | jq '.updatedCells'
valueInputOption:
RAW: Values are stored as-isUSER_ENTERED: Values are parsed as if typed by user (formulas evaluated)Add new rows to the end of a sheet.
Write to /tmp/gsheets_request.json:
{
"values": [
["John Doe", "john@example.com", "Active"]
]
}
Then run:
curl -s -X POST "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values/Sheet1%21A:C:append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" --header "Content-Type: application/json" -d @/tmp/gsheets_request.json | jq '.updates | {updatedRange, updatedRows}'
Read multiple ranges in one request:
curl -s "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values:batchGet?ranges=Sheet1%21A1:B5&ranges=Sheet1%21D1:E5" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" | jq '.valueRanges'
Update multiple ranges in one request.
Write to /tmp/gsheets_request.json:
{
"valueInputOption": "USER_ENTERED",
"data": [
{
"range": "Sheet1!A1",
"values": [["Header 1"]]
},
{
"range": "Sheet1!B1",
"values": [["Header 2"]]
}
]
}
Then run:
curl -s -X POST "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values:batchUpdate" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" --header "Content-Type: application/json" -d @/tmp/gsheets_request.json | jq '.totalUpdatedCells'
Clear a range of cells.
Write to /tmp/gsheets_request.json:
{}
Then run:
curl -s -X POST "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values/Sheet1%21A2:C100:clear" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" --header "Content-Type: application/json" -d @/tmp/gsheets_request.json | jq '.clearedRange'
Write to /tmp/gsheets_request.json:
{
"properties": {
"title": "My New Spreadsheet"
},
"sheets": [
{
"properties": {
"title": "Data"
}
}
]
}
Then run:
curl -s -X POST "https://sheets.googleapis.com/v4/spreadsheets" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" --header "Content-Type: application/json" -d @/tmp/gsheets_request.json | jq '{spreadsheetId, spreadsheetUrl}'
Add a new sheet to an existing spreadsheet.
Write to /tmp/gsheets_request.json:
{
"requests": [
{
"addSheet": {
"properties": {
"title": "New Sheet"
}
}
}
]
}
Then run:
curl -s -X POST "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}:batchUpdate" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" --header "Content-Type: application/json" -d @/tmp/gsheets_request.json | jq '.replies[0].addSheet.properties'
Delete a sheet from a spreadsheet (use sheetId from metadata).
Write to /tmp/gsheets_request.json:
{
"requests": [
{
"deleteSheet": {
"sheetId": 123456789
}
}
]
}
Then run:
curl -s -X POST "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}:batchUpdate" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" --header "Content-Type: application/json" -d @/tmp/gsheets_request.json
Find cells containing specific text (read all then filter):
curl -s "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheet-id}/values/Sheet1" --header "Authorization: Bearer $GOOGLE_SHEETS_TOKEN" | jq '[.values[] | select(.[0] | ascii_downcase | contains("search_term"))]'
| Notation | Description |
|---|---|
Sheet1!A1 | Single cell A1 in Sheet1 |
Sheet1!A1:B2 | Range from A1 to B2 |
Sheet1!A:A | Entire column A |
Sheet1!1:1 | Entire row 1 |
Sheet1!A1:C | From A1 to end of column C |
'Sheet Name'!A1 | Sheet names with spaces need quotes |
USER_ENTERED for formulas, RAW for literal strings%21 in URLs (e.g., Sheet1%21A1:D10)larksuite/cli
googleworkspace/cli
googleworkspace/cli
googleworkspace/cli