Connect Google Sheets to OpenAI: Generate Content with Apps Script
Artificial intelligence has revolutionized content creation, and now you can harness that power directly within Google Sheets. By connecting OpenAI’s API to your spreadsheets using Google Apps Script, you can generate content, summarize text, analyze data, and much more—all without switching between different tools.
In this tutorial, I’ll walk you through how to create a Google Sheets integration with OpenAI that lets you generate content with a simple function call or button click.
What You’ll Build
By the end of this tutorial, you’ll have:
- A Google Sheet connected to OpenAI’s API
- Custom functions that generate content based on your prompts
- A user-friendly interface with buttons
- The ability to process batches of content requests
Prerequisites
- A Google account
- An OpenAI API key (requires signup and payment method)
- Basic familiarity with Google Sheets
- No prior coding experience required, though it helps
Step 1: Set Up Your Google Sheet
First, let’s create a spreadsheet that will serve as our interface with OpenAI:
- Create a new Google Sheet
- Set up the following columns in row 1:
- A1: Prompt
- B1: Generated Content
- C1: Model
- D1: Temperature
- E1: Max Tokens
- F1: Generate
Format the header row to make it stand out (bold, background color, etc.).
Step 2: Create the Apps Script Project
Now, let’s create the script that will connect your sheet to OpenAI:
- Click Extensions → Apps Script
- Delete any existing code
- Paste the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Store your OpenAI API key
const OPENAI_API_KEY = 'YOUR_API_KEY_HERE'; // Replace with your actual API key
/**
* Creates a menu item for the Google Sheet
*/
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('OpenAI')
.addItem('Generate Content', 'generateForSelectedRows')
.addItem('About', 'showAbout')
.addToUi();
}
/**
* Shows information about the script
*/
function showAbout() {
const ui = SpreadsheetApp.getUi();
ui.alert(
'OpenAI Integration',
'This script connects Google Sheets to OpenAI\'s API for content generation.\n\n' +
'Created by Blogmines.com',
ui.ButtonSet.OK
);
}
/**
* Generates content for the selected rows
*/
function generateForSelectedRows() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const selectedRange = sheet.getActiveRange();
const startRow = selectedRange.getRow();
const numRows = selectedRange.getNumRows();
// Process each selected row
for (let i = 0; i < numRows; i++) {
const currentRow = startRow + i;
// Skip the header row if selected
if (currentRow === 1) continue;
// Get values from the row
const prompt = sheet.getRange(currentRow, 1).getValue();
if (!prompt) continue; // Skip empty prompts
// Get optional parameters or use defaults
const model = sheet.getRange(currentRow, 3).getValue() || 'gpt-3.5-turbo';
const temperature = sheet.getRange(currentRow, 4).getValue() || 0.7;
const maxTokens = sheet.getRange(currentRow, 5).getValue() || 500;
// Call OpenAI API and write the result
try {
const generatedContent = callOpenAI(prompt, model, temperature, maxTokens);
sheet.getRange(currentRow, 2).setValue(generatedContent);
} catch (error) {
sheet.getRange(currentRow, 2).setValue('Error: ' + error.message);
}
}
}
/**
* Custom function to generate content in a cell
* Example: =GENERATEAI(A2, C2, D2, E2)
*/
function GENERATEAI(prompt, model, temperature, maxTokens) {
// Default values if not provided
model = model || 'gpt-3.5-turbo';
temperature = temperature || 0.7;
maxTokens = maxTokens || 500;
try {
return callOpenAI(prompt, model, temperature, maxTokens);
} catch (error) {
return 'Error: ' + error.message;
}
}
/**
* Call the OpenAI API
*/
function callOpenAI(prompt, model, temperature, maxTokens) {
// Prepare the request
const url = 'https://api.openai.com/v1/chat/completions';
const payload = {
model: model,
messages: [
{
role: "user",
content: prompt
}
],
temperature: temperature,
max_tokens: maxTokens
};
const options = {
method: 'post',
contentType: 'application/json',
headers: {
'Authorization': 'Bearer ' + OPENAI_API_KEY
},
payload: JSON.stringify(payload)
};
// Make the API call
const response = UrlFetchApp.fetch(url, options);
const responseData = JSON.parse(response.getContentText());
// Extract and return the generated content
return responseData.choices[0].message.content.trim();
}
/**
* Add buttons to the "Generate" column
*/
function addGenerateButtons() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const lastRow = Math.max(2, sheet.getLastRow()); // Start from row 2
// Create buttons for each row
for (let row = 2; row <= lastRow; row++) {
// Skip if there's already a button
if (sheet.getRange(row, 6).getValue() === 'Generate') continue;
// Add a "Generate" button
sheet.getRange(row, 6).setValue('Generate')
.setBackground('#4285F4')
.setFontColor('white')
.setHorizontalAlignment('center')
.setVerticalAlignment('middle');
}
}
/**
* Handle clicks on the "Generate" buttons
*/
function onEdit(e) {
const range = e.range;
const sheet = range.getSheet();
// Check if the edit was in the Generate column (column F)
if (range.getColumn() === 6 && range.getValue() === 'Generate' && range.getRow() > 1) {
const row = range.getRow();
// Get values from the row
const prompt = sheet.getRange(row, 1).getValue();
if (!prompt) {
sheet.getRange(row, 2).setValue('Error: No prompt provided');
return;
}
// Get optional parameters or use defaults
const model = sheet.getRange(row, 3).getValue() || 'gpt-3.5-turbo';
const temperature = sheet.getRange(row, 4).getValue() || 0.7;
const maxTokens = sheet.getRange(row, 5).getValue() || 500;
// Show "Generating..." while processing
sheet.getRange(row, 2).setValue('Generating...');
// Call OpenAI API and write the result
try {
const generatedContent = callOpenAI(prompt, model, temperature, maxTokens);
sheet.getRange(row, 2).setValue(generatedContent);
} catch (error) {
sheet.getRange(row, 2).setValue('Error: ' + error.message);
}
}
}
- Replace
'YOUR_API_KEY_HERE'
with your actual OpenAI API key - Save the project with a name like “OpenAI Integration”
Step 3: Test Your Integration
Let’s test the basic functionality:
- Go back to your Google Sheet
- Reload the page (you should see a new “OpenAI” menu)
- In cell A2, enter a prompt like: “Write a short paragraph about cloud computing”
- Leave B2 empty (this is where the generated content will appear)
- In C2, enter: “gpt-3.5-turbo” (or “gpt-4” if you have access)
- In D2, enter: 0.7 (controls creativity, higher = more creative)
- In E2, enter: 150 (maximum length of response)
- Click OpenAI → Generate Content
After a brief moment, you should see AI-generated content appear in cell B2!
Step 4: Add Interactive Buttons (Optional)
To make your sheet more user-friendly, let’s add buttons that trigger generation for individual rows:
- Go back to the Apps Script editor
- Run the
addGenerateButtons
function by:- Select the function from the dropdown at the top
- Click the Run button (play icon)
- When prompted, authorize the script
- Return to your sheet to see the buttons in column F
Now you can click these buttons to generate content for a specific row without using the menu.
Step 5: Use Custom Functions in Cells
You can also use the built-in custom function directly in cells:
- In a new cell (e.g., G2), enter:
=GENERATEAI(A2, C2, D2, E2)
- Press Enter
This will generate content based on the parameters in the referenced cells. The advantage of this approach is that it recalculates when the input cells change.
Practical Applications
Here are some ways you can use this OpenAI integration:
Content Creation
Prompt | Purpose |
---|---|
Write a product description for a blue ceramic coffee mug | E-commerce listings |
Generate 5 email subject lines about our summer sale | Email marketing |
Write a professional LinkedIn post about our company’s 5th anniversary | Social media content |
Data Analysis
Prompt | Purpose |
---|---|
Summarize the following customer feedback: [paste feedback] | Customer insights |
Convert this technical description into simple language: [paste text] | Simplification |
Identify key action items from this meeting transcript: [paste transcript] | Meeting summaries |
Search Engine Optimization
Prompt | Purpose |
---|---|
Generate 10 SEO-friendly blog title ideas about indoor gardening | Content planning |
Write meta descriptions for a webpage about healthy breakfast recipes | SEO optimization |
Create a list of 20 long-tail keywords related to sustainable fashion | Keyword research |
Advanced Customization
Handling Longer Responses
For longer content, you might need to adjust the formatting:
1
2
3
4
5
6
7
8
9
10
// Modify the callOpenAI function:
function callOpenAI(prompt, model, temperature, maxTokens) {
// ... existing code ...
// Format longer responses with line breaks
const content = responseData.choices[0].message.content.trim();
// Properly format paragraphs in Google Sheets
return content.replace(/\n\n/g, "\n");
}
Adding a Progress Indicator
For batch processing, add a progress indicator:
1
2
3
4
5
6
7
8
9
10
function generateForSelectedRows() {
// ... existing code ...
const ui = SpreadsheetApp.getUi();
ui.alert('Processing', `Processing ${numRows} rows. This might take a moment.`, ui.ButtonSet.OK);
// ... process rows ...
ui.alert('Complete', `Successfully processed ${numRows} rows.`, ui.ButtonSet.OK);
}
Rate Limiting
To avoid hitting OpenAI’s rate limits, add a delay between API calls:
1
2
3
4
5
6
7
8
9
10
11
12
function generateForSelectedRows() {
// ... existing code ...
for (let i = 0; i < numRows; i++) {
// ... process row ...
// Add a delay between API calls
if (i < numRows - 1) {
Utilities.sleep(1000); // 1-second delay
}
}
}
Security Best Practices
Protecting Your API Key
Storing your API key directly in the script is convenient but not the most secure method. For better security, use the Properties Service:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Store API key securely
function setApiKey() {
const ui = SpreadsheetApp.getUi();
const response = ui.prompt(
'OpenAI API Key',
'Enter your OpenAI API key (it will be stored securely):',
ui.ButtonSet.OK_CANCEL
);
if (response.getSelectedButton() === ui.Button.OK) {
const apiKey = response.getResponseText();
PropertiesService.getUserProperties().setProperty('OPENAI_API_KEY', apiKey);
ui.alert('Success', 'API key saved successfully.', ui.ButtonSet.OK);
}
}
// Retrieve API key
function getApiKey() {
return PropertiesService.getUserProperties().getProperty('OPENAI_API_KEY');
}
// Modify callOpenAI to use the stored key
function callOpenAI(prompt, model, temperature, maxTokens) {
const apiKey = getApiKey();
if (!apiKey) {
throw new Error('API key not found. Please set up your API key first.');
}
// ... rest of the function using apiKey instead of OPENAI_API_KEY ...
}
Add a menu item to set the API key:
1
2
3
4
5
6
7
8
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('OpenAI')
.addItem('Generate Content', 'generateForSelectedRows')
.addItem('Set API Key', 'setApiKey')
.addItem('About', 'showAbout')
.addToUi();
}
Troubleshooting
Common Errors
- API Key Error: Ensure your OpenAI API key is correct and has sufficient credits
- Timeout Error: For large batches, process fewer rows at once
- Content Policy Violation: Ensure your prompts comply with OpenAI’s content policy
Debugging
Add logging to troubleshoot issues:
1
2
3
4
5
6
7
8
9
10
function callOpenAI(prompt, model, temperature, maxTokens) {
try {
// ... existing code ...
return responseData.choices[0].message.content.trim();
} catch (error) {
console.error('Error calling OpenAI API:', error);
console.error('Response:', response ? response.getContentText() : 'No response');
throw error;
}
}
Conclusion
By connecting Google Sheets to OpenAI’s API, you’ve created a powerful tool for content generation and text processing. This integration allows you to leverage AI capabilities without leaving your spreadsheet, streamlining your workflow and saving valuable time.
The possibilities are virtually endless—from creating marketing copy to summarizing data, analyzing feedback, or generating creative content. As AI models continue to improve, your Google Sheets integration will become even more powerful.
Next Steps
Ready to take your AI integration further? Check out these other tutorials:
- Build a CRUD Web App with Google Apps Script
- Automate Google Sheets with Time-Saving Scripts
- Send Personalized Emails from Google Sheets
Have you used AI in your spreadsheets before? Share your experience or questions in the comments below!
Questions? Corrections? Issues and pull requests are always welcome.