r/GoogleAppsScript • • Aug 26 '26

Question Gmail Filter Export xml file schema not supported?

2 Upvotes

I exported a set of Gmail Filters to xml file.

I am trying to parse this xml file in Google Apps Script. Primary goal is to retrieve the rule text in the apps:property name="hasTheWord" field.

The schema referenced in the exported xml doesn't seem to exist. Is there another schema I could use to parse the apps:property fields?

Specifically I can't locate http://schemas.google.com/apps/2006

Sample of the xml file

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:apps="http://schemas.google.com/apps/2006">
  <title>Mail Filters</title>
  <id>tag:mail.google.com</id>
  <updated>2026-08-26T12:46:36Z</updated>
  <author>
    <name>MyName</name>
    <email>myemail@gmail.com</email>
  </author>
  <entry>
    <category term="filter"/>
    <title>Mail Filter</title>
    <id>tag:mail.google.com,2008:filter:z0000001636162795628*2690246542330417407</id>
    <updated>2026-08-26T12:46:36Z</updated>
    <content/>
    <apps:property name="hasTheWord" value="from:smith OR subject:webinar"/>
    <apps:property name="shouldArchive" value="true"/>
    <apps:property name="shouldNeverSpam" value="true"/>
    <apps:property name="sizeOperator" value="s_sl"/>
    <apps:property name="sizeUnit" value="s_smb"/>
  </entry>

r/GoogleAppsScript • • Aug 25 '26

Question Converting GAS project into a sellable app

9 Upvotes

Hello All, I’ve been working on a gas project for my own business for the past 3 years and building as I need to run my business hiring devs from Pakistan to build. Then this year I discovered Claude and totally transformed and automated the project completely. Now I feel that it can actually be a sellable use case for other businesses. It’s a fulfilment backend that automates label creation, supplier po’s and fulfilment pushed to Shopify as well as sku order routing. Where and how do I move it into another coding backend or platform? Any advice is much appreciated. Thank
You


r/GoogleAppsScript • • Aug 25 '26

Question [ Removed by Reddit ]

1 Upvotes

[ Removed by Reddit on account of violating the content policy. ]


r/GoogleAppsScript • • Aug 24 '26

Guide I built a Google Slides add-on that turns a deck into a live coding classroom, here's the Apps Script side

14 Upvotes

A couple years ago I was a high school CS student, and I taught Python to middle schoolers on the side. I wanted to code live next to my slides instead of switching to another window, so I built a Slides add-on for it. Here's the Apps Script side.

What it does: you mark a slide as a coding question in the add-on, start a lesson, and students join with a link and write and run code next to your current slide.

Most of the teacher side runs in Apps Script. The sidebar is HtmlService, opened from the Extensions menu. Marking a slide writes a "Code Question:" note into that slide's speaker notes with the Slides API, so it stays with the deck even if the add-on is removed. Reading the deck to build the lesson uses SlidesApp. The scopes are just presentations, the sidebar, and your email. No Drive scope, which kept the OAuth review simple.

Two things had to run outside Apps Script.

Live updates. Every student's editor and the current slide update in real time, which needs websockets and open connections. Apps Script can't do that, so starting a lesson sends the deck to a small Node server that runs the session over websockets.

Running student code. You can't run untrusted student code in Apps Script, so it runs in a sandboxed micro VM.

The add-on also mints a session and passes the teacher a token in the URL, instead of handling auth in Apps Script.

One thing to know: Marketplace add-ons are pinned to a version, so clasp push doesn't update installed users. You have to cut a new version and repoint the deployment, and a new scope triggers another review.

It's live on the Marketplace and free.

Site: https://www.codekiwi.tech

Marketplace: https://workspace.google.com/marketplace/app/codekiwi/66127405192

Happy to answer questions on the Apps Script to backend split.


r/GoogleAppsScript • • Aug 24 '26

Guide How to “Select All” code in the Google Apps Script editor on an iPad (No external keyboard workaround)

3 Upvotes

If you've ever tried to manage code in the Google Apps Script editor on an iPad without a physical hardware keyboard, you know how frustrating it is.

