#appsScript
Google Apps Script now supports data regions. You can finally specify the geographic location for script execution and storage to help with your compliance requirements.

#GoogleWorkspace #AppsScript
Data regions for Google Apps Script now generally available
Take control of your Apps Script data residency. New Google Workspace updates now allow for geographic control of script execution and storage.
cloud-captains.com
September 18, 2026 at 3:20 PM
Google Apps Script gotcha: .atHour(9) is not 9:00. It fires somewhere in the 9-10 window, and it drifts day to day.

ScriptApp.newTrigger("daily").timeBased().atHour(9).everyDays(1).create();

So never derive "yesterday" from when the trigger ran. Filter on the timestamp in the row.

#AppsScript
September 10, 2026 at 11:19 AM
Ask: next week's meetings in a sheet, every Sunday.

Google Apps Script, weekly trigger:
const ev = CalendarApp.getEvents(mon, sun);
if (!ev.length) return;
sh.getRange(2,1,ev.length,2).setValues(ev.map(e=>[e.getStartTime(),e.getTitle()]));

A quiet week is 0 rows, and setValues throws. #AppsScript
September 9, 2026 at 11:22 AM
Google Apps Script gotcha: two form submits in the same second both read getLastRow() = 40, both write row 41, one silently overwrites the other.

sheet.appendRow(row) is atomic — the one write that cannot lose that race.

If you must setValues(), take a LockService lock first. #AppsScript
September 7, 2026 at 11:18 AM
Google Apps Script gotcha: simple onEdit(e) triggers run with NO auth — call GmailApp or UrlFetchApp inside one and it dies silently. No error, no log.

Need an edit-trigger that sends mail or hits an API? Make it an INSTALLABLE onEdit (Triggers → Add) — same function, full scopes. #AppsScript
July 23, 2026 at 11:24 AM
The chore: every invoice PDF in a Gmail label, saved to Drive by hand.

Google Apps Script, once:
GmailApp.search("label:invoices filename:pdf newer_than:7d")
.flatMap(t=>t.getMessages())
.forEach(m=>m.getAttachments()
.forEach(a=>folder.createFile(a)));

Trigger it, done. #AppsScript
July 21, 2026 at 1:16 PM
"Highlight every row where the amount is over 1000."

const sh = SpreadsheetApp.getActive().getActiveSheet();
sh.getDataRange().getValues().forEach((r, i) => {
if (r[2] > 1000) sh.getRange(i+1, 1, 1, r.length).setBackground("#fde68a");
});

One pass, every matching row flagged. #AppsScript
July 18, 2026 at 6:16 PM
Renaming a Drive folder full of files to a consistent scheme, one by one, eats a morning.

const files = DriveApp.getFolderById(ID).getFiles();
while (files.hasNext()) {
const f = files.next();
f.setName(f.getName().replace(/ /g, "_"));
}

Whole folder normalized in one run. #AppsScript
July 17, 2026 at 11:15 AM
getLastRow() counts a cell holding "" as content. setValue("") to clear a row leaves it in the count — your loop grinds through empty rows and your append lands in the wrong place.

clearContent() actually removes it. Or filter blanks from getValues() before trusting the length.

#AppsScript
July 15, 2026 at 4:38 PM
The Friday ritual: open the sheet, File > Download > PDF, email it to the team. A time-driven trigger (Fri 5pm) does all three — fetch the sheet's PDF-export blob, MailApp.sendEmail with it attached. You stop being the cron job. #AppsScript
July 12, 2026 at 11:30 AM
'move a row to an Archive tab when its Status cell becomes Done' →

onEdit(e): if the edited cell is the Status column and e.value == 'Done', appendRow() it to Archive, then deleteRow() from the source.

~8 lines. Pinning down the spec sentence was harder than the code. #AppsScript #GoogleSheets
July 11, 2026 at 11:30 AM
Apps Script gotcha: getValues() gives a 0-indexed array, but getRange() is 1-indexed. So data row i writes back to getRange(i + 2, col) — +1 for 1-indexing, +1 more if row 1 is a header. That off-by-one is why "my script edits the wrong row." #AppsScript
July 10, 2026 at 11:30 AM
"Archive every Gmail thread older than a year, keep anything starred."

