Generate a PDF from a sheet row and file it in Drive
Ops wants a PDF of each approved row, dropped in that client’s Drive folder, named so a human can find it six months later. The spreadsheet…
Generate a PDF from a sheet row and file it in Drive
Ops wants a PDF of each approved row, dropped in that client’s Drive folder, named so a human can find it six months later. The spreadsheet…
Mirror a tab to another workbook on a schedule (without IMPORTRANGE)
The client wants “their” copy of the Orders tab. You reach for IMPORTRANGE, it works in the demo, and then: the client can’t see it because…
Stamp “last successful run” where ops can actually see it
“Did the sync run last night?” is a question that shouldn’t need you. But if the only answer lives in the Apps Script Executions page, every…
Keep formula columns when the script appends rows
Your import appends ten new orders. Column D used to say =C2*1.2. Now rows 42–51 say nothing — or worse, a hard-coded number from whatever…
onChange vs onEdit: catch inserts, deletes, and tab moves
onEdit is the hammer everyone reaches for. Then a teammate inserts ten rows, deletes a tab, or drags a sheet to reorder — and your sync…
Move a bound script to standalone without orphaning triggers
The workbook started as “a few menu items.” Now it’s a product shared across files, or you need a library, or the bound project’s authorize…
Protect the sheet so people can’t wreck formulas (while the script still writes)
Someone tabs into a formula column, types over =VLOOKUP(…), and tonight’s digest is garbage. You don’t need to lock people out of the…
Duplicate the spreadsheet for a throwaway dry-run of tonight’s job
Tonight’s job rewrites three tabs, refreshes pivot inputs, and emails a digest. A DRY_RUN = true flag skips the email — but it still mutates…
Ask for fewer OAuth scopes so your client actually clicks Allow
You paste a script for a client. They hit Run. Google shows “See, edit, create, and delete all of your Google Sheets spreadsheets.” They…
Validate Form answers before they hit your master sheet
Linked Forms feel convenient until one typo in “Email” breaks every nightly job that trusts the master tab. The fix isn’t a sterner form…
Version-pin an Apps Script library so “latest” doesn’t break client scripts
Shared libraries are how bootstrappers stay DRY across client spreadsheets — until someone saves a breaking change and every file on “Head…
Debounce onEdit so your sheet automation doesn’t thrash
Paste twenty status cells and watch your onEdit fan out twenty UrlFetch calls, twenty labeling passes, or twenty “send Slack” attempts. The…
Checkpoint a long run so the next trigger finishes the job
You already batch setValues, respect quotas, and chunk CSV imports. Then a 45-minute export still dies at ~6 minutes with half the work done…
Import a Drive CSV into a sheet in safe chunks
Export guides get the glory; imports fail at 4am with "Exceeded maximum execution time" after writing 8,000 of 40,000 rows. Read the Drive…
Pin a stable web app URL with versioned deployments
Webhooks and Zapier "Custom Request" steps hate moving targets. If you Deploy → New deployment every time you tweak doPost, partners get a…
Stay under someone else’s API rate limit
Third-party APIs rarely care that your nightly trigger "usually" fits. When five client files share one key — or one file fans out 200 GETs…
Export last night’s filtered rows to a dated CSV in Drive
Ops ask we hear a lot: after the nightly sync, dump “status = done” (or last 24h) rows into Exports/2026-09-18.csv without opening Sheets…
Point your script at staging so you never write prod by accident
Dry Run previews writes. This guide is the other half of safety: which spreadsheet those writes would hit. Keep a Script Property pointer…
“Execute as me” vs “as the user” — pick the web app identity that won’t haunt you
You deploy a doGet / doPost web app, share the URL, and suddenly writes land under the wrong account — or the script can’t see the sheet at…
Build a tiny HtmlService sidebar your teammates will actually click
Non-technical teammates will not open Apps Script. They will click a menu item that opens a sidebar with one obvious button and a status…
Find and flag duplicate rows before you push upstream
Inbound imports often get an idempotency story ("re-run without duplicating"). Outbound pushes are the opposite footgun: two sheet rows with…
Pause a nightly job without deleting the trigger
Deleting a time-driven trigger to "turn off" a nightly job feels clean until Monday when nobody remembers the exact hour, timezone, or…
Give non-technical teammates errors they can act on
Your script threw TypeError: Cannot read properties of undefined (reading '0') and the account manager Slack'd "is it broken?" That's on the…
Simple triggers vs installable triggers (when onEdit lies to you)
You wrote a perfect onEdit that emails the team when Status flips to Done — and nothing happens. Or worse: it works when you edit, then…
Treat a sheet like a job queue (claim → work → done)
Spreadsheets make terrible message buses — until you need a visible, editable backlog that non-engineers can triage. A Jobs tab with pending…
Brief NitroGAS Co-Pilot so you get working Apps Script
Co-Pilot is optional. The NitroGAS extension stays free forever for snippets and the editor workflow. When you do use Co-Pilot, the quality…
Clone a template sheet for every new client
Freelancer / ops pain: you keep copying last month's tab and inheriting junk — stale sample rows, half-edited formulas, a filter that still…
Email yourself when the nightly job fails
You've got a time-driven sync that "mostly works" until it doesn't — and you find out three days later from a confused teammate. Triggers…
Map columns by header, not by letter
Column C is a rumor. The moment a client inserts "Middle Name" between A and B, every hard-coded letter in your script writes into the wrong…
Add a Dry Run switch before you write
The scariest line in a bootstrapper is the first setValues against a live client tab. A Dry Run switch lets you rehearse the import: same…
Setup your triggers once (no doppelgängers)
Re-running "Install triggers" should be safe. In too many client workbooks it isn't — every Setup click stacks another time-driven job, and…
Archive rows, don’t delete them
Delete feels decisive until a client asks where order 1842 went. Soft-delete flags help; a dedicated Archive tab is clearer for operators…
Budget Apps Script quotas like a grown-up
Apps Script quotas aren't a surprise if you treat them like a budget. UrlFetch calls, email sends, spreadsheet reads, and total runtime all…
Re-run your import without duplicating rows
Imports fail halfway. APIs page slowly. Someone clicks the menu twice. If "run again" means double every row, you don't have an importer…
A Log sheet you’ll actually read later
Logger.log is fine until you need yesterday's failure and the Executions page shrugged. A tiny Log sheet — timestamp, level, message…
Catch a webhook in Apps Script without losing the payload
Webhooks don't retry politely when your script throws mid-flight. A solid Apps Script receiver does four boring things well: accept doPost…
Custom functions that don’t thrash your sheet
Custom functions look like spreadsheet superpowers until one volatile formula starts refetching an API on every edit. Use them for pure…
Timezone-safe dates in Sheets and Apps Script
new Date() in Apps Script, a date cell in Sheets, and a teammate in another city will happily disagree by a day — and you'll spend an…
Script Properties for bootstrapper config
Hardcoding an API key in the script editor feels fine… until you share the project, clone it for another client, or paste the same file into…
Batch writes without timeouts
When a script dies halfway through writing thousands of rows, you don't need a fancier API — you need a boring pattern: lock, chunk…
How to Auto-send Slackbot DMs using Google Sheets
Save yourself time (and save your sanity) by automating weekly metric update messages to your co-workers. In this video, you'll learn how to…