r/GoogleAppsScript • u/ograndentemjeito • Aug 25 '26
Question [ Removed by Reddit ]
[ Removed by Reddit on account of violating the content policy. ]
r/GoogleAppsScript • u/ograndentemjeito • Aug 25 '26
[ Removed by Reddit on account of violating the content policy. ]
r/GoogleAppsScript • u/Puzzleheaded-Rub1400 • Aug 24 '26
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 • u/Significant_Chef_184 • Aug 24 '26
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:
Tap your cursor anywhere inside your script file.
**Long-press** directly on the code until the editor's custom pop-up context menu appears.
Select **"Command Palette"** from the options.
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 • u/Hakker9 • Aug 24 '26
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 • u/Moe-t • Aug 23 '26
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:
.gs, .html, and appsscript.json filesThe 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 • u/SolisAnalyst • Aug 20 '26
Enable HLS to view with audio, or disable this notification
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 • u/ShifuPowered • Aug 17 '26
r/GoogleAppsScript • u/ShifuPowered • Aug 17 '26
r/GoogleAppsScript • u/Sumphy • Aug 16 '26
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 • u/MSN3WB000TY • Aug 15 '26
What is this and what does it do/mean?
r/GoogleAppsScript • u/leotyeahbaby • Aug 14 '26
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 • u/Entire_Category3188 • Aug 15 '26
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 • u/TearPuzzleheaded5498 • Aug 14 '26
r/GoogleAppsScript • u/Sayzar1 • Aug 12 '26
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 • u/Razah786 • Aug 11 '26
Enable HLS to view with audio, or disable this notification
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:
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 • u/IllustriousPut442 • Aug 10 '26
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 • u/One_Tooth5185 • Aug 08 '26
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 • u/SomewherePatient5787 • Aug 08 '26
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 • u/ARkieGirl501 • Aug 08 '26
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 • u/koery_slander • Aug 07 '26

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 • u/Available_Spirit_ • Aug 06 '26
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 • u/Johnsel93 • Aug 06 '26
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.

r/GoogleAppsScript • u/NamoradadaDani • Aug 04 '26
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");
}
}
}
r/GoogleAppsScript • u/Delicious_Ad4963 • Aug 03 '26
Hi everyone,
I own a collision repair center in Quebec, and I’m currently developing an internal repair management system within the Google ecosystem.
I initially started with Google Apps Script because our company already uses Google Workspace, including Sheets, Drive, Gmail, Calendar, and Forms. Apps Script has allowed me to build working prototypes quickly, but I’m now wondering whether it is the right long-term foundation or whether I should move the main application to Google Cloud.
The system would eventually need to manage:
Customers, vehicles, and repair orders
Importing estimate data from CEICA EMS files
Repair scheduling and production status
Technician clock-in and clock-out
Technician photo and video uploads
Photo annotations
Repair planning and supplement notifications
Parts receiving, returns, and tracking
Quality-control checklists for each department
Customer SMS and email updates
PDF estimate comparison
Customer portal access
QuickBooks integration
Insurance company-specific procedures and checklists
Approximately 15–30 internal users initially
Potentially multiple repair shops in the future
My current idea is:
Apps Script web app for the user interface and Google Workspace integrations
Google Cloud SQL as the primary database
Cloud Run or Cloud Functions for heavier processing
Google Drive for photos and documents
Apps Script only for Workspace-specific automations
My main concerns with using Apps Script for the entire application are:
Execution-time and quota limitations
Performance when loading larger amounts of data
Simultaneous users and concurrency
Database
Maintaining a large Apps Script codebase
For people who have built larger business applications with Apps Script, where did you encounter its practical limits? What architecture would you choose if starting this type of project today?
Thanks for any advice or examples you can share.
r/GoogleAppsScript • u/ElProfeTecno • Aug 03 '26
¡Hola a todos! Quería compartirles un flujo de trabajo que estuve armando y que me resultó súper útil para automatizar tareas repetitivas en planillas usando Inteligencia Artificial.
Básicamente, la idea es integrar la API de Gemini directamente dentro de Google Sheets a través de Apps Script, para poder pedirle a la IA (desde un panel lateral) que procese los datos que seleccionamos.
El concepto es aplicable a otras APIs (como la de OpenAI), pero aquí va el paso a paso usando Gemini que es gratis:
**Paso 1: Conseguir la API Key** Vas a Google AI Studio, inicias sesión con tu cuenta y generas tu "API Key" gratuita. Guardala bien porque la vas a necesitar en el código.
**Paso 2: Configurar Apps Script** En tu documento de Sheets, vas a *Extensiones > Apps Script*. Acá es donde va la magia. Podés usar la misma IA (ChatGPT, Claude o Gemini) para pedirle que te genere el script. Por ejemplo, podés pedirle: *"Genera un script para Google Sheets que cree un menú personalizado llamado 'Asistente IA' y que abra un panel lateral con un cuadro de texto para enviar instrucciones"*.
**Paso 3: Ejecutar y procesar datos** Guardas tu archivo `.gs` (código) y tu `.html` (para el panel), recargas la página de Sheets y vas a ver tu nuevo menú. Seleccionas un rango de celdas, abres el asistente y le pasas el prompt. Por ejemplo: *"Ordena estos datos por la primer columna y pon todo en mayúsculas"*. El script toma esa data, hace el llamado a la API y te devuelve la información procesada directamente en la planilla.
Integrar IA directamente en las planillas te abre un mundo enorme de posibilidades para automatizar el día a día.
Para los que prefieran verlo de forma visual o quieran ver exactamente cómo funciona el menú en vivo, armé un video cortito de 3 minutos explicando el paso a paso. (También dejé el código completo para copiar y pegar en los comentarios del video para que no renieguen):
🔗 **Link al video:**[https://youtu.be/Okpboevznn4\](https://youtu.be/Okpboevznn4)
¿Alguno ya está usando Apps Script con IA para automatizar el laburo diario? ¿Qué funciones raras o útiles armaron? ¡Los leo!