Apps Script example · 9 min read

Pipeline Stage Automation: Copy-Paste Apps Script Pattern

Working pipeline stage automation example in Apps Script—copy-paste code, common mistakes, and when to get it built professionally.

CRMPipelineAutomation

Pipeline hygiene fails when stages lag reality. Automate forward transitions when milestone checkboxes are set.

pipelineStageAutomation reads discovery/demo/proposal flags and advances one stage at a time per run.

Won stays manual here so revenue recognition is deliberate; pair with a deal-won notification script.

truthy_ accepts common Sheets checkbox and Yes/y forms.

Need this built? Hire a Google Apps Script developer →

Sheet / project setup

SheetColumnPurpose
DealsA idDeal id
DealsB stageCurrent stage
DealsC discoveryDoneCheckbox
DealsD demoDoneCheckbox
DealsE proposalSentCheckbox
DealsF lastTransitionTimestamp

What this script does

Forward-only stage updates driven by milestone columns.

Prerequisites

Deals sheet with stages matching STAGE_ORDER names.

  • Checkboxes or Yes values
  • Run on edit or hourly
  • Won handled elsewhere

Walkthrough

Set New deal discoveryDone; run; stage becomes Discovery and F stamps.

Edge cases

Skipping stages intentionally is not supported — require each flag.

  • No automatic regression
  • One hop per execution

How to test

Toggle flags out of order; ensure it still waits for the current stage's flag.

Hardening for production

Log transitions to StageHistory; notify owners on change.

Variations

Map stages from HubSpot via API instead of local checkboxes.

Full code: pipelineStageAutomation()

Maintain checklist columns, then run pipelineStageAutomation() on a trigger or after bulk edits.

/**
 * Move deals to the next stage when checklist columns are complete.
 */
const DEALS = "Deals";
// A id, B stage, C discoveryDone, D demoDone, E proposalSent, F lastTransition

const STAGE_ORDER = ["New", "Discovery", "Demo", "Proposal", "Won"];

function pipelineStageAutomation() {
  const sheet = SpreadsheetApp.getActive().getSheetByName(DEALS);
  const values = sheet.getDataRange().getValues();

  for (let i = 1; i < values.length; i++) {
    let stage = values[i][1];
    const discovery = truthy_(values[i][2]);
    const demo = truthy_(values[i][3]);
    const proposal = truthy_(values[i][4]);
    let next = stage;

    if (stage === "New" && discovery) next = "Discovery";
    else if (stage === "Discovery" && demo) next = "Demo";
    else if (stage === "Demo" && proposal) next = "Proposal";
    // Won is manual or via deal-won flow

    if (next !== stage) {
      values[i][1] = next;
      values[i][5] = new Date();
    }
  }
  sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
}

function truthy_(v) {
  return v === true || v === "TRUE" || v === "Yes" || v === "y" || v === 1;
}
  1. Line 7: Documents allowed stages (Won manual).
  2. Line 15: Normalizes checkbox/Yes values.
  3. Line 25: Only writes when advancing.
  4. Line 5: Column F timestamp.
  5. Line 30: Batch-writes stage updates.

Deploy this example

  1. 01

    Open Apps Script

    In the bound spreadsheet: Extensions → Apps Script. For standalone projects, create one at script.google.com and link your Sheet by ID.

  2. 02

    Paste and save

    Add a .gs file, paste the code below, rename constants at the top (sheet names, column letters, API property keys), then save.

  3. 03

    Authorize once

    Run the main function from the editor. Accept OAuth scopes when prompted — triggers cannot run until authorization succeeds once.

  4. 04

    Add the trigger

    Triggers → Add trigger → choose the handler function and event (time-driven, on edit, or on form submit). Delete test triggers before production.

Before you run: pipeline stages

  • 1Stage names match code exactly
  • 2Checkbox columns validated
  • 3Won not auto-set here
  • 4Owners know automation is forward-only
  • 5History logging considered
  • 6Test on a copy of Deals

Frequently asked questions

Not in this sample — it advances one stage per required flag.

Manual edit; or add explicit regress rules.

Possible, but batch hourly is gentler on large pipelines.

Edit the if/else chain and STAGE_ORDER comments.

Filter by a pipeline column before applying rules.

truthy_ handles both Sheets boolean and text.

Compare old vs next and MailApp the owner email column.

Related examples

Want this wired into your real workflow?

I adapt these patterns to your Sheet structure, APIs, and triggers — deployed in your Google account. Fixed-scope quotes from $500 · free 30-min consult · quote within 24 hours.