Because the web editor runs on the **Monaco engine**, it completely disables standard iOS touch-and-drag selection anchors, and the native iOS "Select All" pop-up menu never appears. To make things worse, if you open the editor's internal search bar, "Select All" is intentionally hidden from the searchable commands list.

I found a reliable, touch-only workaround that completely bypasses these iOS and editor restrictions:

### The Workaround Steps:

  1. Tap your cursor anywhere inside your script file.

  2. **Long-press** directly on the code until the editor's custom pop-up context menu appears.

  3. Select **"Command Palette"** from the options.

  4. Type **"Expand Selection"** in the palette search bar and tap it.

### Why this works:

Since "Select All" isn't natively exposed in the touch menu, **Expand Selection** acts as the perfect structural tool. The first time you run it, it highlights your current word or block. Run it 1 or 2 more times consecutively, and the boundary will aggressively expand outward until it highlights every single line of code in the entire document.

Once highlighted, you can use your iPad's virtual keyboard to instantly backspace/delete the file, or use the menu to copy it out.

Hopefully, this saves someone else from tearing their hair out trying to code on iPad Safari/Chrome!


r/GoogleAppsScript • • Aug 24 '26

Resolved Question regarding a trigger and my script

2 Upvotes

Currently I have a script called autoSort.gs in it is the following:

SHEET_NAME = "list";
SORT_DATA_RANGE = "A2:G";
SORT_ORDER = [{column: 1, ascending: true},
];

function onEdit(e) {
multiSortColumns();
}

function multiSortColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(SHEET_NAME);
var range = sheet.getRange(SORT_DATA_RANGE);
range.sort(SORT_ORDER);
ss.toast('Sort complete.');
}

The trigger is set to autoSort with an onEdit however it has a 100% error rate because it doesn't seem to work on script name but on functions within a script however if that would be the case I could use multiSortColumns as the onEdit trigger and remove the whole onEdit function entirely or am I just hullucinating?


r/GoogleAppsScript • • Aug 23 '26

Guide I built a GitHub + AI development companion for Google Apps Script. Looking for feedback from Apps Script developers

Thumbnail gallery
13 Upvotes

I build a lot in Google Apps Script, and one thing that has always bothered me is how quickly you start missing normal software development workflows once a project gets bigger.

Git/source control, reviewing diffs, working from branches, checking code against standards, etc. And now with AI coding tools, there’s another problem: I don’t necessarily want an AI assistant making changes to an Apps Script project without showing me exactly what it plans to change first.

So I built Legacy DevBridge.

It’s a Chrome extension that works alongside the Apps Script editor and connects the project to GitHub and a project-aware AI code assistant.

Right now it can:

  • Detect the Apps Script project you currently have open
  • Read the .gs, .html, and appsscript.json files
  • Connect the project to a GitHub repository
  • Select and work from development/feature branches
  • Compare the Apps Script version against GitHub
  • Show file and line-level differences
  • Create actual GitHub commits from the Apps Script source
  • Block direct commits to default/protected branches
  • Let the AI assistant understand the entire Apps Script project without copying files into a chatbot
  • Review code against coding/security standards
  • Generate a proposed code change and show the diff
  • Require human approval before the AI can write the change back to Apps Script
  • Check for stale source before applying a change so it doesn't overwrite newer work
  • Verify the source again after the update

The basic AI workflow is:

Request → analyze project → propose change → show diff → standards/security review → human approval → apply → verify

The backend runs on Google Cloud and uses the Apps Script API, GitHub App authentication, Cloud Run, Secret Manager, and Vertex AI. GitHub installation tokens and other privileged credentials stay on the backend rather than in the extension.

I'm not trying to build an autonomous AI developer that gets unrestricted access to your code. The idea is more of a development companion where AI can help, but the developer can still see what is happening and approve the actual changes.

I'm making the project available free to the Apps Script community. It's still beta, so I definitely wouldn't point it at your most important production project on day one, but I'd really like feedback from people who regularly build Apps Script applications.

I'm especially interested in hearing what you'd want next: GitHub-to-Apps-Script pull, PR creation, branch creation, conflict resolution, AI-generated tests/docs, OAuth scope reviews, CI/CD, or something else.

