Skip to content
Development
Skill

/google-apps-script

Build Google Apps Script automation for Sheets and Workspace. Custom menus, triggers (onEdit / time-driven / form submit), dialogs, sidebars, email batches, PDF export, external API. Use whenever the user wants to automate a Google Sheet, build a Sheets menu / sidebar / dialog,

From plugin
jezweb-skills
1.1k63 skills57 commands

Claude Code

$ npx -y skills add jezweb/claude-skills --skill google-apps-script --agent claude-code

SKILL.md

google-apps-script.SKILL.md
name: google-apps-script
description: "Build Google Apps Script automation for Sheets and Workspace. Custom menus, triggers (onEdit / time-driven / form submit), dialogs, sidebars, email batches, PDF export, external API. Use whenever the user wants to automate a Google Sheet, build a Sheets menu / sidebar / dialog, hit a Sheets row from email or a webhook, schedule a Sheets workflow, or asks 'how do I script this in Sheets'."
compatibility: claude-code-only

Google Apps Script

Build automation scripts for Google Sheets and Workspace apps. Scripts run server-side on Google's infrastructure with a generous free tier.

What You Produce

  • Apps Script code pasted into Extensions > Apps Script
  • Custom menus, dialogs, sidebars
  • Automated triggers (on edit, time-driven, form submit)
  • Email notifications, PDF exports, API integrations

Workflow

Step 1: Understand the Automation

Ask what the user wants automated. Common scenarios:

  • Custom menu with actions (report generation, data processing)
  • Auto-triggered behaviour (on edit, on form submit, scheduled)
  • Sidebar app for data entry
  • Email notifications from sheet data
  • PDF export and distribution

Step 2: Generate the Script

Follow the structure template below. Every script needs a header comment, configuration constants at top, and `onOpen()` for menu setup.

Step 3: Provide Installation Instructions

All scripts install the same way: 1. Open the Google Sheet 2. **Extensions > Apps Script** 3. Delete any existing code in the editor 4. Paste the script 5. Click **Save** 6. Close the Apps Script tab 7. **Reload the spreadsheet** (onOpen runs on page load)

Step 4: First-Time Authorisation

Each user gets a Google OAuth consent screen on first run. For unverified scripts (most internal scripts), users must click:

**Advanced > Go to [Project Name] (unsafe) > Allow**

This is a one-time step per user. Warn users about this in your output.

---

Script Structure Template

Every script should follow this pattern:

/**
 * [Project Name] - [Brief Description]
 *
 * [What it does, key features]
 *
 * INSTALL: Extensions > Apps Script > paste this > Save > Reload sheet
 */

// --- CONFIGURATION ---
const SOME_SETTING = 'value';

// --- MENU SETUP ---
function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('My Menu')
    .addItem('Do Something', 'myFunction')
    .addSeparator()
    .addSubMenu(ui.createMenu('More Options')
      .addItem('Option A', 'optionA'))
    .addToUi();
}

// --- FUNCTIONS ---
function myFunction() {
  // Implementation
}

---

Critical Rules

Public vs Private Functions

Functions ending with `_` (underscore) are **private** and CANNOT be called from client-side HTML via `google.script.run`. This is a silent failure -- the call simply doesn't work with no error.

// WRONG - dialog can't call this, fails silently
function doWork_() { return 'done'; }

// RIGHT - dialog can call this
function doWork() { return 'done'; }

**Also applies to**: Menu item function references must be public function names as strings.

Batch Operations (Critical for Performance)

Read/write data in bulk, never cell-by-cell. The difference is 70x.

// SLOW (70 seconds on 100x100) - reads one cell at a time
for (let i = 1; i <= 100; i++) {
  const val = sheet.getRange(i, 1).getValue();
}

// FAST (1 second) - reads all at once
const allData = sheet.getRange(1, 1, 100, 1).getValues();
for (const row of allData) {
  const val = row[0];
}

