Here are three working approaches, starting with the simplest.
Method 1: Apps Script Custom Function
This gives you a formula like =GPT("summarize this text") that you can drag across cells. It's the most spreadsheet-native approach.
Open your sheet, go to Extensions → Apps Script, and paste this:
function GPT(prompt, temperature) {
temperature = temperature || 0.3;
const apiKey = PropertiesService.getScriptProperties().getProperty('OPENAI_API_KEY');
const response = UrlFetchApp.fetch('https://api.openai.com/v1/chat/completions', {
method: 'post',
headers: {
'Authorization': 'Bearer ' + apiKey,
'Content-Type': 'application/json'
},
payload: JSON.stringify({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
temperature: temperature,
max_tokens: 500
})
});
const json = JSON.parse(response.getContentText());
return json.choices[0].message.content.trim();
}
Before using it, store your API key: in Apps Script, go to Project Settings → Script Properties and add OPENAI_API_KEY with your key.
Then in any cell:
=GPT("Classify this support ticket as bug, feature request, or question: " & A2)
The catch: Apps Script has a 6-minute execution limit per run. If you call =GPT() on 500 cells at once, it will timeout. Process in batches of 20-30 cells, or use the batch approach in Method 2.
Cost reality: gpt-4o-mini costs about $0.15 per million input tokens. A typical cell-level prompt with 50 words of input runs about 75 tokens. Processing 1,000 cells costs roughly $0.01. The API cost is negligible — the execution time is the real constraint.
Method 2: Python Script for Bulk Processing
When you need to process thousands of rows, a Python script is faster and more reliable than Apps Script. It sidesteps the execution time limits entirely.
pip install openai gspread google-auth
import openai
import gspread
from google.oauth2.service_account import Credentials
# Setup
openai.api_key = "sk-your-key"
creds = Credentials.from_service_account_file(
"service-account.json",
scopes=["https://www.googleapis.com/auth/spreadsheets"]
)
client = gspread.authorize(creds)
sheet = client.open_by_key("YOUR_SHEET_ID").sheet1
# Read input column
inputs = sheet.col_values(1)[1:] # Skip header
# Process with ChatGPT
results = []
for i, text in enumerate(inputs):
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"Summarize in one sentence: {text}"}],
temperature=0.3,
)
results.append([response.choices[0].message.content.strip()])
if i % 50 == 0:
print(f"Processed {i}/{len(inputs)}")
# Write results to column B
sheet.update(range_name="B2", values=results)
print(f"Done. Processed {len(results)} rows.")
For serious throughput, swap the loop for async requests with asyncio and httpx. The OpenAI API handles concurrent requests well, and you can process 1,000 rows in under a minute with 10 concurrent requests.
Method 3: Google Sheets Add-ons
If you don't want to write code at all, several add-ons bring GPT directly into Sheets:
- GPT for Sheets and Docs by Talarian — the most popular option. Adds
=GPT(),=GPT_LIST(),=GPT_TABLE()functions. Requires your own OpenAI API key. - SheetAI — similar formula-based approach with a built-in prompt builder.
- Numerous.ai — designed for bulk operations with batch processing built in.
Install from Extensions → Add-ons → Get add-ons and search for the name.
The trade-off: add-ons are the fastest to set up but the least flexible. You're limited to what the add-on author exposed as functions. If you need custom prompts with specific system messages, few-shot examples, or structured output, you'll outgrow them fast.
Common Gotchas
Rate limits bite hard in spreadsheets. OpenAI's API limits requests per minute. With the Apps Script approach, each cell recalculation is a separate API call. If you edit a column that 200 =GPT() formulas reference, all 200 fire simultaneously. Use Utilities.sleep(200) between calls or switch to batch processing.
Formulas recalculate on every edit. Unlike a normal formula, =GPT() hits a paid API each time. If someone edits an unrelated cell and Sheets recalculates, you're paying for reruns. Consider writing results as values (Ctrl+Shift+V to paste as values) once you're happy with the output.
Structured output needs work. If you want ChatGPT to return a specific format (JSON, comma-separated tags, a number), put the format instructions in the prompt explicitly: "Return only a JSON object with keys 'category' and 'confidence'. No explanation." Otherwise you'll get prose mixed in with your data.
Which Approach to Pick
| Situation | Best method |
|---|---|
| Quick analysis, < 50 cells | Apps Script custom function |
| Bulk processing, 100+ rows | Python script |
| Non-technical team needs it | Add-on |
| Complex prompts with context | Python script or Apps Script |