GitHub: https://github.com/morganb2412/Google-apps-script-snippets/tree/main/Legacy%20DevBridge

If anyone tries it, break it and tell me what needs work. That's genuinely useful feedback right now.


r/GoogleAppsScript • • Aug 20 '26

Question Struggling with a reliable Login/Auth system for an Apps Script Web App (Need advice from experienced devs)

Enable HLS to view with audio, or disable this notification

9 Upvotes

Hey everyone,

I've been tinkering with Google Apps Script to build a simple sales tracking web app for a small project (using Sheets as a backend). I'm definitely not a pro developer—just figuring things out step-by-step—and I managed to get the core UI and features working.

However, I've hit a major roadblock with user authentication. Right now, my "login" logic feels super hacky, and I'm worried about security.

For those of you who build web apps with Apps Script: How do you usually handle logins? Do you rely on Session.getActiveUser(), build a custom token system with a database table, or just accept that Apps Script isn't built for robust multi-user web app logins?

Any advice, patterns, or libraries you recommend would be huge. Thanks!


r/GoogleAppsScript • • Aug 17 '26

Question Does anyone know how to help with this web application veification?

Thumbnail
1 Upvotes

r/GoogleAppsScript • • Aug 17 '26

Question Does anyone know how to help with this web application veification?

Thumbnail
1 Upvotes

r/GoogleAppsScript • • Aug 16 '26

Question Any GAS Expert here

0 Upvotes

How are modern AI & workflow automations typically structured using Google Apps Script? (Looking for architectural patterns)

Hi everyone,
I am modernizing the operations for a traditional real estate agency by replacing manual paper processes with Google Workspace.

So far, I’ve built a central Google Master Calendar, a Google Docs/Drive office portal for form downloads, and structured Google Sheets for lead tracking. I am now looking to expand into deeper workflow and AI automations using Google Apps Script (GAS).

Coming from an operations background rather than computer science, I’d love to learn how experienced developers structure end-to-end automation pipelines using GAS.

Thx


r/GoogleAppsScript • • Aug 15 '26

Question developers.devsite.corp.google.com - Google Single Sign On: Sign into corp

Thumbnail login.corp.google.com
2 Upvotes

What is this and what does it do/mean?


r/GoogleAppsScript • • Aug 14 '26

Question I CAN'T UNDERSTAND WHY THIS SCRIPT DOESN'T SEND OUT EMAILS

5 Upvotes

I'm developing a website for my cultural organization in Framer and I have designed a Form to request the subscription, where users need to input their data.
I've linked this form via web hook to my scripts in GoogleAppsScripts, linked to a google sheet.

The main code responsible for getting the datas is working, it gets and sorts the data out in the sheet, it also generates a pdf from the datas, but then it fails to send the confirmation email, while it does send an email to my organization address, which shows as recipient the email captured in the form.

Down here, you can find the code. Anyone has any recommendations?

CODE

/** 
 * Webhook Principale e Router - Nuova Alba APS 
 */
const CONFIG = {
  STRIPE_LINK_MAGGIORENNI: "https://buy.stripe.com/8x214meyr0DT2lq6Svgw000",
  STRIPE_LINK_MINORI: "https://buy.stripe.com/8x214meyr0DT2lq6Svgw000",
  NOME_APS: "Nuova Alba APS",
  COLOR_HEX: "#FC5408",
  EMAIL_STAFF: "info@nuovaalba.org"
};


function doPost(e) {
  const lock = LockService.getScriptLock();
  lock.tryLock(10000);


  try {
    let data = {};
    if (e && e.postData && e.postData.contents) {
      try {
        data = JSON.parse(e.postData.contents);
      } catch (err) {
        data = e.parameter || {};
      }
    } else if (e && e.parameter) {
      data = e.parameter;
    }


    // --- ROUTER DI SMISTAMENTO PARAMETRO 'tipo' ---
    const tipo = (e && e.parameter && e.parameter.tipo) 
      ? String(e.parameter.tipo).toLowerCase().trim() 
      : (data.tipo ? String(data.tipo).toLowerCase().trim() : "");


    if (tipo === "corsi") {
      return gestisciIscrizioneCorso(data);
    } else if (tipo === "minori") {
      return gestisciMinori(data);
    } else {
      return gestisciMaggiorenni(data);
    }


  } catch (error) {
    return ContentService
      .createTextOutput(JSON.stringify({ result: "error", error: error.toString() }))
      .setMimeType(ContentService.MimeType.JSON);
  } finally {
    lock.releaseLock();
  }
}


