How to Connect Claude API to Google Sheets
Google Sheets has no native Claude integration, but you can connect to Claude from inside a spreadsheet using Google Apps Script's UrlFetchApp to call the Claude API directly. This lets you build custom functions like =CLAUDE(A1) that summarize text, classify rows, extract data, or generate content without leaving the sheet.
The fastest path is a custom Apps Script function that sends each cell's content as a prompt to Claude and writes the response back. Below is a complete working setup, plus the gotchas that trip people up — execution timeouts, rate limits, and quota tracking across a shared team sheet.
What you need before starting
- A Claude API key (either directly from Anthropic, or a
sub_live_...key from SubToAPI if you want usage tracking and team seats built in) - Access to Extensions → Apps Script in your Google Sheet
- Basic comfort reading/writing JavaScript (Apps Script is JS-based)
If you're using SubToAPI, grab your key from the dashboard after signing up at /signup — it's a drop-in replacement for the Anthropic endpoint with the same request/response shape, documented at /docs/quickstart.
Step 1: Open the Apps Script editor
In your spreadsheet, go to Extensions → Apps Script. This opens a separate script environment tied to that sheet. Delete the placeholder code and paste in the function below.
Step 2: Write the custom function
This creates a =CLAUDE() formula you can use like any built-in Sheets function:
function CLAUDE(prompt, model) {
if (!prompt) return "";
var apiKey = "YOUR_SUBTOAPI_KEY"; // store in Script Properties instead
var url = "https://api.subtoapi.app/v1/messages";
var payload = {
model: model || "claude-opus-4-5",
max_tokens: 1024,
messages: [
{ role: "user", content: prompt }
]
};
var options = {
method: "post",
contentType: "application/json",
headers: {
"Authorization": "Bearer " + apiKey
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
var response = UrlFetchApp.fetch(url, options);
var json = JSON.parse(response.getContentText());
if (json.content && json.content[0] && json.content[0].text) {
return json.content[0].text;
}
return "ERROR: " + response.getContentText();
}
Save the script, name the project, and return to your sheet. In any cell, type:
=CLAUDE(A1, "claude-opus-4-5")
Sheets will call out to the API and populate the result. The request/response format matches the standard Messages API — see /docs/messages for the full parameter list if you want to add system prompts, temperature, or stop sequences.
Step 3: Store your API key securely
Never hardcode a key in script source if the sheet is shared. Use Script Properties instead:
function setApiKey() {
PropertiesService.getScriptProperties().setProperty('SUBTOAPI_KEY', 'sub_live_xxxxx');
}
Run setApiKey() once manually from the editor, then replace the hardcoded key in CLAUDE() with:
var apiKey = PropertiesService.getScriptProperties().getProperty('SUBTOAPI_KEY');
This keeps the key out of the script source and out of the sheet itself, which matters once you share the spreadsheet with teammates.
Handling rate limits and timeouts
Two Apps Script constraints matter here:
- Execution time limit: Apps Script functions time out after 6 minutes (30 seconds for custom functions triggered by formulas). If you're processing a large column, custom functions recalculating on every edit will hit this fast.
- Rate limits: Calling
=CLAUDE()across hundreds of rows simultaneously can trigger 429 responses if you fire them all at once.
For bulk processing, don't rely on live formulas — use a batch script with a loop and a short delay instead:
function batchProcess() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var apiKey = PropertiesService.getScriptProperties().getProperty('SUBTOAPI_KEY');
for (var i = 1; i < data.length; i++) {
var prompt = data[i][0];
if (!prompt) continue;
var result = CLAUDE(prompt);
sheet.getRange(i + 1, 2).setValue(result);
Utilities.sleep(500); // throttle requests
}
}
Bind this to a menu button or a time-driven trigger (Triggers → Add Trigger) so it runs on a schedule instead of on every cell edit.
Why use SubToAPI instead of calling Anthropic directly
The code above works identically against the raw Anthropic endpoint or against SubToAPI — the request shape is the same. The practical difference shows up once more than one person touches the sheet:
- Team visibility: SubToAPI's dashboard shows usage per API key, so if three teammates are running batch jobs against the same spreadsheet, you can see who's burning tokens without digging through logs.
- Streaming support: if you move beyond single-cell lookups into a sidebar chat UI inside Sheets, SubToAPI supports streaming responses — see /docs/streaming.
- Tool use: for more advanced sheet automation (e.g., Claude deciding to call a function to fetch external data before answering), the tool-use flow is documented at /docs/tools.
- Spending control: plans start at Solo for solo builders and scale to Team and Scale tiers with per-seat pricing, so a shared internal tool doesn't need everyone generating separate API keys from scratch — check /pricing.
Either way, the Apps Script integration pattern stays the same: UrlFetchApp makes the HTTP call, Claude returns text, and the function writes it back into the cell.
Common use cases once it's connected
- Summarizing long text pasted into a column
- Classifying support tickets or survey responses by sentiment/category
- Extracting structured fields (names, dates, amounts) from unstructured text
- Drafting outreach emails or product descriptions row-by-row
- Translating a column of content into multiple languages
Questions
Does Claude have an official Google Sheets add-on? No. There's no native Anthropic-built Sheets extension as of now. The standard approach is the Apps Script method above, which works with any Claude-compatible API endpoint.
Will this work with Claude's streaming responses? Custom Sheets functions return a single value, so streaming doesn't apply inside a formula. If you want streaming output, build a sidebar or web app with Apps Script's HTML service instead of a cell formula — see /docs/streaming for the API side.
How do I avoid hitting rate limits with large sheets? Use a batch script with Utilities.sleep() between calls instead of live formulas that recalculate on every edit, and check your plan's request limits — SubToAPI's usage dashboard shows how close you are to your quota in real time.