Always use `getRange().getValues()` / `setValues()` for bulk reads/writes.

V8 Runtime

V8 is the **only** runtime (Rhino was removed January 2026). Supports modern JavaScript: `const`, `let`, arrow functions, template literals, destructuring, classes, async/generators.

**NOT available** (use Apps Script alternatives):

| Missing API | Apps Script Alternative | |-------------|------------------------| | `setTimeout` / `setInterval` | `Utilities.sleep(ms)` (blocking) | | `fetch` | `UrlFetchApp.fetch()` | | `FormData` | Build payload manually | | `URL` | String manipulation | | `crypto` | `Utilities.computeDigest()` / `Utilities.getUuid()` |

Flush Before Returning

Call `SpreadsheetApp.flush()` before returning from functions that modify the sheet, especially when called from HTML dialogs. Without it, changes may not be visible when the dialog shows "Done."

Simple vs Installable Triggers

| Feature | Simple (`onEdit`) | Installable | |---------|-------------------|-------------| | Auth required | No | Yes | | Send email | No | Yes | | Access other files | No | Yes | | URL fetch | No | Yes | | Open dialogs | No | Yes | | Runs as | Active user | Trigger creator |

Use simple triggers for lightweight reactions. Use installable triggers (via `ScriptApp.newTrigger()`) when you need email, external APIs, or cross-file access.

Custom Spreadsheet Functions

Functions used as `=MY_FUNCTION()` in cells have strict limitations:

/**
 * Calculates something custom.
 * @param {string} input The input value
 * @return {string} The result
 * @customfunction
 */
function MY_FUNCTION(input) {
  // Can use: basic JS, Utilities, CacheService
  // CANNOT use: MailApp, UrlFetchApp, SpreadsheetApp.getUi(), triggers
  return input.toUpperCase();
}
  • Must include `@customfunction` JSDoc tag
  • 30-second execution limit (vs 6 minutes for regular functions)
  • Cannot access services requiring authorisation

---

Quotas and Limits

| Resource | Free Account | Google Workspace | |----------|-------------|-----------------| | Script runtime | 6 min / execution | 6 min / execution | | Time-driven trigger runtime | 30 min | 30 min | | Triggers total daily runtime | 90 min | 6 hours | | Triggers total | 20 per user per script | 20 per user per script | | Email recipients/day | 100 | 1,500 | | URL Fetch calls/day | 20,000 | 100,000 | | Properties storage | 500 KB | 500 KB | | Custom function

Read more
@jezweb
Ships withjezweb-skills

Production workflow skills for Claude Code. Each skill guides Claude through a recipe to produce tangible output — scaffolded projects, generated assets, professional documents, deployed services. Ten plugins of practical, production-oriented skills.

Stars on GitHub

Momentum

stars in total
1.1k
Star history of jezweb/claude-skills on GitHub, a chart by star-history.com

Other skills on jezweb-skills.

cloudflare-api

cloudflare-api

Hit the Cloudflare REST API directly for operations that wrangler and MCP can't handle well. Bulk DNS, custom hostnames, email…

d1-drizzle-schema

d1-drizzle-schema

Generate Drizzle ORM schemas for Cloudflare D1 databases with correct D1-specific patterns. Produces schema files, migration…

d1-migration

d1-migration

Cloudflare D1 migration workflow: generate with Drizzle, inspect SQL for gotchas, apply to local and remote, fix stuck…

db-seed

db-seed

Generate database seed scripts with realistic sample data. Reads Drizzle schemas or SQL migrations, respects foreign key…

hono-api-scaffolder

hono-api-scaffolder

Scaffold Hono API routes for Cloudflare Workers. Produces route files, middleware, typed bindings, Zod validation, error…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills11d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react2d252k
@facebook@facebookInstall Skill

Questions about google-apps-script.

Which coding agents can use google-apps-script?
google-apps-script installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.