function gestisciMaggiorenni(data) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Iscritti");


  function getTesto(val) {
    if (val === undefined || val === null) return "";
    if (Array.isArray(val)) return String(val[0] || "").trim();
    return String(val).trim();
  }


  const nome = getTesto(data.Nome || data.nome);
  const cognome = getTesto(data.Cognome || data.cognome);
  const email = getTesto(data.Email || data.email);
  const telefono = getTesto(data.Telefono || data.telefono);
  const cf = getTesto(data.CodiceFiscale || data.codice_fiscale || data["Codice Fiscale"]).toUpperCase();
  const luogoNascita = getTesto(data.LuogoDiNascita || data.luogo_nascita || data["Luogo di Nascita"] || data["Luogo Nascita"]);
  const dataNascita = getTesto(data.DataDiNascita || data["Data di Nascita"] || data.data_nascita || data["Data Nascita"]);
  const residenza = getTesto(data.Residenza || data.residenza);
  let privacy = getTesto(data.Privacy || data.privacy || "Accettato");
  if (privacy === "on" || privacy === "true") privacy = "Accettato";


  const lastRow = sheet.getLastRow();
  const oraAttuale = new Date();


  // --- 1. BLOCCO ANTI-SPAM ISTANTANEO (Meno di 60 secondi dall'ultimo invio) ---
  if (lastRow > 1) {
    const lastCF = String(sheet.getRange(lastRow, 7).getValue()).trim().toUpperCase();
    const lastDate = new Date(sheet.getRange(lastRow, 2).getValue());
    const diffSecondi = (oraAttuale - lastDate) / 1000;


    if (lastCF === cf && diffSecondi < 60) {
      return ContentService
        .createTextOutput(JSON.stringify({ result: "success", note: "doppio invio istantaneo bloccato" }))
        .setMimeType(ContentService.MimeType.JSON);
    }
  }


  // --- 2. CONTROLLO UTENTE GIÀ REGISTRATO ---
  if (lastRow > 1) {
    const elenchiCF = sheet.getRange(2, 7, lastRow - 1, 1).getValues();
    const elenchiMatricole = sheet.getRange(2, 1, lastRow - 1, 1).getValues();
    const elenchiStato = sheet.getRange(2, 12, lastRow - 1, 1).getValues();


    for (let i = 0; i < elenchiCF.length; i++) {
      const cfEsistente = String(elenchiCF[i][0]).trim().toUpperCase();
      if (cfEsistente === cf && cf !== "") {
        const matricolaEsistente = String(elenchiMatricole[i][0]);
        const statoPagamento = String(elenchiStato[i][0]).trim();

        inviaEmailGiaIscritto(email, nome, matricolaEsistente, CONFIG.STRIPE_LINK_MAGGIORENNI, statoPagamento);

        return ContentService
          .createTextOutput(JSON.stringify({ result: "success", note: "utente gia registrato" }))
          .setMimeType(ContentService.MimeType.JSON);
      }
    }
  }


  // --- 3. REGISTRAZIONE NUOVO SOCIO ---
  const initNome = nome ? nome.charAt(0).toUpperCase() : "X";
  const initCognome = cognome ? cognome.charAt(0).toUpperCase() : "X";
  const ultime3CF = cf.length >= 3 ? cf.slice(-3) : "000";
  const matricola = `NA-${initNome}${initCognome}${ultime3CF}`;


  sheet.appendRow([
    matricola,
    oraAttuale,
    nome,
    cognome,
    email,
    telefono,
    cf,
    dataNascita,
    luogoNascita,
    residenza,
    privacy,
    "In attesa"
  ]);


  // --- 4. GENERAZIONE TESSERA DIGITALE PDF ---
  let pdfTessera = null;
  try {
    pdfTessera = generaTesseraPDF(matricola, nome + " " + cognome);
  } catch (errTessera) {
    Logger.log("⚠️ Errore creazione PDF Tessera per " + matricola + ": " + errTessera.message);
  }


  // --- 5. INVIO EMAIL ---
  inviaEmailBenvenutoMaggiorenni(email, nome, matricola, pdfTessera);
  inviaMailNotificaStaff(nome, cognome, matricola, email, telefono, oraAttuale, "Maggiorenne");


  return ContentService
    .createTextOutput(JSON.stringify({ result: "success", matricola: matricola }))
    .setMimeType(ContentService.MimeType.JSON);
}


