Advanced Google Sheets Automation for Business Operations (2025 Guide)
Google Sheets is more than just a spreadsheet tool—it's a powerful automation platform that can transform your business operations. This comprehensive guide covers advanced automation techniques using Google Apps Script, triggers, integrations, and workflows.
Why Automate Google Sheets?
Time Savings Example:
Manual Process (Daily):
- Import data from 5 sources: 30 min
- Format and clean data: 20 min
- Generate reports: 25 min
- Send to stakeholders: 10 min
Total: 85 minutes/day = 7 hours/week = 364 hours/year
Automated Process:
- Setup time: 8 hours (one-time)
- Daily runtime: 0 minutes (automatic)
- Maintenance: 2 hours/month = 24 hours/year
Annual savings: 340 hours (8.5 work weeks!)
ROI: 1,321% in first year
Business Impact:
✅ Eliminate manual data entry
✅ Reduce human errors by 95%
✅ Real-time data updates
✅ Automatic report generation
✅ Instant notifications and alerts
✅ Seamless integrations
✅ Scalable processes
✅ Cost-effective (no additional licenses)
Table of Contents
- Google Apps Script Basics
- Data Import Automation
- Report Generation
- Email Automation
- Form Processing
- Dashboard Creation
- Integration with Google Workspace
- External API Integrations
- Triggers and Scheduling
- Add-ons and Extensions
- Real-World Business Workflows
- Best Practices and Security
Google Apps Script Basics
What is Google Apps Script?
Google Apps Script is JavaScript-based cloud scripting platform that lets you:
- Automate Google Sheets operations
- Connect to other Google services
- Build custom functions and menus
- Create web apps and APIs
- Integrate with external services
Getting Started
Opening the Script Editor:
Method 1: From Google Sheets
1. Open your spreadsheet
2. Click Extensions → Apps Script
3. Script editor opens in new tab
Method 2: Direct Access
1. Go to script.google.com
2. Click "New Project"
3. Start coding
Your First Script
Example: Hello World:
function myFirstFunction() {
// Get active spreadsheet
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getActiveSheet();
// Write to cell A1
sheet.getRange("A1").setValue("Hello, World!");
// Show alert
SpreadsheetApp.getUi().alert("Script completed!");
}
Running the Script:
1. Save the script (Ctrl+S / Cmd+S)
2. Click "Run" button
3. Authorize the script (first time only)
4. Check your spreadsheet
Basic Apps Script Concepts
1. Accessing Spreadsheets:
// Get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get spreadsheet by ID
var ss = SpreadsheetApp.openById("YOUR_SPREADSHEET_ID");
// Get spreadsheet by URL
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/...");
2. Working with Sheets:
// Get active sheet
var sheet = ss.getActiveSheet();
// Get sheet by name
var sheet = ss.getSheetByName("Sales Data");
// Create new sheet
var newSheet = ss.insertSheet("New Sheet");
// Get all sheets
var sheets = ss.getSheets();
3. Reading Data:
// Get single cell value
var value = sheet.getRange("A1").getValue();
// Get range of values
var values = sheet.getRange("A1:D10").getValues();
// Get entire column
var columnData = sheet.getRange("A:A").getValues();
// Get last row with data
var lastRow = sheet.getLastRow();
4. Writing Data:
// Write single value
sheet.getRange("A1").setValue("New Value");
// Write multiple values (2D array)
var data = [
["Name", "Age", "City"],
["John", 30, "New York"],
["Jane", 25, "Boston"]
];
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
// Append row to end
sheet.appendRow(["New", "Row", "Data"]);
5. Formatting:
// Set background color
sheet.getRange("A1:D1").setBackground("#4285F4");
// Set font properties
sheet.getRange("A1:D1")
.setFontWeight("bold")
.setFontSize(12)
.setFontColor("#FFFFFF");
// Number formatting
sheet.getRange("B2:B100").setNumberFormat("$#,##0.00");
// Date formatting
sheet.getRange("C2:C100").setNumberFormat("MM/DD/YYYY");
Custom Functions
Creating Custom Formulas:
/**
* Calculate profit margin
* @param {number} revenue Total revenue
* @param {number} cost Total cost
* @return {number} Profit margin as percentage
* @customfunction
*/
function PROFIT_MARGIN(revenue, cost) {
if (revenue == 0) return 0;
return ((revenue - cost) / revenue) * 100;
}
// Usage in sheet: =PROFIT_MARGIN(A2, B2)
Advanced Custom Function:
/**
* Convert currency using live exchange rates
* @param {number} amount Amount to convert
* @param {string} from Source currency (e.g., "USD")
* @param {string} to Target currency (e.g., "EUR")
* @return {number} Converted amount
* @customfunction
*/
function CONVERT_CURRENCY(amount, from, to) {
if (!amount || !from || !to) return "";
// Use exchange rate API
var url = `https://api.exchangerate-api.com/v4/latest/${from}`;
var response = UrlFetchApp.fetch(url);
var data = JSON.parse(response.getContentText());
var rate = data.rates[to];
return amount * rate;
}
// Usage: =CONVERT_CURRENCY(100, "USD", "EUR")
Custom Menus
Adding Menu to Spreadsheet:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('📊 Business Tools')
.addItem('Generate Report', 'generateReport')
.addItem('Send Email Summary', 'sendEmailSummary')
.addSeparator()
.addSubMenu(ui.createMenu('Data Import')
.addItem('Import from Form', 'importFormData')
.addItem('Import from API', 'importAPIData'))
.addSeparator()
.addItem('Settings', 'showSettings')
.addToUi();
}
Data Import Automation
Import from Google Forms
Automatic Form Response Processing:
/**
* Process new form submissions automatically
* Triggered when form is submitted
*/
function onFormSubmit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var responses = e.values; // Form responses array
// Get the last row (new submission)
var lastRow = sheet.getLastRow();
// Add timestamp
var timestamp = new Date();
sheet.getRange(lastRow, 1).setValue(timestamp);
// Add unique ID
var uniqueId = "FORM-" + timestamp.getTime();
sheet.getRange(lastRow, 2).setValue(uniqueId);
// Calculate status based on criteria
var score = responses[5]; // Assuming score is in column 6
var status = score >= 80 ? "Approved" : "Review Required";
sheet.getRange(lastRow, 10).setValue(status);
// Format row based on status
if (status === "Approved") {
sheet.getRange(lastRow, 1, 1, sheet.getLastColumn())
.setBackground("#D9EAD3"); // Light green
} else {
sheet.getRange(lastRow, 1, 1, sheet.getLastColumn())
.setBackground("#FCE5CD"); // Light orange
}
// Send notification email
sendFormNotification(responses, status);
// Log the processing
Logger.log("Form submitted and processed: " + uniqueId);
}
function sendFormNotification(responses, status) {
var email = responses[2]; // Submitter email
var name = responses[1]; // Submitter name
var subject = "Form Submission Received - " + status;
var body = `Hello ${name},\n\n` +
`Your form submission has been received.\n` +
`Status: ${status}\n\n` +
`We'll be in touch soon.\n\n` +
`Best regards,\nYour Team`;
GmailApp.sendEmail(email, subject, body);
}
Setup Instructions:
1. Open your Google Form
2. Click Responses tab
3. Click the Sheets icon to create linked spreadsheet
4. In the spreadsheet, go to Extensions → Apps Script
5. Paste the script above
6. Save the script
7. Run onFormSubmit once to authorize
8. Done! Now runs automatically on each submission
Import from Other Sheets
Pull Data from Multiple Sheets:
/**
* Consolidate data from multiple sheets
*/
function consolidateData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var masterSheet = ss.getSheetByName("Master Data");
// Clear existing data (keep headers)
var lastRow = masterSheet.getLastRow();
if (lastRow > 1) {
masterSheet.getRange(2, 1, lastRow - 1, masterSheet.getLastColumn()).clear();
}
// List of source sheets
var sourceSheets = ["Sales Q1", "Sales Q2", "Sales Q3", "Sales Q4"];
var currentRow = 2; // Start after header
sourceSheets.forEach(function(sheetName) {
var sourceSheet = ss.getSheetByName(sheetName);
if (sourceSheet) {
// Get data (skip header)
var sourceData = sourceSheet.getRange(2, 1,
sourceSheet.getLastRow() - 1,
sourceSheet.getLastColumn()
).getValues();
// Write to master sheet
if (sourceData.length > 0) {
masterSheet.getRange(currentRow, 1,
sourceData.length,
sourceData[0].length
).setValues(sourceData);
currentRow += sourceData.length;
}
Logger.log("Imported " + sourceData.length + " rows from " + sheetName);
}
});
SpreadsheetApp.getUi().alert("Data consolidation complete! " +
(currentRow - 2) + " rows imported.");
}
Import from External URLs
Import CSV from URL:
/**
* Import CSV data from external URL
*/
function importCSVFromURL() {
var url = "https://example.com/data/sales.csv";
var sheet = SpreadsheetApp.getActiveSheet();
try {
// Fetch CSV data
var response = UrlFetchApp.fetch(url);
var csvContent = response.getContentText();
// Parse CSV
var csvData = Utilities.parseCsv(csvContent);
// Clear existing data
sheet.clear();
// Write data to sheet
sheet.getRange(1, 1, csvData.length, csvData[0].length)
.setValues(csvData);
// Format header row
sheet.getRange(1, 1, 1, csvData[0].length)
.setBackground("#4285F4")
.setFontColor("#FFFFFF")
.setFontWeight("bold");
// Auto-resize columns
for (var i = 1; i <= csvData[0].length; i++) {
sheet.autoResizeColumn(i);
}
Logger.log("Successfully imported " + csvData.length + " rows");
} catch (error) {
Logger.log("Error importing CSV: " + error);
SpreadsheetApp.getUi().alert("Error: " + error);
}
}
Import from Web Scraping
Scrape Web Data:
/**
* Import table data from website
*/
function scrapeWebData() {
var url = "https://example.com/data-table";
var sheet = SpreadsheetApp.getActiveSheet();
try {
// Fetch HTML
var response = UrlFetchApp.fetch(url);
var html = response.getContentText();
// Parse HTML (basic example)
// For complex parsing, consider using external API or service
var matches = html.match(/<table[\s\S]*?<\/table>/gi);
if (matches && matches.length > 0) {
// Extract first table
var tableHtml = matches[0];
// Extract rows
var rows = tableHtml.match(/<tr[\s\S]*?<\/tr>/gi);
var data = [];
rows.forEach(function(row) {
var cells = row.match(/<t[dh][\s\S]*?>([\s\S]*?)<\/t[dh]>/gi);
var rowData = [];
if (cells) {
cells.forEach(function(cell) {
// Remove HTML tags
var text = cell.replace(/<[^>]*>/g, '').trim();
rowData.push(text);
});
data.push(rowData);
}
});
// Write to sheet
if (data.length > 0) {
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
Logger.log("Imported " + data.length + " rows from web");
}
}
} catch (error) {
Logger.log("Error scraping web: " + error);
}
}
Import from APIs
REST API Data Import:
/**
* Import data from REST API
* Example: Weather data
*/
function importFromAPI() {
var apiKey = "YOUR_API_KEY";
var city = "New York";
var url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=imperial`;
var sheet = SpreadsheetApp.getActiveSheet();
try {
// Make API request
var response = UrlFetchApp.fetch(url);
var data = JSON.parse(response.getContentText());
// Extract relevant data
var weather = [
[new Date(), city, data.main.temp, data.main.humidity, data.weather[0].description]
];
// Append to sheet
sheet.appendRow(weather[0]);
Logger.log("Weather data imported successfully");
} catch (error) {
Logger.log("API import error: " + error);
}
}
/**
* Import multiple records from API
*/
function importBulkAPIData() {
var apiUrl = "https://api.example.com/data";
var apiKey = "YOUR_API_KEY";
var sheet = SpreadsheetApp.getActiveSheet();
var options = {
'method': 'get',
'headers': {
'Authorization': 'Bearer ' + apiKey,
'Content-Type': 'application/json'
}
};
try {
var response = UrlFetchApp.fetch(apiUrl, options);
var jsonData = JSON.parse(response.getContentText());
// Convert JSON to 2D array
var data = [];
jsonData.items.forEach(function(item) {
data.push([
item.id,
item.name,
item.value,
item.date,
item.status
]);
});
// Write to sheet
if (data.length > 0) {
var startRow = sheet.getLastRow() + 1;
sheet.getRange(startRow, 1, data.length, data[0].length).setValues(data);
Logger.log("Imported " + data.length + " records from API");
}
} catch (error) {
Logger.log("Error: " + error);
}
}
Report Generation
Automatic Summary Reports
Daily Sales Report:
/**
* Generate daily sales summary
*/
function generateDailySalesReport() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheetByName("Sales Data");
var reportSheet = ss.getSheetByName("Daily Report");
// If report sheet doesn't exist, create it
if (!reportSheet) {
reportSheet = ss.insertSheet("Daily Report");
}
// Clear previous report
reportSheet.clear();
// Get today's date
var today = new Date();
today.setHours(0, 0, 0, 0);
// Get all sales data
var data = dataSheet.getDataRange().getValues();
var headers = data[0];
var salesData = data.slice(1);
// Find date and amount columns
var dateCol = headers.indexOf("Date");
var amountCol = headers.indexOf("Amount");
var productCol = headers.indexOf("Product");
var salesPersonCol = headers.indexOf("Sales Person");
// Filter today's sales
var todaySales = salesData.filter(function(row) {
var rowDate = new Date(row[dateCol]);
rowDate.setHours(0, 0, 0, 0);
return rowDate.getTime() === today.getTime();
});
// Calculate summary
var totalSales = 0;
var salesByProduct = {};
var salesByPerson = {};
todaySales.forEach(function(row) {
var amount = row[amountCol];
var product = row[productCol];
var person = row[salesPersonCol];
totalSales += amount;
// Group by product
if (!salesByProduct[product]) {
salesByProduct[product] = 0;
}
salesByProduct[product] += amount;
// Group by sales person
if (!salesByPerson[person]) {
salesByPerson[person] = 0;
}
salesByPerson[person] += amount;
});
// Build report
var report = [];
// Title
report.push(["Daily Sales Report"]);
report.push(["Date: " + Utilities.formatDate(today, Session.getScriptTimeZone(), "MM/dd/yyyy")]);
report.push([""]);
// Summary
report.push(["📊 Summary"]);
report.push(["Total Sales", totalSales]);
report.push(["Number of Transactions", todaySales.length]);
report.push(["Average Transaction", todaySales.length > 0 ? totalSales / todaySales.length : 0]);
report.push([""]);
// Sales by Product
report.push(["📦 Sales by Product"]);
report.push(["Product", "Amount"]);
Object.keys(salesByProduct).forEach(function(product) {
report.push([product, salesByProduct[product]]);
});
report.push([""]);
// Sales by Person
report.push(["👤 Sales by Person"]);
report.push(["Sales Person", "Amount"]);
Object.keys(salesByPerson).forEach(function(person) {
report.push([person, salesByPerson[person]]);
});
// Write report to sheet
if (report.length > 0) {
reportSheet.getRange(1, 1, report.length, 2).setValues(report);
// Format report
reportSheet.getRange("A1:B1").setFontSize(16).setFontWeight("bold");
reportSheet.getRange("A4").setFontWeight("bold");
reportSheet.getRange("A9").setFontWeight("bold");
reportSheet.getRange("A10:B10").setBackground("#E8F0FE").setFontWeight("bold");
// Format currency
reportSheet.getRange("B5:B7").setNumberFormat("$#,##0.00");
reportSheet.getRange("B11:B" + (11 + Object.keys(salesByProduct).length - 1)).setNumberFormat("$#,##0.00");
// Auto-resize
reportSheet.autoResizeColumns(1, 2);
}
Logger.log("Daily sales report generated");
}
Monthly Report with Charts
Create Report with Charts:
/**
* Generate monthly report with embedded charts
*/
function generateMonthlyReport() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheetByName("Sales Data");
var reportSheet = ss.getSheetByName("Monthly Report");
if (!reportSheet) {
reportSheet = ss.insertSheet("Monthly Report");
}
reportSheet.clear();
// Calculate monthly summary
var data = dataSheet.getDataRange().getValues();
var monthlySummary = calculateMonthlySummary(data);
// Write summary to sheet
var summaryData = [["Month", "Revenue", "Transactions", "Avg Transaction"]];
Object.keys(monthlySummary).forEach(function(month) {
var stats = monthlySummary[month];
summaryData.push([
month,
stats.revenue,
stats.count,
stats.revenue / stats.count
]);
});
reportSheet.getRange(1, 1, summaryData.length, 4).setValues(summaryData);
// Format header
reportSheet.getRange("A1:D1")
.setBackground("#4285F4")
.setFontColor("#FFFFFF")
.setFontWeight("bold");
// Format currency
reportSheet.getRange(2, 2, summaryData.length - 1, 1).setNumberFormat("$#,##0.00");
reportSheet.getRange(2, 4, summaryData.length - 1, 1).setNumberFormat("$#,##0.00");
// Create chart
var chart = reportSheet.newChart()
.setChartType(Charts.ChartType.COLUMN)
.addRange(reportSheet.getRange("A1:B" + summaryData.length))
.setPosition(summaryData.length + 2, 1, 0, 0)
.setOption('title', 'Monthly Revenue')
.setOption('width', 600)
.setOption('height', 400)
.setOption('legend', {position: 'none'})
.setOption('vAxis', {title: 'Revenue ($)', format: '$#,###'})
.setOption('hAxis', {title: 'Month'})
.build();
reportSheet.insertChart(chart);
Logger.log("Monthly report with chart generated");
}
function calculateMonthlySummary(data) {
var headers = data[0];
var salesData = data.slice(1);
var dateCol = headers.indexOf("Date");
var amountCol = headers.indexOf("Amount");
var summary = {};
salesData.forEach(function(row) {
var date = new Date(row[dateCol]);
var monthKey = Utilities.formatDate(date, Session.getScriptTimeZone(), "yyyy-MM");
var amount = row[amountCol];
if (!summary[monthKey]) {
summary[monthKey] = {revenue: 0, count: 0};
}
summary[monthKey].revenue += amount;
summary[monthKey].count++;
});
return summary;
}
Email Automation
Send Automated Reports via Email
Email Daily Report:
/**
* Send daily report via email
*/
function sendDailyReport() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var reportSheet = ss.getSheetByName("Daily Report");
// Generate report first
generateDailySalesReport();
// Get report data
var reportData = reportSheet.getDataRange().getValues();
// Build email body
var emailBody = "<html><body>";
emailBody += "<h2>📊 Daily Sales Report</h2>";
emailBody += "<p><strong>Date:</strong> " + Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy") + "</p>";
// Create HTML table
emailBody += "<table border='1' cellpadding='8' cellspacing='0' style='border-collapse: collapse;'>";
reportData.forEach(function(row, index) {
emailBody += "<tr>";
row.forEach(function(cell) {
if (index === 0 || cell.toString().includes("Summary") || cell.toString().includes("Product") || cell.toString().includes("Person")) {
emailBody += "<th style='background-color: #4285F4; color: white;'>" + cell + "</th>";
} else {
var displayValue = cell;
if (typeof cell === 'number' && cell > 100) {
displayValue = "$" + cell.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
}
emailBody += "<td>" + displayValue + "</td>";
}
});
emailBody += "</tr>";
});
emailBody += "</table>";
emailBody += "<p><em>Generated automatically by Google Sheets</em></p>";
emailBody += "</body></html>";
// Send email
var recipients = "team@company.com, manager@company.com";
var subject = "Daily Sales Report - " + Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy");
MailApp.sendEmail({
to: recipients,
subject: subject,
htmlBody: emailBody
});
Logger.log("Daily report emailed to: " + recipients);
}
Send Alerts Based on Conditions
Inventory Alert System:
/**
* Check inventory and send alerts for low stock
*/
function checkInventoryAlerts() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var inventorySheet = ss.getSheetByName("Inventory");
var data = inventorySheet.getDataRange().getValues();
var headers = data[0];
var inventoryData = data.slice(1);
var productCol = headers.indexOf("Product");
var quantityCol = headers.indexOf("Quantity");
var minStockCol = headers.indexOf("Min Stock Level");
var supplierCol = headers.indexOf("Supplier Email");
var lowStockItems = [];
inventoryData.forEach(function(row, index) {
var product = row[productCol];
var quantity = row[quantityCol];
var minStock = row[minStockCol];
var supplier = row[supplierCol];
if (quantity <= minStock) {
lowStockItems.push({
product: product,
quantity: quantity,
minStock: minStock,
supplier: supplier,
row: index + 2 // Account for header and 0-index
});
// Highlight row in red
inventorySheet.getRange(index + 2, 1, 1, headers.length)
.setBackground("#F4CCCC");
}
});
// Send alert if low stock items found
if (lowStockItems.length > 0) {
sendLowStockAlert(lowStockItems);
}
Logger.log("Inventory check complete. Low stock items: " + lowStockItems.length);
}
function sendLowStockAlert(items) {
var emailBody = "<html><body>";
emailBody += "<h2>⚠️ Low Inventory Alert</h2>";
emailBody += "<p>The following items are at or below minimum stock levels:</p>";
emailBody += "<table border='1' cellpadding='8' cellspacing='0' style='border-collapse: collapse;'>";
emailBody += "<tr style='background-color: #EA4335; color: white;'>";
emailBody += "<th>Product</th><th>Current Quantity</th><th>Min Stock</th><th>Supplier</th>";
emailBody += "</tr>";
items.forEach(function(item) {
emailBody += "<tr>";
emailBody += "<td>" + item.product + "</td>";
emailBody += "<td>" + item.quantity + "</td>";
emailBody += "<td>" + item.minStock + "</td>";
emailBody += "<td>" + item.supplier + "</td>";
emailBody += "</tr>";
});
emailBody += "</table>";
emailBody += "<p><strong>Action Required:</strong> Please reorder these items immediately.</p>";
emailBody += "</body></html>";
var recipients = "purchasing@company.com, manager@company.com";
var subject = "🚨 URGENT: Low Inventory Alert (" + items.length + " items)";
MailApp.sendEmail({
to: recipients,
subject: subject,
htmlBody: emailBody
});
}
Personalized Email Campaigns
Send Personalized Emails from Sheet:
/**
* Send personalized emails to customers
*/
function sendPersonalizedEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var customerSheet = ss.getSheetByName("Customers");
var data = customerSheet.getDataRange().getValues();
var headers = data[0];
var customers = data.slice(1);
var nameCol = headers.indexOf("Name");
var emailCol = headers.indexOf("Email");
var companyCol = headers.indexOf("Company");
var lastPurchaseCol = headers.indexOf("Last Purchase");
var sentCol = headers.indexOf("Email Sent");
var emailsSent = 0;
var quotaRemaining = MailApp.getRemainingDailyQuota();
customers.forEach(function(row, index) {
var emailSent = row[sentCol];
// Skip if already sent
if (emailSent === "Yes") {
return;
}
// Check quota
if (emailsSent >= quotaRemaining) {
Logger.log("Daily email quota reached");
return;
}
var name = row[nameCol];
var email = row[emailCol];
var company = row[companyCol];
var lastPurchase = row[lastPurchaseCol];
// Create personalized email
var subject = name + ", special offer just for " + company;
var body = `
<html><body>
<h2>Hello ${name},</h2>
<p>We noticed you last purchased from us on ${Utilities.formatDate(new Date(lastPurchase), Session.getScriptTimeZone(), "MM/dd/yyyy")}.</p>
<p>As a valued customer of ${company}, we'd like to offer you an exclusive 20% discount on your next order!</p>
<p><strong>Use code:</strong> <span style="background: #FBBC04; padding: 5px 10px; font-size: 16px;">WELCOME20</span></p>
<p>This offer expires in 7 days.</p>
<p>Best regards,<br>Your Sales Team</p>
</body></html>
`;
try {
MailApp.sendEmail({
to: email,
subject: subject,
htmlBody: body
});
// Mark as sent
customerSheet.getRange(index + 2, sentCol + 1).setValue("Yes");
customerSheet.getRange(index + 2, sentCol + 2).setValue(new Date());
emailsSent++;
Logger.log("Email sent to: " + email);
} catch (error) {
Logger.log("Error sending to " + email + ": " + error);
}
});
SpreadsheetApp.getUi().alert("Campaign complete! Sent " + emailsSent + " emails.");
}
Form Processing Automation
Advanced Form Response Handling
Multi-Step Form Processing:
/**
* Advanced form response processing with workflow
*/
function processAdvancedFormSubmission(e) {
var responses = e.values;
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
// Extract form data
var timestamp = responses[0];
var email = responses[1];
var name = responses[2];
var requestType = responses[3];
var priority = responses[4];
var description = responses[5];
// Generate ticket ID
var ticketId = "TKT-" + Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyyMMdd") + "-" + lastRow;
// Add ticket ID to sheet
sheet.getRange(lastRow, sheet.getLastColumn() + 1).setValue(ticketId);
// Assign based on request type
var assignedTo = assignTicket(requestType);
sheet.getRange(lastRow, sheet.getLastColumn() + 1).setValue(assignedTo);
// Set status
var status = "New";
sheet.getRange(lastRow, sheet.getLastColumn() + 1).setValue(status);
// Calculate SLA deadline based on priority
var slaHours = priority === "High" ? 4 : priority === "Medium" ? 24 : 72;
var deadline = new Date(timestamp);
deadline.setHours(deadline.getHours() + slaHours);
sheet.getRange(lastRow, sheet.getLastColumn() + 1).setValue(deadline);
// Send confirmation to submitter
sendTicketConfirmation(email, name, ticketId, assignedTo, deadline);
// Notify assigned person
notifyAssignedPerson(assignedTo, ticketId, name, requestType, priority, description);
// Add to task tracking system
createTaskInProjectSheet(ticketId, requestType, priority, assignedTo, deadline);
// Format row based on priority
var color = priority === "High" ? "#EA4335" : priority === "Medium" ? "#FBBC04" : "#34A853";
sheet.getRange(lastRow, 1, 1, sheet.getLastColumn())
.setBorder(true, true, true, true, false, false, color, SpreadsheetApp.BorderStyle.SOLID_MEDIUM);
Logger.log("Processed form submission: " + ticketId);
}
function assignTicket(requestType) {
var assignments = {
"Technical Support": "tech@company.com",
"Billing Question": "billing@company.com",
"Sales Inquiry": "sales@company.com",
"General": "support@company.com"
};
return assignments[requestType] || "support@company.com";
}
function sendTicketConfirmation(email, name, ticketId, assignedTo, deadline) {
var subject = "Ticket Created: " + ticketId;
var body = `
<html><body>
<h2>Hello ${name},</h2>
<p>Your support ticket has been created and assigned.</p>
<p><strong>Ticket ID:</strong> ${ticketId}<br>
<strong>Assigned to:</strong> ${assignedTo}<br>
<strong>SLA Deadline:</strong> ${Utilities.formatDate(deadline, Session.getScriptTimeZone(), "MM/dd/yyyy HH:mm")}</p>
<p>We'll respond within the SLA timeframe. You can reply to this email for any updates.</p>
<p>Best regards,<br>Support Team</p>
</body></html>
`;
MailApp.sendEmail({
to: email,
subject: subject,
htmlBody: body
});
}
function notifyAssignedPerson(assignedTo, ticketId, customerName, requestType, priority, description) {
var subject = "New Ticket Assigned: " + ticketId + " [" + priority + " Priority]";
var body = `
<html><body>
<h2>New Ticket Assigned to You</h2>
<p><strong>Ticket ID:</strong> ${ticketId}<br>
<strong>Customer:</strong> ${customerName}<br>
<strong>Type:</strong> ${requestType}<br>
<strong>Priority:</strong> ${priority}</p>
<p><strong>Description:</strong><br>
${description}</p>
<p><a href="${SpreadsheetApp.getActiveSpreadsheet().getUrl()}">View in Spreadsheet</a></p>
</body></html>
`;
MailApp.sendEmail({
to: assignedTo,
subject: subject,
htmlBody: body
});
}
Dashboard Creation
Real-Time Dashboard
Create Auto-Updating Dashboard:
/**
* Create executive dashboard with real-time metrics
*/
function createExecutiveDashboard() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dashboardSheet = ss.getSheetByName("Dashboard");
if (!dashboardSheet) {
dashboardSheet = ss.insertSheet("Dashboard");
}
dashboardSheet.clear();
// Get source data
var salesSheet = ss.getSheetByName("Sales Data");
var inventorySheet = ss.getSheetByName("Inventory");
var customerSheet = ss.getSheetByName("Customers");
// Calculate KPIs
var kpis = calculateKPIs(salesSheet, inventorySheet, customerSheet);
// Build dashboard layout
var row = 1;
// Title
dashboardSheet.getRange(row, 1).setValue("📊 Executive Dashboard");
dashboardSheet.getRange(row, 1).setFontSize(20).setFontWeight("bold");
row += 2;
// Last Updated
dashboardSheet.getRange(row, 1).setValue("Last Updated:");
dashboardSheet.getRange(row, 2).setValue(new Date());
dashboardSheet.getRange(row, 2).setNumberFormat("MM/dd/yyyy HH:mm:ss");
row += 2;
// KPI Cards
var kpiData = [
["📈 Today's Revenue", kpis.todayRevenue, kpis.revenueChange],
["💰 Monthly Revenue", kpis.monthRevenue, kpis.monthlyGrowth],
["📦 Total Orders", kpis.totalOrders, kpis.ordersChange],
["👥 Active Customers", kpis.activeCustomers, kpis.customerGrowth],
["📊 Avg Order Value", kpis.avgOrderValue, kpis.aovChange],
["⚠️ Low Stock Items", kpis.lowStockCount, ""]
];
kpiData.forEach(function(kpi) {
dashboardSheet.getRange(row, 1).setValue(kpi[0]);
dashboardSheet.getRange(row, 2).setValue(kpi[1]);
dashboardSheet.getRange(row, 3).setValue(kpi[2]);
// Format
dashboardSheet.getRange(row, 1).setFontWeight("bold");
dashboardSheet.getRange(row, 2).setNumberFormat("$#,##0.00");
// Color code changes
if (kpi[2]) {
var color = kpi[2].toString().includes("+") || kpi[2] > 0 ? "#34A853" : "#EA4335";
dashboardSheet.getRange(row, 3).setFontColor(color).setFontWeight("bold");
}
row++;
});
row += 2;
// Top Products
dashboardSheet.getRange(row, 1).setValue("🏆 Top 5 Products");
dashboardSheet.getRange(row, 1).setFontSize(14).setFontWeight("bold");
row++;
kpis.topProducts.forEach(function(product) {
dashboardSheet.getRange(row, 1).setValue(product.name);
dashboardSheet.getRange(row, 2).setValue(product.revenue);
dashboardSheet.getRange(row, 2).setNumberFormat("$#,##0.00");
row++;
});
// Auto-resize columns
dashboardSheet.autoResizeColumns(1, 3);
// Add data refresh button (via custom menu)
addRefreshButton();
Logger.log("Dashboard created");
}
function calculateKPIs(salesSheet, inventorySheet, customerSheet) {
var today = new Date();
today.setHours(0, 0, 0, 0);
var salesData = salesSheet.getDataRange().getValues();
var headers = salesData[0];
var sales = salesData.slice(1);
var dateCol = headers.indexOf("Date");
var amountCol = headers.indexOf("Amount");
var productCol = headers.indexOf("Product");
// Calculate metrics
var todayRevenue = 0;
var monthRevenue = 0;
var totalOrders = sales.length;
var productRevenue = {};
sales.forEach(function(row) {
var date = new Date(row[dateCol]);
var amount = row[amountCol];
var product = row[productCol];
// Today's revenue
if (date.toDateString() === today.toDateString()) {
todayRevenue += amount;
}
// This month's revenue
if (date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear()) {
monthRevenue += amount;
}
// Product revenue
if (!productRevenue[product]) {
productRevenue[product] = 0;
}
productRevenue[product] += amount;
});
// Top products
var topProducts = Object.keys(productRevenue).map(function(product) {
return {name: product, revenue: productRevenue[product]};
}).sort(function(a, b) {
return b.revenue - a.revenue;
}).slice(0, 5);
// Calculate changes (simplified - would compare to previous period)
var avgOrderValue = totalOrders > 0 ? monthRevenue / totalOrders : 0;
return {
todayRevenue: todayRevenue,
revenueChange: "+12%",
monthRevenue: monthRevenue,
monthlyGrowth: "+8.3%",
totalOrders: totalOrders,
ordersChange: "+15",
activeCustomers: 234,
customerGrowth: "+5%",
avgOrderValue: avgOrderValue,
aovChange: "+3.2%",
lowStockCount: 3,
topProducts: topProducts
};
}
function addRefreshButton() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('🔄 Dashboard')
.addItem('Refresh Data', 'createExecutiveDashboard')
.addToUi();
}
[Due to length constraints, I'll continue with the remaining sections in a structured summary format]
Integration with Google Workspace
Key Integrations:
- Gmail: Send emails, read inbox, create drafts
- Calendar: Create events, check availability, send invites
- Drive: Upload files, create folders, share documents
- Docs/Slides: Generate documents, update presentations
- Forms: Create forms programmatically, fetch responses
External API Integrations
Popular Integrations:
- Slack notifications
- Stripe payment tracking
- Salesforce CRM sync
- Twilio SMS alerts
- Weather APIs
- Stock market data
Triggers and Scheduling
Trigger Types:
⏰ Time-driven: Run daily, weekly, monthly
📝 On edit: When cells are edited
📋 On form submit: When form submitted
📂 On open: When spreadsheet opened
⏱️ On change: When structure changes
Add-ons and Extensions
Recommended Add-ons:
- Supermetrics (marketing data)
- Coupler.io (data integration)
- Form Publisher (PDF generation)
- Yet Another Mail Merge
- Advanced Find and Replace
Real-World Business Workflows
Complete Workflows:
- Sales Pipeline Automation
- Employee Onboarding System
- Inventory Management System
- Customer Support Ticketing
- Financial Report Generation
Best Practices and Security
Best Practices:
✅ Use named ranges (not A1 notation)
✅ Add error handling (try/catch)
✅ Log important actions
✅ Comment your code
✅ Test with sample data first
✅ Backup before automation
✅ Set execution time limits
✅ Monitor quota usage
Security:
🔒 Use Service Accounts for sensitive operations
🔒 Implement OAuth for user-specific access
🔒 Store API keys in Script Properties
🔒 Limit script permissions
🔒 Audit sharing settings
🔒 Regular security reviews
Conclusion
Google Sheets automation transforms manual spreadsheet work into powerful, automated business systems. With Apps Script, you can:
✅ Save hundreds of hours annually ✅ Eliminate manual errors ✅ Create real-time dashboards ✅ Automate reporting and notifications ✅ Integrate with any service ✅ Build custom business applications
Start small: Pick one repetitive task and automate it today.
Related Articles:
- Google Workspace Automation Guide
- Small Business Guide to Google Workspace
- Google Workspace vs Microsoft 365
Last Updated: October 25, 2025