¿Qué son Google Ads Scripts?
Fragmentos de JavaScript que se ejecutan dentro de tu cuenta de Google Ads. Automatizan tareas que manualmente te llevarían horas.
Pausar campañas que gastan sin convertir
Enviarte alertas cuando algo va mal
Generar reportes automáticos
Monitorear quality score
Detectar anomalías en gasto
Verificar que tus anuncios están activos
✓ No necesitás ser programador. Los scripts están listos para copiar. Solo cambiás 2-3 variables (tu email, umbrales) y funcionan.
📍 Dónde pegar los scripts
- 1Google Ads → Tools & Settings (llave inglesa)
- 2Bulk Actions → Scripts
- 3Click "+" para nuevo script
- 4Pegá código + Authorize
- 5Preview (sin cambios reales)
- 6Run o programá frecuencia
⏱ Frecuencia de ejecución
SCRIPT
01
Alerta de Gasto Excesivo
El más importante · Detecta campañas desbocadas
⚙️ Qué hace
Te envía email si una campaña gasta más del 60% de su presupuesto antes de mediodía.
💡 Por qué lo necesitás
Si tu campaña tiene budget $50/día y a las 10am ya gastó $40 -> algo está mal (bot, keyword basura). El script avisa antes de que se vacíe.
1// ================================================2// ALERTA DE GASTO EXCESIVO3// Email si campaña gasta >60% antes de mediodía4// ================================================56function main() {7 var EMAIL = 'tu@email.com'; // <- CAMBIA ESTO8 var THRESHOLD = 0.6; // 60% del presupuesto9 var HOUR_LIMIT = 12; // Antes de las 12pm1011 var now = new Date();12 if (now.getHours() >= HOUR_LIMIT) return;1314 var campaigns = AdsApp.campaigns()15 .withCondition('Status = ENABLED')16 .withCondition('CampaignExperimentType = BASE')17 .get();1819 var alerts = [];20 while (campaigns.hasNext()) {21 var c = campaigns.next();22 var stats = c.getStatsFor('TODAY');23 var cost = stats.getCost();24 var budget = c.getBudget().getAmount();2526 if (budget > 0 && cost / budget >= THRESHOLD) {27 alerts.push({28 name: c.getName(),29 budget: budget.toFixed(2),30 spent: cost.toFixed(2),31 percent: (cost / budget * 100).toFixed(0)32 });33 }34 }3536 if (alerts.length > 0) {37 var body = 'Campañas con gasto >' + (THRESHOLD*100) + '%:\n\n';38 alerts.forEach(function(a) {39 body += '⚠️ ' + a.name + ': $' + a.spent +40 ' de $' + a.budget + ' (' + a.percent + '%)\n';41 });42 MailApp.sendEmail(EMAIL, '⚠️ Gasto excesivo Google Ads', body);43 }44}
SCRIPT
02
Pausar Keywords Sin Conversiones
Ahorra presupuesto · Ahorra $$$ en keywords muertos
⚙️ Qué hace
Pausa keywords que gastaron más de $50 sin generar conversiones en 30 días.
💡 Por qué lo necesitás
En cualquier cuenta hay keywords que queman dinero sin convertir. Este script los identifica y los apaga.
1// ================================================2// PAUSAR KEYWORDS SIN CONVERSIONES3// Pausa keywords que gastaron >$50 sin conversiones (30 días)4// ================================================56function main() {7 var COST_THRESHOLD = 50;8 var DATE_RANGE = 'LAST_30_DAYS';9 var EMAIL = 'tu@email.com';1011 var keywords = AdsApp.keywords()12 .withCondition('Status = ENABLED')13 .withCondition('CampaignStatus = ENABLED')14 .withCondition('AdGroupStatus = ENABLED')15 .withCondition('Conversions < 1')16 .withCondition('Cost > ' + COST_THRESHOLD)17 .forDateRange(DATE_RANGE)18 .orderBy('Cost DESC')19 .get();2021 var paused = [];22 while (keywords.hasNext()) {23 var kw = keywords.next();24 var s = kw.getStatsFor(DATE_RANGE);25 paused.push({26 keyword: kw.getText(),27 matchType: kw.getMatchType(),28 campaign: kw.getCampaign().getName(),29 cost: s.getCost().toFixed(2),30 clicks: s.getClicks()31 });32 kw.pause();33 }3435 if (paused.length > 0) {36 var body = 'Pausados ' + paused.length + ' keywords sin conversiones:\n\n';37 paused.forEach(function(p) {38 body += '🔴 "' + p.keyword + '" [' + p.matchType + ']\n' +39 ' ' + p.campaign + '\n' +40 ' Gasto: $' + p.cost + ' | Clicks: ' + p.clicks + '\n\n';41 });42 MailApp.sendEmail(EMAIL, '🔴 Keywords pausadas', body);43 }44}
SCRIPT
03
Reporte Semanal por Email
Lunes a las 8am · Resumen ejecutivo automático
⚙️ Qué hace
Cada lunes te llega un email con el resumen de la semana: gasto, conversiones, ROAS, CPA por campaña.
💡 Por qué lo necesitás
Sin tener que entrar a Google Ads cada lunes. Lo abrís desde el celular tomando el café.
1// ================================================2// REPORTE SEMANAL AUTOMÁTICO3// Email con resumen de los últimos 7 días4// ================================================56function main() {7 var EMAIL = 'tu@email.com';8 var ACCOUNT_NAME = 'Mi Empresa';910 var campaigns = AdsApp.campaigns()11 .withCondition('Status = ENABLED')12 .withCondition('Impressions > 0')13 .forDateRange('LAST_7_DAYS')14 .orderBy('Cost DESC')15 .get();1617 var totalCost=0, totalConv=0, totalValue=0;18 var rows = [];1920 while (campaigns.hasNext()) {21 var c = campaigns.next();22 var s = c.getStatsFor('LAST_7_DAYS');23 var cost = s.getCost(), conv = s.getConversions(), val = s.getConversionValue();24 var clicks = s.getClicks(), impr = s.getImpressions();25 var ctr = impr > 0 ? (clicks/impr*100) : 0;26 var cpa = conv > 0 ? cost/conv : 0;27 var roas = cost > 0 ? val/cost : 0;2829 totalCost += cost; totalConv += conv; totalValue += val;3031 rows.push(c.getName() + '\n' +32 ' $' + cost.toFixed(0) + ' | CTR ' + ctr.toFixed(1) + '% | ' +33 'Conv ' + conv.toFixed(0) + ' | CPA $' + cpa.toFixed(2) +34 ' | ROAS ' + roas.toFixed(2) + 'x\n');35 }3637 var totalRoas = totalCost > 0 ? totalValue/totalCost : 0;38 var totalCpa = totalConv > 0 ? totalCost/totalConv : 0;3940 var body = '📊 REPORTE SEMANAL - ' + ACCOUNT_NAME + '\n';41 body += '━━━━━━━━━━━━━━━━━━━━━━━━━━\n';42 body += '💰 Gasto: $' + totalCost.toFixed(0) + '\n';43 body += '📈 Conv: ' + totalConv.toFixed(0) + '\n';44 body += '💵 Revenue: $' + totalValue.toFixed(0) + '\n';45 body += '🎯 ROAS: ' + totalRoas.toFixed(2) + 'x\n';46 body += '💸 CPA: $' + totalCpa.toFixed(2) + '\n\n';47 body += rows.join('\n');4849 MailApp.sendEmail(EMAIL, '📊 Reporte Semanal - ' + ACCOUNT_NAME, body);50}
SCRIPT
04
Monitor de Quality Score
QS bajo = CPC alto · Identifica keywords caros
⚙️ Qué hace
Identifica keywords con Quality Score <=5 que están gastando dinero. QS bajo = CPC más alto.
💡 Por qué lo necesitás
Cada punto de QS bajo te cuesta hasta 30% más en CPC. Mejorar QS es la forma más barata de bajar costos.
1// ================================================2// MONITOR DE QUALITY SCORE3// Alerta sobre keywords con QS <=5 que están gastando4// ================================================56function main() {7 var EMAIL = 'tu@email.com';8 var QS_THRESHOLD = 5;9 var DATE_RANGE = 'LAST_30_DAYS';1011 var report = AdsApp.report(12 'SELECT CampaignName, AdGroupName, Criteria, QualityScore, ' +13 'Cost, Impressions, Clicks, Conversions ' +14 'FROM KEYWORDS_PERFORMANCE_REPORT ' +15 'WHERE Status = ENABLED AND CampaignStatus = ENABLED ' +16 'AND HasQualityScore = TRUE ' +17 'AND QualityScore <= ' + QS_THRESHOLD + ' ' +18 'AND Impressions > 100 ' +19 'DURING ' + DATE_RANGE);2021 var rows = report.rows();22 var alerts = [];23 while (rows.hasNext()) {24 var r = rows.next();25 alerts.push({26 campaign: r['CampaignName'],27 keyword: r['Criteria'],28 qs: r['QualityScore'],29 cost: r['Cost'],30 conv: r['Conversions']31 });32 }3334 if (alerts.length > 0) {35 var body = '⚠️ ' + alerts.length + ' keywords con QS <= ' + QS_THRESHOLD + ':\n\n';36 alerts.forEach(function(a) {37 body += '🔶 "' + a.keyword + '" - QS: ' + a.qs + '/10\n' +38 ' ' + a.campaign + ' | Gasto: ' + a.cost + ' | Conv: ' + a.conv + '\n\n';39 });40 body += '\n📋 ACCIONES:\n';41 body += '• QS 1-3: Revisar keyword vs ad copy vs landing\n';42 body += '• QS 4-5: Mejorar ad copy o landing\n';43 body += '• Sin mejora en 2 semanas: pausar y reemplazar';4445 MailApp.sendEmail(EMAIL, '⚠️ Quality Score bajo', body);46 }47}
SCRIPT
05
Detector de Anomalías
Spike o caída inusual · Detecta fraude / problemas técnicos
⚙️ Qué hace
Compara gasto/clicks de hoy vs promedio de últimos 7 días. Alerta si hay desviación >50%.
💡 Por qué lo necesitás
Detecta: campañas que de repente gastan el doble (fraude de clicks) o dejaron de gastar (anuncio desaprobado).
1// ================================================2// DETECTOR DE ANOMALÍAS3// Alerta si gasto o clicks difieren >50% del promedio4// ================================================56function main() {7 var EMAIL = 'tu@email.com';8 var DEVIATION_THRESHOLD = 0.5;910 var todayData = {};11 var today = AdsApp.campaigns()12 .withCondition('Status = ENABLED').forDateRange('TODAY').get();13 while (today.hasNext()) {14 var c = today.next();15 var s = c.getStatsFor('TODAY');16 todayData[c.getName()] = { cost: s.getCost(), clicks: s.getClicks() };17 }1819 var avgData = {};20 var c7 = AdsApp.campaigns().withCondition('Status = ENABLED')21 .forDateRange('LAST_7_DAYS').get();22 while (c7.hasNext()) {23 var c = c7.next();24 var s = c.getStatsFor('LAST_7_DAYS');25 avgData[c.getName()] = { avgCost: s.getCost()/7, avgClicks: s.getClicks()/7 };26 }2728 var anomalies = [];29 for (var name in todayData) {30 if (avgData[name] && avgData[name].avgCost > 1) {31 var costDev = (todayData[name].cost - avgData[name].avgCost) / avgData[name].avgCost;32 if (Math.abs(costDev) > DEVIATION_THRESHOLD) {33 anomalies.push({34 name: name,35 todayCost: todayData[name].cost.toFixed(2),36 avgCost: avgData[name].avgCost.toFixed(2),37 costDev: (costDev*100).toFixed(0)38 });39 }40 }41 }4243 if (anomalies.length > 0) {44 var body = '🔍 Anomalías detectadas:\n\n';45 anomalies.forEach(function(a) {46 var emoji = parseInt(a.costDev) > 0 ? '📈' : '📉';47 body += emoji + ' ' + a.name + '\n' +48 ' Hoy: $' + a.todayCost + ' (avg: $' + a.avgCost + ') -> ' + a.costDev + '%\n\n';49 });50 MailApp.sendEmail(EMAIL, '🔍 Anomalía Google Ads', body);51 }52}
SCRIPT
06
Verificar Anuncios Activos
Anti-desaprobaciones · Cero anuncios apagados
⚙️ Qué hace
Revisa que no haya anuncios desaprobados ni campañas sin servir. Alerta si encuentra problemas.
💡 Por qué lo necesitás
Un anuncio desaprobado puede dejar tu campaña sin servir por días sin que te enteres.
1// ================================================2// VERIFICAR ANUNCIOS ACTIVOS3// Alerta sobre desaprobados o campañas sin impresiones4// ================================================56function main() {7 var EMAIL = 'tu@email.com';8 var issues = [];910 // Anuncios desaprobados11 var ads = AdsApp.ads()12 .withCondition('CampaignStatus = ENABLED')13 .withCondition('AdGroupStatus = ENABLED')14 .withCondition('PolicyApprovalStatus = DISAPPROVED')15 .get();1617 while (ads.hasNext()) {18 var ad = ads.next();19 issues.push('🔴 DESAPROBADO: ' + ad.getHeadlinePart1() +20 ' | ' + ad.getCampaign().getName());21 }2223 // Campañas habilitadas sin impresiones (después de 2pm)24 if (new Date().getHours() >= 14) {25 var camps = AdsApp.campaigns()26 .withCondition('Status = ENABLED')27 .withCondition('Impressions = 0')28 .forDateRange('TODAY').get();2930 while (camps.hasNext()) {31 var c = camps.next();32 if (c.getBudget().getAmount() > 0) {33 issues.push('⚠️ SIN IMPRESIONES: ' + c.getName() +34 ' (Budget: $' + c.getBudget().getAmount() + ')');35 }36 }37 }3839 if (issues.length > 0) {40 MailApp.sendEmail(EMAIL, '🚨 Problemas Google Ads',41 issues.length + ' problemas:\n\n' + issues.join('\n\n'));42 }43}
SCRIPT
07
Search Terms Basura
Encuentra negative keywords · Te dice cuánto $ desperdiciás
⚙️ Qué hace
Reporte de search terms que activaron tus ads, gastaron dinero y NO convirtieron.
💡 Por qué lo necesitás
El subject del email te dice EXACTAMENTE cuánto dinero estás desperdiciando. Brutal pero útil.
1// ================================================2// SEARCH TERMS SIN CONVERSIONES3// Encuentra terms que gastan tu presupuesto sin convertir4// ================================================56function main() {7 var EMAIL = 'tu@email.com';8 var MIN_COST = 10;9 var DATE_RANGE = 'LAST_30_DAYS';1011 var report = AdsApp.report(12 'SELECT Query, CampaignName, Cost, Clicks, Conversions, Ctr ' +13 'FROM SEARCH_QUERY_PERFORMANCE_REPORT ' +14 'WHERE Conversions < 1 AND Cost > ' + (MIN_COST * 1000000) + ' ' +15 'DURING ' + DATE_RANGE);1617 var rows = report.rows();18 var terms = [];19 var totalWasted = 0;2021 while (rows.hasNext()) {22 var r = rows.next();23 var cost = parseFloat(r['Cost'].replace(/,/g, ''));24 totalWasted += cost;25 terms.push({26 query: r['Query'],27 campaign: r['CampaignName'],28 cost: cost.toFixed(2),29 clicks: r['Clicks']30 });31 }3233 terms.sort(function(a, b) { return parseFloat(b.cost) - parseFloat(a.cost); });3435 if (terms.length > 0) {36 var body = '💸 Total desperdiciado: $' + totalWasted.toFixed(2) + '\n';37 body += 'Terms: ' + terms.length + '\n\n';3839 terms.slice(0, 30).forEach(function(t) {40 body += '❌ "' + t.query + '"\n' +41 ' ' + t.campaign + ' | $' + t.cost + ' | Clicks: ' + t.clicks + '\n\n';42 });43 body += '\n📋 Agregar como negative keywords.';4445 MailApp.sendEmail(EMAIL,46 '💸 $' + totalWasted.toFixed(0) + ' desperdiciados sin conversión', body);47 }48}
SCRIPT
08
Auto-Pausar por Horario
Para negocios locales · No gastes a las 3am
⚙️ Qué hace
Pausa campañas fuera de horario de negocio (ej: 8am-10pm) y las reactiva sola.
💡 Por qué lo necesitás
Útil para restaurantes, servicios locales, cualquier negocio que no atiende 24/7.
1// ================================================2// PAUSAR/ACTIVAR POR HORARIO3// Activa 8am-10pm, pausa 10pm-8am4// ================================================56function main() {7 var CAMPAIGN_LABEL = 'horario-limitado';8 var START_HOUR = 8;9 var END_HOUR = 22;1011 var currentHour = new Date().getHours();12 var shouldBeActive = currentHour >= START_HOUR && currentHour < END_HOUR;1314 var campaigns = AdsApp.campaigns()15 .withCondition("LabelNames CONTAINS_ANY ['" + CAMPAIGN_LABEL + "']")16 .get();1718 while (campaigns.hasNext()) {19 var c = campaigns.next();2021 if (shouldBeActive && c.isPaused()) {22 c.enable();23 Logger.log('✅ Activada: ' + c.getName());24 } else if (!shouldBeActive && c.isEnabled()) {25 c.pause();26 Logger.log('⏸️ Pausada: ' + c.getName());27 }28 }29}3031// SETUP:32// 1. En Google Ads: agrega label "horario-limitado" a las campañas33// 2. Frecuencia del script: cada hora34// 3. Ajusta START_HOUR / END_HOUR a tu horario
SCRIPT
09
Monitor de Presupuesto Mensual
Anti-sobregasto · No te excedés de tu budget
⚙️ Qué hace
Calcula cuánto del budget mensual llevás gastado y proyecta fin de mes. Alerta si excedés o subgastás.
💡 Por qué lo necesitás
El budget diario de Google Ads es engañoso (puede gastar hasta 2x en un día). Este script te dice si vas a terminar bien.
1// ================================================2// MONITOR DE PRESUPUESTO MENSUAL3// Alerta si vas a exceder o subgastar el budget mensual4// ================================================56function main() {7 var EMAIL = 'tu@email.com';8 var MONTHLY_BUDGET = 3000; // <- Tu budget mensual910 var now = new Date();11 var dayOfMonth = now.getDate();12 var daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();13 var daysRemaining = daysInMonth - dayOfMonth;1415 var firstDay = Utilities.formatDate(16 new Date(now.getFullYear(), now.getMonth(), 1),17 'America/Los_Angeles', 'yyyyMMdd');18 var today = Utilities.formatDate(now, 'America/Los_Angeles', 'yyyyMMdd');1920 var report = AdsApp.report(21 'SELECT Cost FROM ACCOUNT_PERFORMANCE_REPORT DURING ' + firstDay + ',' + today);22 var rows = report.rows();23 var totalSpent = 0;24 while (rows.hasNext()) {25 totalSpent += parseFloat(rows.next()['Cost'].replace(/,/g, ''));26 }2728 var dailyAvg = totalSpent / dayOfMonth;29 var projected = totalSpent + (dailyAvg * daysRemaining);30 var percentUsed = (totalSpent / MONTHLY_BUDGET * 100);31 var expectedPercent = (dayOfMonth / daysInMonth * 100);3233 var status = '🟢 En ritmo normal';34 var sendAlert = false;3536 if (percentUsed > expectedPercent * 1.2) {37 status = '🔴 EXCEDIENDO RITMO'; sendAlert = true;38 } else if (percentUsed < expectedPercent * 0.7) {39 status = '🟡 MUY POR DEBAJO'; sendAlert = true;40 }4142 if (sendAlert) {43 var body = '📊 PRESUPUESTO MENSUAL\n\n';44 body += 'Budget: $' + MONTHLY_BUDGET + '\n';45 body += 'Gastado (día ' + dayOfMonth + '): $' + totalSpent.toFixed(2) + '\n';46 body += 'Usado: ' + percentUsed.toFixed(1) + '% (esperado: ' + expectedPercent.toFixed(1) + '%)\n';47 body += 'Proyección: $' + projected.toFixed(2) + '\n';48 body += 'Status: ' + status;4950 MailApp.sendEmail(EMAIL, status + ' — Budget Google Ads', body);51 }52}
SCRIPT
10
Exportar a Google Sheets
Dashboard automático · Dashboard en vivo
⚙️ Qué hace
Envía datos de performance a un Google Sheet automáticamente. Creás dashboard + gráficos.
💡 Por qué lo necesitás
Compartís el Sheet con tu equipo, jefe o cliente. Se actualiza solo todos los días.
1// ================================================2// EXPORTAR A GOOGLE SHEETS3// Actualiza un Sheet con datos de campañas diariamente4// ================================================56function main() {7 var SHEET_URL = 'https://docs.google.com/spreadsheets/d/TU_SHEET_ID/edit';8 var SHEET_NAME = 'Datos';910 var ss = SpreadsheetApp.openByUrl(SHEET_URL);11 var sheet = ss.getSheetByName(SHEET_NAME) || ss.insertSheet(SHEET_NAME);1213 var headers = ['Fecha', 'Campaña', 'Tipo', 'Gasto', 'Impresiones',14 'Clicks', 'CTR', 'Conv', 'Valor', 'CPA', 'ROAS'];1516 var today = Utilities.formatDate(new Date(), 'America/Los_Angeles', 'yyyy-MM-dd');1718 // Borrar duplicados de hoy19 var data = sheet.getDataRange().getValues();20 for (var i = data.length - 1; i >= 1; i--) {21 if (data[i][0] === today) sheet.deleteRow(i + 1);22 }2324 if (sheet.getLastRow() === 0) {25 sheet.appendRow(headers);26 sheet.getRange(1, 1, 1, headers.length).setFontWeight('bold');27 }2829 var campaigns = AdsApp.campaigns()30 .withCondition('Status = ENABLED')31 .withCondition('Impressions > 0')32 .forDateRange('TODAY').get();3334 while (campaigns.hasNext()) {35 var c = campaigns.next();36 var s = c.getStatsFor('TODAY');37 var cost = s.getCost(), conv = s.getConversions(),38 val = s.getConversionValue(), clicks = s.getClicks(), impr = s.getImpressions();3940 sheet.appendRow([41 today, c.getName(), c.getAdvertisingChannelType(),42 cost, impr, clicks,43 impr > 0 ? (clicks/impr) : 0,44 conv, val,45 conv > 0 ? cost/conv : 0,46 cost > 0 ? val/cost : 047 ]);48 }4950 Logger.log('✅ Exportado: ' + today);51}
Cómo instalar en 2 minutos
⚠️ SIEMPRE usá Preview antes de activar. Preview ejecuta el script pero NO hace cambios reales (no pausa nada, no envía emails). Solo te muestra qué HARÍA.
Scripts más impactantes por tipo de negocio
Ecommerce
Empezá con
Negocio local
Empezá con
Agencia (multi-cliente)
Empezá con

José Moreno
Fundador · Web PremiereFundador de Web Premiere y Signal Lab. Especialista en publicidad digital con 13 años de experiencia en Google Ads, Meta Ads y marketing de resultados para empresas en LATAM y USA. Invitado al programa Google Partners LEAD en Silicon Valley.