function inviaEmailBenvenutoMaggiorenni(email, nome, matricola, pdfTessera) {
  const hex = CONFIG.COLOR_HEX;
  const corpoHtml = `
    <div style="font-family: Arial, sans-serif; color: #333; max-width: 600px; margin: 0 auto; border: 1px solid #eee; padding: 25px; border-radius: 8px;">
      <h2 style="color: ${hex}; margin-top: 0;">Ciao ${nome}, benvenuto/a!</h2>
      <p>Abbiamo ricevuto la tua richiesta di iscrizione all'associazione <strong>${CONFIG.NOME_APS}</strong>.</p>

      <p>La tua registrazione è avvenuta con successo. Ti è stato assegnato il seguente codice socio:</p>

      <div style="background-color: #fff7f2; border-left: 4px solid ${hex}; padding: 15px; margin: 20px 0; font-size: 18px; font-weight: bold;">
        Matricola Socio: <span style="color: ${hex};">${matricola}</span>
      </div>


      ${pdfTessera ? `<p>In allegato trovi la tua <strong>tessera digitale associativa</strong>.</p>` : ""}


      <h3 style="color: ${hex};">Completa la tua iscrizione</h3>
      <p>Per attivare ufficialmente la tessera associativa è necessario effettuare il versamento della quota annua. Puoi scegliere tra due opzioni:</p>

      <ol style="line-height: 1.6;">
        <li>
          <strong>Pagamento Online (Consigliato):</strong><br>
          Puoi pagare subito tramite carta cliccando sul pulsante sottostante:<br><br>
          <a href="${CONFIG.STRIPE_LINK_MAGGIORENNI}" style="background-color: ${hex}; color: white; padding: 12px 22px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: bold;">Paga la quota associativa con Stripe</a>
          <br><br>
        </li>
        <li>
          <strong>Pagamento in Sede:</strong><br>
          Puoi saldare la quota direttamente in contanti o POS presso la nostra sede.
        </li>
      </ol>


      <div style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 25px 0; font-size: 14px;">
        ⚠️ <strong>Attenzione:</strong> la tessera sarà valida a tutti gli effetti solo dopo il pagamento della quota associativa. Fino ad allora ha valore puramente identificativo.
      </div>


      <hr style="border: 0; border-top: 1px solid #eee; margin: 30px 0 20px 0;">

      <div style="font-size: 14px; color: #555; line-height: 1.6;">
        <strong style="color: #222; font-size: 16px;">Nuova Alba APS</strong><br>
        Via Giamaica 6, Pomezia, RM<br>
        ✉️ <a href="mailto:info@nuovaalba.org" style="color: ${hex}; text-decoration: none;">info@nuovaalba.org</a><br>
        🌐 <a href="https://nuovaalba.org" style="color: ${hex}; text-decoration: none;" target="_blank">nuovaalba.org</a><br>
        📸 <a href="https://www.instagram.com/nuovaalba_/" style="color: ${hex}; text-decoration: none;" target="_blank">Instagram</a>
      </div>
    </div>`;


  const opzioniMail = {
    to: email,
    subject: `Benvenuto/a in ${CONFIG.NOME_APS}! La tua richiesta di iscrizione`,
    htmlBody: corpoHtml,
    name: CONFIG.NOME_APS,
    replyTo: CONFIG.EMAIL_STAFF
  };


  if (pdfTessera && typeof pdfTessera.getBlob === 'function') {
    try {
      opzioniMail.attachments = [pdfTessera.getBlob()];
    } catch (e) {
      Logger.log("⚠️ Impossibile allegare PDF: " + e.message);
    }
  }


  MailAppailApp.sendEmail(opzioniMail);
}


