Gemini × Google Apps Script for Workflow Automation
Google Apps Script (GAS) gives you programmatic access to every corner of Google Workspace — Sheets, Gmail, Docs, Calendar, Drive, and more. Pair it with the Gemini API and you unlock a new tier of automation: AI-powered data analysis in spreadsheets, automatic email triage and summarization, draft generation for documents, and much more — all without spinning up a single server.
Why GAS + Gemini?
The combination works so well because of three things.
First, zero infrastructure. Apps Script runs on Google's servers. There's nothing to deploy, no containers to manage, and no cold starts to worry about. You open the script editor and start writing.
Second, native Workspace integration. GAS has built-in services for Gmail, Sheets, Docs, Calendar, Drive, Forms, and Slides. You can read a spreadsheet, send the data to Gemini for analysis, and write the results back — all in a few lines of code.
Third, trigger-based automation. Time-driven triggers, edit triggers, and form-submit triggers let you run scripts on autopilot. A Monday-morning sales analysis, a nightly inbox digest, or an instant document draft whenever a new row appears in a sheet — all are straightforward to set up.
Getting Started
1. Get a Gemini API Key
Head to Google AI Studio (https://aistudio.google.com) and create an API key. Store it safely in script properties rather than hard-coding it.
2. Create an Apps Script Project
Open any Google Spreadsheet, go to Extensions → Apps Script, and you'll land in the script editor. First, save your API key to script properties:
// Run once to store your API key
function setApiKey() {
const props = PropertiesService.getScriptProperties();
props.setProperty('GEMINI_API_KEY', 'your-api-key-here');
}3. Build a Reusable Gemini Helper
This function handles the API call and can be shared across all your workflows:
function callGemini(prompt, model = 'gemini-2.5-flash') {
const apiKey = PropertiesService.getScriptProperties()
.getProperty('GEMINI_API_KEY');
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: {
temperature: 0.7,
maxOutputTokens: 2048
}
};
const response = UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload),
muteHttpExceptions: true
});
const json = JSON.parse(response.getContentText());
if (json.candidates && json.candidates[0]) {
return json.candidates[0].content.parts[0].text;
}
throw new Error('Gemini API error: ' + response.getContentText());
}Practical Workflows
Workflow 1: Auto-Analyze Spreadsheet Data
Feed sales figures or survey responses into Gemini and get back a structured analysis — automatically.
function analyzeSalesData() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Sales Data');
const data = sheet.getDataRange().getValues();
const headers = data[0];
const rows = data.slice(1);
const csvText = [headers.join(','),
...rows.map(row => row.join(','))
].join('\n');
const prompt = `Analyze the following sales data and provide:
1. Overall trends
2. Category performance highlights
3. Areas that need improvement
4. Concrete action items
Data:
${csvText}`;
const analysis = callGemini(prompt);
let resultSheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('AI Analysis');
if (!resultSheet) {
resultSheet = SpreadsheetApp.getActiveSpreadsheet()
.insertSheet('AI Analysis');
}
resultSheet.getRange('A1').setValue('Analysis Date');
resultSheet.getRange('B1').setValue(new Date());
resultSheet.getRange('A3').setValue(analysis);
}Workflow 2: Summarize Unread Emails
Run this every morning and you'll start your day with a prioritized snapshot of your inbox.
function summarizeUnreadEmails() {
const threads = GmailApp.search('is:unread', 0, 20);
const summaries = [];
for (const thread of threads) {
const messages = thread.getMessages();
const latest = messages[messages.length - 1];
const prompt = `Summarize this email in 1-2 sentences and rate
its urgency as high, medium, or low.
Subject: ${latest.getSubject()}
From: ${latest.getFrom()}
Body: ${latest.getPlainBody().substring(0, 1000)}
Respond in JSON: {"summary": "...", "urgency": "high|medium|low"}`;
try {
const result = callGemini(prompt);
const parsed = JSON.parse(
result.replace(/```json\n?/g, '').replace(/```/g, '')
);
summaries.push([
new Date(),
latest.getFrom(),
latest.getSubject(),
parsed.summary,
parsed.urgency
]);
} catch (e) {
summaries.push([
new Date(),
latest.getFrom(),
latest.getSubject(),
'Summary failed',
'-'
]);
}
}
if (summaries.length > 0) {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Email Digest')
|| SpreadsheetApp.getActiveSpreadsheet()
.insertSheet('Email Digest');
const lastRow = sheet.getLastRow();
sheet.getRange(lastRow + 1, 1, summaries.length, 5)
.setValues(summaries);
}
}Workflow 3: Generate Document Drafts
List your topics in a spreadsheet and let Gemini produce first drafts as Google Docs.
function generateDocumentDraft() {
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Document Requests');
const data = sheet.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
const [topic, audience, length, status] = data[i];
if (status === 'Done') continue;
const prompt = `Write a business document draft on the
following topic.
Topic: ${topic}
Target audience: ${audience}
Approximate length: ${length}
Use clear headings and a professional tone.`;
const draft = callGemini(prompt);
const doc = DocumentApp.create(`[AI Draft] ${topic}`);
doc.getBody().setText(draft);
sheet.getRange(i + 1, 4).setValue('Done');
sheet.getRange(i + 1, 5).setValue(doc.getUrl());
}
}Setting Up Triggers
Use GAS triggers to run your workflows hands-free.
function createTriggers() {
// Summarize emails every morning at 8 AM
ScriptApp.newTrigger('summarizeUnreadEmails')
.timeBased()
.everyDays(1)
.atHour(8)
.create();
// Run sales analysis every Monday at 9 AM
ScriptApp.newTrigger('analyzeSalesData')
.timeBased()
.onWeekDay(ScriptApp.WeekDay.MONDAY)
.atHour(9)
.create();
}You can also configure triggers through the Apps Script editor UI under Triggers in the left sidebar. For complex scheduling, the programmatic approach gives you more flexibility.
Error Handling and Rate Limits
In production, always wrap API calls with retry logic:
function callGeminiWithRetry(prompt, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return callGemini(prompt);
} catch (e) {
if (attempt === maxRetries - 1) throw e;
Utilities.sleep(Math.pow(2, attempt) * 1000);
}
}
}Keep in mind that free Google accounts have a 6-minute execution limit per run and a 90-minute daily cap. If you're processing large datasets, split the work into batches and persist progress in script properties so subsequent runs pick up where the last one left off.
Security Best Practices
Never hard-code your API key. Always use PropertiesService.getScriptProperties(). Be aware that anyone with editor access to the script can read those properties, so restrict sharing accordingly.
Before sending sensitive data to the Gemini API, check your organization's data policies. Workspace admins may have restrictions on external API calls from Apps Script. For enterprise use, consider routing requests through Vertex AI with IAM-based authentication instead of a plain API key.
Wrapping Up
Google Apps Script paired with the Gemini API is one of the lowest-friction ways to bring AI into your daily workflows. No servers, no deployment pipelines — just a script editor and a few dozen lines of code. Start with a single workflow, see the time savings add up, and expand from there.