function archiveOld() {
GmailApp.search("older_than:1y -is:starred")
.forEach(t => t.moveToArchive());
}

One sentence in, four lines out. Put it on a daily trigger and the inbox count stops climbing. #AppsScript #Gmail
July 8, 2026 at 11:30 AM
Apps Script gotcha: appendRow() in a loop makes one Sheets API call per row — 500 rows = 500 round-trips and a timeout. Build a 2D array in memory, then one setValues() over the whole range. Same result, ~100x faster. The round-trip is the cost, not the row count. #AppsScript
July 7, 2026 at 8:03 PM
A Sheets custom function stuck on an old value isn't a bug: Apps Script caches custom-function results by their arguments and only re-runs when an input cell changes. Feed it a cell that updates as a throwaway argument to force the recalc. #AppsScript #GoogleSheets
July 3, 2026 at 1:23 PM
Apps Script gotcha: Session.getActiveUser().getEmail() returns '' when the runner isn't in your Workspace domain (consumer Gmail, shared script) — your audit log looks empty for no reason. For the script owner's address, use getEffectiveUser(). #AppsScript
July 1, 2026 at 1:23 PM
The Monday ritual nobody admits to: open each client's Sheet, copy the totals row, paste into a master tab. SpreadsheetApp.openById(id).getSheetByName('Summary').getRange('B2:F2').getValues() looped over your id list, on one trigger — zero tab-switching. #AppsScript
June 30, 2026 at 2:09 PM
"auto-archive Gmail threads older than 30 days" →

GmailApp.search("in:inbox older_than:30d")
.forEach(t => t.moveToArchive());

Put it on a daily time-driven trigger and the inbox stops being a graveyard. The search operator does the filtering — no date math, no loop. #AppsScript
June 25, 2026 at 1:23 PM
Apps Script gotcha: getValues() on a date cell returns a Date in the SCRIPT's timezone, not the spreadsheet's. If they differ, the date silently shifts a day. Fix: Utilities.formatDate(d, ss.getSpreadsheetTimeZone(), 'yyyy-MM-dd') instead of trusting the raw Date. #AppsScript
June 24, 2026 at 1:23 PM
'email me a digest of today's new rows every evening' becomes a time-driven trigger: filter rows where the date is today, build a text body, MailApp.sendEmail(). ~12 lines, no add-on. The sheet stays the source of truth; the script just reads and sends. #AppsScript
June 22, 2026 at 10:21 PM
💡 Quick Tip: Google Forms Auto Processor Script

Most people don't know you can automate this in under 5 minutes.

Here's the approach:
1. Set up the base script
2. Configure your triggers
3. Let it run forever

Full free script in thread 👇

#appsScript #automation #free #devto
June 18, 2026 at 10:25 PM
💡 Quick Tip: Sheets to PDF Auto Generator

Most people don't know you can automate this in under 5 minutes.

Here's the approach:
1. Set up the base script
2. Configure your triggers
3. Let it run forever

Full free script in thread 👇

#appsScript #automation #free #devtools
June 16, 2026 at 6:25 AM
"Flag anything I've left unread for 3+ days so it stops slipping."

const label = GmailApp.getUserLabelByName('Follow-up');
GmailApp.search('is:unread older_than:3d')
.forEach(t => t.addLabel(label));

A daily time-trigger and you're done — the Gmail search bar does the filtering. #AppsScript
June 15, 2026 at 2:16 PM
Apps Script gotcha: Utilities.formatDate() uses the *script's* timezone, not the spreadsheet's — so your dates silently shift by hours.

Pass the sheet's zone explicitly:

Utilities.formatDate(d, ss.getSpreadsheetTimeZone(), 'yyyy-MM-dd')

Same trap hits Logger timestamps. #AppsScript
June 14, 2026 at 10:15 PM