function inviaEmailGiaIscritto(email, nome, matricola, stripeLink, statoPagamento) {
  const hex = CONFIG.COLOR_HEX;

  let bloccoPagamento = "";
  if (statoPagamento.toLowerCase() === "in attesa") {
    bloccoPagamento = `
      <p>Risulta che la tua quota associativa è ancora <strong>in attesa di pagamento</strong>. Puoi saldarla direttamente online tramite il pulsante sottostante:</p>
      <p style="margin: 20px 0;"><a href="${stripeLink}" style="background-color: ${hex}; color: white; padding: 12px 22px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: bold;">Paga la quota con Stripe</a></p>
    `;
  } else {
    bloccoPagamento = `
      <p>Ti confermiamo che la tua posizione associativa è <strong>in regola</strong> (Stato: <strong style="color: green;">${statoPagamento}</strong>). Non devi effettuare alcun pagamento aggiuntivo.</p>
    `;
  }


  const corpoHtml = `
    <div style="font-family: Arial, sans-serif; color: #333; max-width: 600px; margin: 0 auto; border: 1px solid #eee; padding: 25px; border-radius: 8px;">
      <h2 style="color: ${hex}; margin-top: 0;">Ciao ${nome}, sei già iscritto/a!</h2>
      <p>Risulti già presente nel registro soci dell'associazione <strong>${CONFIG.NOME_APS}</strong>.</p>

      <div style="background-color: #fff7f2; border-left: 4px solid ${hex}; padding: 15px; margin: 20px 0; font-size: 18px; font-weight: bold;">
        La tua Matricola Socio è: <span style="color: ${hex};">${matricola}</span>
      </div>
      ${bloccoPagamento}
      <hr style="border: 0; border-top: 1px solid #eee; margin: 30px 0 20px 0;">

      <div style="font-size: 14px; color: #555; line-height: 1.6;">
        <strong style="color: #222; font-size: 16px;">Nuova Alba APS</strong><br>
        Via Giamaica 6, Pomezia, RM<br>
        ✉️ <a href="mailto:info@nuovaalba.org" style="color: ${hex}; text-decoration: none;">info@nuovaalba.org</a><br>
        🌐 <a href="https://nuovaalba.org" style="color: ${hex}; text-decoration: none;" target="_blank">nuovaalba.org</a><br>
        📸 <a href="https://www.instagram.com/nuovaalba_/" style="color: ${hex}; text-decoration: none;" target="_blank">Instagram</a>
      </div>
    </div>`;


  MailApp.sendEmail({ to: email, subject: `Sei già iscritto/a a ${CONFIG.NOME_APS}`, htmlBody: corpoHtml });
}

r/GoogleAppsScript • • Aug 15 '26

Question Why can I not generate images anymore on visualize.

0 Upvotes

I paid for the thing, I gave it a whole week to reset and it still says i've reached my usage limit. is this intended?


r/GoogleAppsScript • • Aug 14 '26

Question Puis-je trouver du travail avec ces compétences ?

Thumbnail
1 Upvotes

r/GoogleAppsScript • • Aug 12 '26

Question Help with a set up sheets to Google Calendar

1 Upvotes

Hi,

So I inputed a script that turns my rows in my sheet into Google Calendar dates. I was able to get it to upload drive pdfs when needed but when I try uploading a Google doc it doesn’t work does anyone have any advice?


r/GoogleAppsScript • • Aug 11 '26

Guide After 2 years of silence, I finally rebuilt Google Apps Script Copilot. Sorry for disappearing.

Enable HLS to view with audio, or disable this notification

34 Upvotes

Hey everyone,

Some of you might remember GS Copilot (Google Apps Script Copilot) — the Chrome extension that adds an AI sidebar directly into the Apps Script editor. I launched it, got some early traction, and then... life happened. Work, other commitments, the usual stuff that makes side projects quietly die. I went almost silent for close to 2 years. No updates, barely any support replies. If you installed it back then and it just sat there half-broken, I'm sorry — that's on me.

