Monitoring Sheet Changes with SHEET and SHEETS Functions on Google Sheets — DeepSeek Blog | Neura Market
    Neura MarketNeura Market/DeepSeek
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityDeepSeekDeepSeek
    CoPilotCoPilotStable DiffusionStable DiffusionMidjourneyMidjourney
    View All Directories
    OverviewRulesPromptsMCPsAgentsBlogVideosGuidesCoursesCommunityTrendingGenerate
    DeepSeekBlogMonitoring Sheet Changes with SHEET and SHEETS Functions on Google Sheets
    Back to Blog
    Monitoring Sheet Changes with SHEET and SHEETS Functions on Google Sheets
    googleappsscript

    Monitoring Sheet Changes with SHEET and SHEETS Functions on Google Sheets

    Tanaike April 8, 2026
    0 views

    Abstract Google Sheets recently introduced the SHEET and SHEETS functions. Because they...

    ## Abstract Google Sheets recently introduced the `SHEET` and `SHEETS` functions. Because they automatically recalculate upon structural changes, developers can utilize them as custom triggers. This article demonstrates how to leverage these functions to detect sheet insertions, deletions, renames, and movements without requiring cumbersome installable triggers in Google Apps Script. ## Introduction On February 23, 2026, Google introduced two pivotal built-in functions to Google Sheets: `SHEET` and `SHEETS` [Ref](https://workspaceupdates.googleblog.com/2026/02/two-new-functions-in-google-sheets.html). The `SHEET` function returns the index (sheet number) of a specified sheet or reference [Ref](https://support.google.com/docs/answer/16865249?dark=1&hl=en). Meanwhile, the `SHEETS` function provides the total count of sheets within a spreadsheet [Ref](https://support.google.com/docs/answer/16865347?dark=1&hl=en). A critical technical characteristic of these functions is their volatility and automatic recalculation based on the spreadsheet's structural metadata. Specifically: - `SHEET` triggers a recalculation when a sheet is renamed or its position is changed via drag-and-drop. - `SHEETS` triggers a recalculation whenever a sheet is inserted, duplicated, or removed. Historically, detecting such structural changes necessitated the use of an **installable OnChange trigger** in Google Apps Script (GAS). This posed a significant barrier for template distribution, as installable triggers require manual authorization by each user and do not persist through simple file copies. By leveraging these new functions as "custom triggers," we can effectively bypass the need for installable triggers. When a custom function or formula containing `SHEET` or `SHEETS` recalculates, it serves as a catalyst for GAS execution. This enables the creation of self-contained spreadsheets where advanced sheet monitoring logic is activated immediately upon copying the file, significantly improving the user experience and portability of GAS-based solutions. ![fig1](https://tanaikech.github.io/image-storage/20260408a/fig1.jpg) ## Implementation Guide ### 1. Spreadsheet Initialization Create a new Google Sheets file to serve as your testing environment. ### 2. Google Apps Script Configuration Open the Google Apps Script editor bound to your new spreadsheet. Copy and paste the following script, replacing any default code, and save your project. ```javascript /** * Global constant defining the Script Properties storage key. */ const STORAGE_KEY = "SHEET_STATUS_CACHE"; /** * Simple trigger to initialize the cached sheet metadata upon opening the spreadsheet. */ function onOpen() { updateStoredSheetData_(); } /** * Custom function wrapper to retrieve an array of all current sheet names. */ function getAllSheetNames() { return SpreadsheetApp.getActiveSpreadsheet() .getSheets() .map((s) => s.getName()); } /** * Core custom function for detecting structural alterations. * Priority: If any structural change (Add/Remove/Rename) occurs, * subsequent "move" reports are suppressed to avoid noise from index shifting. */ function getSheetStatus(_trigger1, _trigger2, returnRawObject = false) { const propService = PropertiesService.getScriptProperties(); const oldDataJson = propService.getProperty(STORAGE_KEY); const ss = SpreadsheetApp.getActiveSpreadsheet(); const currentSheets = ss.getSheets(); const newData = currentSheets.map((s, i) => ({ name: s.getName(), id: s.getSheetId(), index: i + 1, })); if (!oldDataJson) { updateStoredSheetData_(); return "Initial state recorded."; } const oldData = JSON.parse(oldDataJson).map((s, i) => ({ ...s, index: i + 1, })); // Categorize detected modifications into structural changes or simple index moves. const { structural, moves } = detectCategorizedChanges_(oldData, newData); // Persist the newly fetched metadata to Script Properties. propService.setProperty( STORAGE_KEY, JSON.stringify(newData.map(({ name, id }) => ({ name, id }))), ); // Evaluate which results to return based on change priority. // Ignore index movement noise if a primary structural change (addition, removal, rename) occurred. const finalDiffs = structural.length > 0 ? structural : moves; if (finalDiffs.length === 0) return "No change"; if (returnRawObject) return JSON.stringify(finalDiffs); return finalDiffs.map((d) => d.message).join("\n"); } /** * Retrieves current spreadsheet metadata and persists it to the properties cache. */ function updateStoredSheetData_() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheetData = ss.getSheets().map((s) => ({ name: s.getName(), id: s.getSheetId(), })); PropertiesService.getScriptProperties().setProperty( STORAGE_KEY, JSON.stringify(sheetData), ); return sheetData; } /** * Differentiates between core structural changes and simple index shifts. */ function detectCategorizedChanges_(oldData, newData) { const structural = []; const moves = []; const oldMap = new Map(oldData.map((s) => [s.id, s])); const newMap = new Map(newData.map((s) => [s.id, s])); // 1. Identify removed sheets (Structural change). oldData.forEach((oldSheet) => { if (!newMap.has(oldSheet.id)) { structural.push({ type: "removed", message: `"${oldSheet.name}" was removed.`, }); } }); // 2. Identify added, renamed, or repositioned sheets. newData.forEach((newSheet) => { const oldSheet = oldMap.get(newSheet.id); if (!oldSheet) { // Handle added sheets (Structural change). structural.push({ type: "added", message: `"${newSheet.name}" was inserted at tab ${newSheet.index}.`, }); } else { const isRenamed = oldSheet.name !== newSheet.name; const isMoved = oldSheet.index !== newSheet.index; if (isRenamed) { // Handle renamed sheets (Structural change). structural.push({ type: "renamed", message: `"${oldSheet.name}" was renamed to "${newSheet.name}".`, }); } else if (isMoved) { // Handle pure index movements (Non-structural change). moves.push({ type: "moved", message: `"${newSheet.name}" was moved from tab ${oldSheet.index} to ${newSheet.index}.`, }); } } }); return { structural, moves }; } /** * Optional callback for installable OnChange triggers. * If utilized, do not use the custom formula in the sheet. */ function onChange(e = {}) { const { changeType } = e; if (["OTHER", "INSERT_GRID", "REMOVE_GRID"].includes(changeType)) { const res = getSheetStatus(); Browser.msgBox(res); } } ``` ### 3. Applying the Custom Formula Return to your Google Sheets interface. In the first sheet, copy and paste the following formula into cell `A1`: ```text =getSheetStatus(SHEETS(),MAP(getAllSheetNames(),lambda(sheetname,SHEET(sheetname)))) ``` ### 4. Testing the Workflow Once the formula is in place, the cell will actively monitor the document's structure. The demonstration below illustrates the expected behavior: ![fig2](https://tanaikech.github.io/image-storage/20260408a/fig2.gif) During the demonstration, the following actions trigger a status update in the cell: 1. Renaming an existing sheet. 2. Adding a new sheet to the workbook. 3. Changing the order (moving) of a sheet. 4. Deleting a sheet. ## Appendix: Using Traditional Triggers If you prefer to use the traditional installable `onChange` trigger method, you can utilize the `onChange` function provided at the bottom of the script. In this scenario, you must manually bind the trigger to the `onChange` function via the Apps Script dashboard and **remove** the custom formula (`=getSheetStatus(...)`) from cell `A1`. The underlying logic handles the detection identically, routing the output to a browser message box instead of a cell. ## Summary - The introduction of `SHEET` and `SHEETS` functions enables automatic formula recalculation based on structural metadata changes. - These built-in functions can be passed into custom Google Apps Script functions to act as volatile execution triggers. - This methodology eliminates the traditional dependency on installable `onChange` triggers for monitoring tab modifications. - Removing installable triggers drastically improves script portability and the user experience when distributing spreadsheet templates. - The provided script successfully categorizes and logs structural alterations versus simple index shifts for comprehensive monitoring.

    Tags

    googleappsscriptgoogleworkspacegooglesheetsjavascript

    Comments

    More Blog

    View all
    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠ai

    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠

    Hi everyone! 👋 I’m Tara, a Senior Software Engineer and Consultant. Over the years, I've jumped...

    T
    tworrell
    Local AI Will Save Us All (The Math Says So, Trust Me)ai

    Local AI Will Save Us All (The Math Says So, Trust Me)

    Every few weeks a take goes viral in tech circles making the case for ditching cloud AI and running...

    S
    Sebastian Schürmann
    Lost in the AI Hype, I Started Smallai

    Lost in the AI Hype, I Started Small

    And it helped me get back into tech without drowning TL;DR at the end Coming back to...

    R
    Rohini Gaonkar
    Building a Replay-Tested Interactive Brokers Client in Gogo

    Building a Replay-Tested Interactive Brokers Client in Go

    I wanted an IBKR library that felt like Go and had testing I could trust. So I wrote one.

    T
    Thomas Marcelis
    Playwright in Pictures: Fully Parallel Modeplaywright

    Playwright in Pictures: Fully Parallel Mode

    Playwright’s fullyParallel mode is often treated as a simple performance switch. In practice, it...

    V
    Vitaliy Potapov
    Designing a CLI for Both Humans and Agentscli

    Designing a CLI for Both Humans and Agents

    Learn how Alpic designed its CLI for both human developers and AI agents — covering tradeoffs like polling, context windows, interactivity, and statelessness.

    J
    Julien Vallini

    Stay up to date

    Get the latest DeepSeek prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for DeepSeek and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.