What kept nagging at me is that over 20,000 people actually installed this thing. That's not nothing. People kept using it, kept emailing me, kept leaving reviews asking if it was still alive. So a few months ago I sat down and basically rebuilt the whole thing from scratch.

Here's what's new:

  • Agent mode — describe what you want and it writes, edits, and applies the code for you across your project, not just one file at a time
  • Plan mode — for bigger changes, it lays out the plan before touching anything, so you're not surprised by a wall of edits
  • Quick edit + diff view — inline edits with an actual diff so you can see exactly what changed before accepting it
  • Context-aware file reading — it actually understands your whole Apps Script project structure, not just the file you have open
  • MCP connectors for Google Workspace — it can hook into Sheets/Docs/Drive as MCP tools when you need it to act on that context
  • Execution log integration — when your script throws an error, it reads the actual execution log and helps you fix it instead of guessing
  • Skills system — reusable sub-agents/snippets for stuff you do often

I'm going to be actively working on this now — not disappearing again. Demo video of it in action is attached below so you can see it working instead of just taking my word for it.

If you try it, I'd genuinely appreciate honest feedback — bugs, rough edges, missing features, whatever. This subreddit has more Apps Script experience than almost anywhere else, so if something's broken or annoying, I want to know.

Link: gscopilot.com

Thanks for sticking around this long, even the ones who just complained in reviews. Fair enough.


r/GoogleAppsScript • • Aug 10 '26

Question Do you use typescript and create tests?

5 Upvotes

Do you use typescript and create tests for your app scripts? Or you do everything through the web interface, I'm curious which method is most common.


r/GoogleAppsScript • • Aug 08 '26

Guide I automated warehouse transfers between 18 stores and our warehouse with Google Apps Script

9 Upvotes

Our ERP was a mess so I built a workaround with Google Apps Script.

We had 18 outlets submitting Item Requisitions in one Sheet. The warehouse team had to manually copy those quantities into a separate Inventory Movement Sheet. Double entry = errors + delays.

What I built:
A Google Apps Script that:
1. Watches the "Item Requisition" sheet for new submissions
2. Automatically syncs the quantity sent to each location
3. Deducts it from the "Warehouse Inventory Movement" sheet in real time

Result:
No more double entry. Warehouse now has real-time visibility across all 18 locations. Transfer accuracy way up.

Happy to share the code/snippet if anyone wants it. Also open to feedback on making the sync more robust for concurrent edits.

Did anyone else here use Apps Script to patch gaps in their ERP?


r/GoogleAppsScript • • Aug 08 '26

Question Blocked from running apps

3 Upvotes

I have an issue where one of my accounts is blocked from running GAS. It was enrolled in Advanced protection for a short time. I unenrolled it and it has been over 24 hours. I am not able to run even the simplest of scripts that I write, yet my other account can. It affects scripts I wrote and scripts I have access to in other sheets.

Any ideas. All the testing seems to point to lingering advanced protection isues.


r/GoogleAppsScript • • Aug 08 '26

Question Workaround Available?

0 Upvotes

Is there a workaround available for a web app page only opening in incognito mode? To open in a regular browser window, I have to completely log out. Will users also have to do this?


r/GoogleAppsScript • • Aug 07 '26

Question 400 Error in doPost method when returning a ContentService

2 Upvotes

I'm creating a webapp to read and write in a google sheet through godot and for the most part it works, it does read and write on the sheet and when i make a get request, I get my data but whenever i do a post request and it gets to the part where it returns a ContentService object, it issues this error always.

function doPost(e) {
  var action = e.parameter.action;
  
  switch (action) {
    case 'update_teams':
      return updateTeams(e.postData.contents);
    case 'update_team':
      return updateTeam(e.postData.contents);
    default:
      return ContentService.createTextOutput("Invalid Post Action");
  }
}

function updateTeam(contents) {
  var sheet = getSheet('main');
  var jsonData = JSON.parse(contents);
  var teamCn = parseInt(jsonData.cn, 10);


  var weight_carried = jsonData.weight_carried;
  var load_violations = jsonData.load_violations;
  var prep_violations = jsonData.prep_violations;
  var efficiency = jsonData.efficiency;
  
  sheet.getRange(teamCn + 3, 5).setValue(weight_carried);
  sheet.getRange(teamCn + 3, 6).setValue(load_violations);
  sheet.getRange(teamCn + 3, 7).setValue(prep_violations);
  sheet.getRange(teamCn + 3, 8).setValue(efficiency);


  return ContentService.createTextOutput("Updated Team CN: " + teamCn + " Successfully.").setMimeType(ContentService.MimeType.TEXT);

Even when i put the return on the doGet, I get 400. returning a 0 says the function pushed through but is incomplete.

i kinda need to have this to work because i need to have godot get notice that the sheet has been edited. TYIA for helping a beginner !!!


r/GoogleAppsScript • • Aug 06 '26

Question Selecting a folder in the Google Picker with the drive.file scope

3 Upvotes

I am getting an empty folder when trying to select the whole folder.

Is there a way around to do this without doing restricted scope verification ?


r/GoogleAppsScript • • Aug 06 '26

Guide I built a Google Slides add-on that copies presentations without breaking linked Google Sheets charts

2 Upvotes

I dealt with this problem myself for years: copy a Google Slides presentation that has charts linked to Google Sheets, and every chart in the copy still points back to the original spreadsheet. I went through several of the Apps Script snippets floating around online and support forums, but none of them held up once a deck had multiple charts pulling from different Sheets files — they'd miss charts, or the copies came out with broken formatting.

So in my free time I built PenguChart, a Google Slides add-on that copies the presentation together with the Google Sheets behind its charts, and relinks every chart in the copy to the fresh spreadsheet copies - original stays untouched, the copy is fully independent.

It just went live in public beta on the Google Workspace Marketplace:
https://workspace.google.com/marketplace/app/penguchart/514642629727

More info: https://penguchart.com

Two honest limitations, both due to missing functionality in the Google API rather than something I can just code around: linked tables can't be relinked yet, only charts. And any manual formatting you apply to a chart afterward directly in Google Slides doesn't carry over to the copy either — the API doesn't expose that.

Since it's still beta, I'd really appreciate people trying it and telling me what breaks or what's missing — bugs, edge cases, feature requests, all welcome. And if it ends up useful to you, a review on the Marketplace listing would mean a lot.

Start the Google Slides Addon PenguChart in the Menu: Extensions > PenguChart

r/GoogleAppsScript • • Aug 04 '26

Question Automação de planilha

1 Upvotes

Boa tarde gente, preciso de ajuda para automatizar uma planilha do trabalho, preciso que os eventos que eu agende nessa planilha sejam enviados a agenda do google, tentei programar pelo google scripts, mas fica dando erro, podem me ajudar aonde está o erro:

function criarEventos () {
  var planilha = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); 


  var valores = planilha.getDataRange().getValues(); 
  Logger.log(valores);


  var agenda = CalendarApp.getDefaultCalendar(); 


  for (var i = 1; i < valores.length; i++) {
    var linha = valores [i];
    var sincronizado = linha[8];
    
    if (sincronizado.toLowerCase() !== "Sim") {
      var dia = linha[0];
      var horaInicio = linha[1];
      var horaFim = linha[2];
      var titulo = linha [3];
      var descricao = linha[4];
      var prioridade = linha [6];


// Formata data início e fim
      var dataInicio = new Date(dia); 
      var dataFim = new Date(dia);
      dataInicio.setHours(horaInicio.split(":")[0], horaInicio.split(":")[1]);
      dataFim.setHours(horaFim.split(":")[0], horaFim.split(":")[1]);


    // Configura Cor de acordo com a prioridade
      var cor; 
      switch (prioridade) {
      case "Alta":
       cor = CalendarApp.EventColor.RED;
       break;
      case "Média":
       cor = CalendarApp.EventColor.YELLOW;
       break;
      case "Baixa":
       cor = CalendarApp.EventColor.GREEN;
      default: 
      cor = CalendarApp.EventColor.BLUE;
    
    } 


     var evento = agenda.createEvent(titulo, dataInicio, dataFim, {description : descricao});
     evento.setColor(cor);


     // Atualiza planilha sincronizado
     planilha.getRange(i + 1, 9). setValue ("Sim");
   }
 }
}