Google Ads · Automação · Código prático

Google Ads Scripts: 5 scripts completos + 3 extras para gestores

Cinco códigos completos para monitorar orçamento, gasto sem conversão, termos e anomalias, mais três extras e guias específicos para instalar, registrar histórico no Google Sheets e revisar alertas sem decisões automáticas cegas.

Atualizado em 2 de agosto de 2026 Por Thiago Scarmeloto 5 scripts completos no artigo
Ver os scripts
Resposta direta Google Ads Scripts são códigos em JavaScript executados dentro da conta para consultar dados, criar relatórios e emitir alertas. Eles ajudam o gestor a perceber problemas mais cedo e dão ao dono da empresa uma camada adicional de controle, mas não substituem tracking, análise comercial ou decisão humana.

Uma empresa não precisa transformar o dono em programador para usar automação no Google Ads. O que ela precisa é definir quais riscos não podem depender de alguém lembrar de abrir a conta: orçamento acelerando, campanhas gastando sem conversão, termos ruins, queda repentina de volume, anúncios reprovados ou páginas quebradas.

É justamente aí que os scripts são mais úteis. Em vez de prometer uma “otimização automática” impossível de generalizar, os exemplos abaixo trabalham como uma camada de monitoramento, governança e diagnóstico. Eles consultam a conta, organizam o que merece atenção e enviam o alerta. A decisão continua com quem conhece o negócio.

Regra de segurança desta biblioteca Nenhum código desta página pausa campanhas, muda lances, altera orçamento ou adiciona palavra negativa. Primeiro vem o alerta; depois vêm a análise e a decisão.

O que um Google Ads Script pode, e o que ele não deveria decidir sozinho

  • Consultar métricas com GAQL e comparar períodos.
  • Enviar alertas por e-mail e registrar dados em Google Sheets.
  • Encontrar anomalias, reprovações e possíveis URLs quebradas.
  • Reduzir tarefas repetitivas sem esconder o que foi analisado.

Por outro lado, um script não conhece sozinho sua margem, o prazo médio de venda, as importações offline atrasadas, a qualidade dos leads, a sazonalidade nem o que aconteceu no CRM. Por isso, automatizar uma pausa com base apenas em CPA ou ROAS pode economizar verba em um cenário e destruir uma campanha saudável em outro.

Como instalar qualquer um destes scripts

  1. Entre na conta correta do Google Ads e abra Ferramentas → Ações em massa → Scripts.
  2. Crie um script novo e cole somente um código por vez.
  3. Edite o bloco CONFIG, principalmente e-mail, orçamento, período e limites.
  4. Autorize as permissões solicitadas pelo Google.
  5. Clique primeiro em Visualizar e confira o log.
  6. Compare os números com a interface da conta e só depois programe a frequência.

Guias específicos deste cluster

5 scripts completos para copiar e adaptar

01

Alerta de ritmo do orçamento mensal

Compara o gasto acumulado com o orçamento mensal informado e calcula uma projeção simples até o fim do mês. Ele é útil para encontrar dois problemas diferentes: verba acabando cedo demais ou ritmo muito abaixo do planejado.

Para o gestor Evita descobrir o desvio no fechamento
Para a empresa Torna o ritmo da verba visível
Frequência Diária
/**
 * ALERTA DE RITMO DO ORÇAMENTO MENSAL
 * Google Ads Scripts, conta individual
 *
 * O script NÃO altera campanhas. Ele compara o gasto acumulado com o
 * orçamento mensal informado e envia um alerta quando o ritmo preocupa.
 *
 * Antes de usar:
 * 1. Troque EMAIL.
 * 2. Troque MONTHLY_BUDGET pelo orçamento mensal da conta.
 * 3. Rode em "Visualizar".
 * 4. Agende diariamente, preferencialmente após 10h.
 */

const CONFIG = {
  EMAIL: 'seu-email@empresa.com.br',
  MONTHLY_BUDGET: 10000,
  ALERT_WHEN_USED_PERCENT: 85,
  PROJECTED_OVERSPEND_TOLERANCE_PERCENT: 5
};

function main() {
  validateConfig();

  const account = AdsApp.currentAccount();
  const timezone = account.getTimeZone();
  const today = new Date();
  const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);
  const monthEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0);

  const metrics = getAccountMetrics(monthStart, today, timezone);
  const spent = metrics.cost;
  const elapsedDays = Math.max(today.getDate(), 1);
  const totalDays = monthEnd.getDate();
  const expectedByToday = CONFIG.MONTHLY_BUDGET * (elapsedDays / totalDays);
  const projectedSpend = (spent / elapsedDays) * totalDays;
  const usedPercent = CONFIG.MONTHLY_BUDGET > 0
    ? (spent / CONFIG.MONTHLY_BUDGET) * 100
    : 0;
  const projectedLimit = CONFIG.MONTHLY_BUDGET *
    (1 + CONFIG.PROJECTED_OVERSPEND_TOLERANCE_PERCENT / 100);

  const shouldAlert =
    usedPercent >= CONFIG.ALERT_WHEN_USED_PERCENT ||
    projectedSpend > projectedLimit;

  const summary = [
    `Conta: ${account.getName()} (${account.getCustomerId()})`,
    `Gasto acumulado: ${money(spent)}`,
    `Orçamento mensal informado: ${money(CONFIG.MONTHLY_BUDGET)}`,
    `Orçamento consumido: ${usedPercent.toFixed(1)}%`,
    `Ritmo esperado até hoje: ${money(expectedByToday)}`,
    `Projeção no fim do mês: ${money(projectedSpend)}`,
    `Dias decorridos: ${elapsedDays} de ${totalDays}`
  ].join('\n');

  Logger.log(summary);

  if (!shouldAlert) {
    Logger.log('Nenhum alerta enviado: ritmo dentro dos limites configurados.');
    return;
  }

  MailApp.sendEmail(
    CONFIG.EMAIL,
    `[Google Ads] Alerta de ritmo de orçamento, ${account.getName()}`,
    `${summary}\n\nRevise contexto, sazonalidade e qualidade das conversões antes de reduzir investimento.`
  );
}

function getAccountMetrics(startDate, endDate, timezone) {
  const query = `
    SELECT metrics.cost_micros
    FROM customer
    WHERE segments.date BETWEEN '${dateForQuery(startDate, timezone)}'
      AND '${dateForQuery(endDate, timezone)}'
  `;

  const rows = AdsApp.search(query);
  let costMicros = 0;

  while (rows.hasNext()) {
    const row = rows.next();
    costMicros += Number(row.metrics.costMicros || 0);
  }

  return {cost: costMicros / 1e6};
}

function dateForQuery(date, timezone) {
  return Utilities.formatDate(date, timezone, 'yyyy-MM-dd');
}

function money(value) {
  return Number(value || 0).toLocaleString('pt-BR', {
    style: 'currency',
    currency: AdsApp.currentAccount().getCurrencyCode()
  });
}

function validateConfig() {
  if (!/@/.test(CONFIG.EMAIL)) {
    throw new Error('Configure um e-mail válido em CONFIG.EMAIL.');
  }
  if (!(CONFIG.MONTHLY_BUDGET > 0)) {
    throw new Error('CONFIG.MONTHLY_BUDGET precisa ser maior que zero.');
  }
}
02

Campanhas com gasto e zero conversões

Lista campanhas ativas que ultrapassaram um limite de investimento sem registrar conversões no período. O alerta é um ponto de partida: antes de pausar, verifique atraso de conversão, importações offline, ação primária, CRM e integridade do tracking.

Para o gestor Prioriza o que revisar primeiro
Para a empresa Expõe gasto sem resultado registrado
Frequência Diária
/**
 * CAMPANHAS COM GASTO E ZERO CONVERSÕES
 * Google Ads Scripts, conta individual
 *
 * O script é somente leitura: não pausa nem modifica campanhas.
 *
 * Antes de usar:
 * 1. Ajuste EMAIL, LOOKBACK_DAYS e MIN_COST.
 * 2. Confirme se a coluna "Conversões" da conta representa a ação certa.
 * 3. Rode em "Visualizar".
 * 4. Agende diariamente.
 */

const CONFIG = {
  EMAIL: 'seu-email@empresa.com.br',
  LOOKBACK_DAYS: 7,
  MIN_COST: 200,
  MAX_ROWS: 50
};

function main() {
  validateConfig();

  const account = AdsApp.currentAccount();
  const timezone = account.getTimeZone();
  const endDate = new Date();
  const startDate = addDays(endDate, -(CONFIG.LOOKBACK_DAYS - 1));

  const minCostMicros = Math.round(CONFIG.MIN_COST * 1e6);
  const query = `
    SELECT
      campaign.id,
      campaign.name,
      campaign.status,
      metrics.cost_micros,
      metrics.clicks,
      metrics.conversions
    FROM campaign
    WHERE segments.date BETWEEN '${dateForQuery(startDate, timezone)}'
      AND '${dateForQuery(endDate, timezone)}'
      AND campaign.status = 'ENABLED'
      AND metrics.cost_micros >= ${minCostMicros}
      AND metrics.conversions = 0
    ORDER BY metrics.cost_micros DESC
    LIMIT ${CONFIG.MAX_ROWS}
  `;

  const rows = AdsApp.search(query);
  const problems = [];

  while (rows.hasNext()) {
    const row = rows.next();
    problems.push({
      id: row.campaign.id,
      name: row.campaign.name,
      cost: Number(row.metrics.costMicros || 0) / 1e6,
      clicks: Number(row.metrics.clicks || 0),
      conversions: Number(row.metrics.conversions || 0)
    });
  }

  if (!problems.length) {
    Logger.log('Nenhuma campanha ativa atingiu o limite com zero conversões.');
    return;
  }

  const lines = problems.map((item, index) =>
    `${index + 1}. ${item.name} [${item.id}], ` +
    `${money(item.cost)} | ${item.clicks} cliques | ${item.conversions} conversões`
  );

  const body = [
    `Conta: ${account.getName()} (${account.getCustomerId()})`,
    `Período: últimos ${CONFIG.LOOKBACK_DAYS} dias`,
    `Critério: gasto mínimo de ${money(CONFIG.MIN_COST)} e zero conversões`,
    '',
    ...lines,
    '',
    'Antes de pausar, confira atraso de conversão, importações offline, CRM, tracking e tipo de campanha.'
  ].join('\n');

  Logger.log(body);
  MailApp.sendEmail(
    CONFIG.EMAIL,
    `[Google Ads] Gasto sem conversão, ${account.getName()}`,
    body
  );
}

function addDays(date, days) {
  const copy = new Date(date.getTime());
  copy.setDate(copy.getDate() + days);
  return copy;
}

function dateForQuery(date, timezone) {
  return Utilities.formatDate(date, timezone, 'yyyy-MM-dd');
}

function money(value) {
  return Number(value || 0).toLocaleString('pt-BR', {
    style: 'currency',
    currency: AdsApp.currentAccount().getCurrencyCode()
  });
}

function validateConfig() {
  if (!/@/.test(CONFIG.EMAIL)) {
    throw new Error('Configure um e-mail válido em CONFIG.EMAIL.');
  }
  if (!(CONFIG.LOOKBACK_DAYS >= 1 && CONFIG.LOOKBACK_DAYS <= 90)) {
    throw new Error('LOOKBACK_DAYS deve ficar entre 1 e 90.');
  }
  if (CONFIG.MIN_COST < 0) {
    throw new Error('MIN_COST não pode ser negativo.');
  }
}
03

Termos de pesquisa com possível desperdício

Localiza termos que consumiram um valor mínimo e não registraram conversões. Ele não adiciona negativas automaticamente porque intenção, correspondência e contexto precisam ser avaliados. A visualização tradicional usada aqui não inclui Performance Max.

Para o gestor Acelera a revisão de consultas
Para a empresa Mostra onde a intenção pode estar errada
Frequência Semanal
/**
 * TERMOS DE PESQUISA COM GASTO E ZERO CONVERSÕES
 * Google Ads Scripts, conta individual
 *
 * Somente leitura. O script NÃO adiciona palavras negativas.
 * A search_term_view tradicional não inclui dados de Performance Max.
 *
 * Antes de usar:
 * 1. Ajuste EMAIL, LOOKBACK_DAYS e MIN_COST.
 * 2. Rode em "Visualizar".
 * 3. Analise intenção e correspondência antes de negativar qualquer termo.
 */

const CONFIG = {
  EMAIL: 'seu-email@empresa.com.br',
  LOOKBACK_DAYS: 30,
  MIN_COST: 50,
  MAX_ROWS: 100
};

function main() {
  validateConfig();

  const account = AdsApp.currentAccount();
  const timezone = account.getTimeZone();
  const endDate = new Date();
  const startDate = addDays(endDate, -(CONFIG.LOOKBACK_DAYS - 1));
  const minCostMicros = Math.round(CONFIG.MIN_COST * 1e6);

  const query = `
    SELECT
      campaign.name,
      ad_group.name,
      search_term_view.search_term,
      metrics.impressions,
      metrics.clicks,
      metrics.cost_micros,
      metrics.conversions
    FROM search_term_view
    WHERE segments.date BETWEEN '${dateForQuery(startDate, timezone)}'
      AND '${dateForQuery(endDate, timezone)}'
      AND metrics.cost_micros >= ${minCostMicros}
      AND metrics.conversions = 0
    ORDER BY metrics.cost_micros DESC
    LIMIT ${CONFIG.MAX_ROWS}
  `;

  const rows = AdsApp.search(query);
  const terms = [];

  while (rows.hasNext()) {
    const row = rows.next();
    terms.push({
      campaign: row.campaign.name,
      adGroup: row.adGroup.name,
      term: row.searchTermView.searchTerm,
      impressions: Number(row.metrics.impressions || 0),
      clicks: Number(row.metrics.clicks || 0),
      cost: Number(row.metrics.costMicros || 0) / 1e6
    });
  }

  if (!terms.length) {
    Logger.log('Nenhum termo atingiu o limite configurado.');
    return;
  }

  const lines = terms.map((item, index) =>
    `${index + 1}. "${item.term}", ${money(item.cost)} | ` +
    `${item.clicks} cliques | Campanha: ${item.campaign} | Grupo: ${item.adGroup}`
  );

  const body = [
    `Conta: ${account.getName()} (${account.getCustomerId()})`,
    `Período: últimos ${CONFIG.LOOKBACK_DAYS} dias`,
    `Critério: gasto mínimo de ${money(CONFIG.MIN_COST)} e zero conversões`,
    '',
    ...lines,
    '',
    'Observação: a search_term_view não inclui Performance Max. Revise intenção, volume e atribuição antes de negativar.'
  ].join('\n');

  Logger.log(body);
  MailApp.sendEmail(
    CONFIG.EMAIL,
    `[Google Ads] Termos com possível desperdício, ${account.getName()}`,
    body
  );
}

function addDays(date, days) {
  const copy = new Date(date.getTime());
  copy.setDate(copy.getDate() + days);
  return copy;
}

function dateForQuery(date, timezone) {
  return Utilities.formatDate(date, timezone, 'yyyy-MM-dd');
}

function money(value) {
  return Number(value || 0).toLocaleString('pt-BR', {
    style: 'currency',
    currency: AdsApp.currentAccount().getCurrencyCode()
  });
}

function validateConfig() {
  if (!/@/.test(CONFIG.EMAIL)) {
    throw new Error('Configure um e-mail válido em CONFIG.EMAIL.');
  }
  if (!(CONFIG.LOOKBACK_DAYS >= 1 && CONFIG.LOOKBACK_DAYS <= 90)) {
    throw new Error('LOOKBACK_DAYS deve ficar entre 1 e 90.');
  }
}
04

Resumo diário para o gestor e o dono da empresa

Envia os principais indicadores de ontem em um e-mail legível. O objetivo não é transformar ROAS da plataforma em verdade financeira, mas criar uma rotina em que investimento, conversões e valor registrado sejam vistos junto com o lembrete de conferir CRM, receita e margem.

Para o gestor Padroniza a leitura diária
Para a empresa Reduz dependência de print manual
Frequência Diária após 3h
/**
 * RESUMO DIÁRIO DA CONTA POR E-MAIL
 * Google Ads Scripts, conta individual
 *
 * Envia os números de ontem em formato direto para gestor e empresa.
 * Não altera campanhas.
 *
 * Agende diariamente depois das 3h no fuso da conta, porque os dados podem
 * sofrer atraso e ajustes.
 */

const CONFIG = {
  EMAIL: 'seu-email@empresa.com.br'
};

function main() {
  validateConfig();

  const account = AdsApp.currentAccount();
  const timezone = account.getTimeZone();
  const yesterday = addDays(new Date(), -1);
  const metrics = getMetrics(yesterday, yesterday, timezone);

  const ctr = metrics.impressions > 0
    ? (metrics.clicks / metrics.impressions) * 100
    : 0;
  const cpc = metrics.clicks > 0 ? metrics.cost / metrics.clicks : 0;
  const cpa = metrics.conversions > 0
    ? metrics.cost / metrics.conversions
    : null;
  const roas = metrics.cost > 0
    ? metrics.conversionValue / metrics.cost
    : null;

  const body = [
    `Conta: ${account.getName()} (${account.getCustomerId()})`,
    `Data analisada: ${dateForHuman(yesterday, timezone)}`,
    '',
    `Impressões: ${integer(metrics.impressions)}`,
    `Cliques: ${integer(metrics.clicks)}`,
    `CTR: ${ctr.toFixed(2)}%`,
    `Investimento: ${money(metrics.cost)}`,
    `CPC médio: ${money(cpc)}`,
    `Conversões: ${decimal(metrics.conversions)}`,
    `CPA: ${cpa === null ? 'sem cálculo' : money(cpa)}`,
    `Valor de conversão: ${money(metrics.conversionValue)}`,
    `ROAS da plataforma: ${roas === null ? 'sem cálculo' : roas.toFixed(2) + 'x'}`,
    '',
    'O resumo mostra dados do Google Ads. Confirme vendas, margem e qualidade no CRM antes de tomar decisões.'
  ].join('\n');

  Logger.log(body);
  MailApp.sendEmail(
    CONFIG.EMAIL,
    `[Google Ads] Resumo de ontem, ${account.getName()}`,
    body
  );
}

function getMetrics(startDate, endDate, timezone) {
  const query = `
    SELECT
      metrics.impressions,
      metrics.clicks,
      metrics.cost_micros,
      metrics.conversions,
      metrics.conversions_value
    FROM customer
    WHERE segments.date BETWEEN '${dateForQuery(startDate, timezone)}'
      AND '${dateForQuery(endDate, timezone)}'
  `;

  const rows = AdsApp.search(query);
  const total = {
    impressions: 0,
    clicks: 0,
    cost: 0,
    conversions: 0,
    conversionValue: 0
  };

  while (rows.hasNext()) {
    const row = rows.next();
    total.impressions += Number(row.metrics.impressions || 0);
    total.clicks += Number(row.metrics.clicks || 0);
    total.cost += Number(row.metrics.costMicros || 0) / 1e6;
    total.conversions += Number(row.metrics.conversions || 0);
    total.conversionValue += Number(row.metrics.conversionsValue || 0);
  }

  return total;
}

function addDays(date, days) {
  const copy = new Date(date.getTime());
  copy.setDate(copy.getDate() + days);
  return copy;
}

function dateForQuery(date, timezone) {
  return Utilities.formatDate(date, timezone, 'yyyy-MM-dd');
}

function dateForHuman(date, timezone) {
  return Utilities.formatDate(date, timezone, 'dd/MM/yyyy');
}

function money(value) {
  return Number(value || 0).toLocaleString('pt-BR', {
    style: 'currency',
    currency: AdsApp.currentAccount().getCurrencyCode()
  });
}

function integer(value) {
  return Math.round(Number(value || 0)).toLocaleString('pt-BR');
}

function decimal(value) {
  return Number(value || 0).toLocaleString('pt-BR', {
    maximumFractionDigits: 2
  });
}

function validateConfig() {
  if (!/@/.test(CONFIG.EMAIL)) {
    throw new Error('Configure um e-mail válido em CONFIG.EMAIL.');
  }
}
05

Comparativo de sete dias e alerta de anomalias

Compara os últimos sete dias completos com os sete anteriores e avisa quando custo, conversões, CPA, valor de conversão ou ROAS ultrapassam a variação configurada. É uma versão simples e transparente do princípio usado no detector oficial de anomalias do Google.

Para o gestor Encontra mudança antes da reunião
Para a empresa Ajuda a perguntar o que mudou
Frequência Diária ou semanal
/**
 * COMPARATIVO DOS ÚLTIMOS 7 DIAS CONTRA OS 7 DIAS ANTERIORES
 * Google Ads Scripts, conta individual
 *
 * O script alerta sobre mudanças relevantes em custo, conversões, CPA e ROAS.
 * Não modifica campanhas.
 */

const CONFIG = {
  EMAIL: 'seu-email@empresa.com.br',
  ALERT_VARIATION_PERCENT: 25
};

function main() {
  validateConfig();

  const account = AdsApp.currentAccount();
  const timezone = account.getTimeZone();
  const today = new Date();

  const currentEnd = addDays(today, -1);
  const currentStart = addDays(currentEnd, -6);
  const previousEnd = addDays(currentStart, -1);
  const previousStart = addDays(previousEnd, -6);

  const current = getMetrics(currentStart, currentEnd, timezone);
  const previous = getMetrics(previousStart, previousEnd, timezone);

  const comparison = [
    compareMetric('Investimento', current.cost, previous.cost, money),
    compareMetric('Conversões', current.conversions, previous.conversions, decimal),
    compareMetric('CPA', cpa(current), cpa(previous), nullableMoney),
    compareMetric('Valor de conversão', current.conversionValue, previous.conversionValue, money),
    compareMetric('ROAS da plataforma', roas(current), roas(previous), nullableRatio)
  ];

  const significant = comparison.filter(item =>
    item.variation !== null &&
    Math.abs(item.variation) >= CONFIG.ALERT_VARIATION_PERCENT
  );

  const lines = comparison.map(item =>
    `${item.name}: ${item.currentText} vs ${item.previousText} ` +
    `(${formatVariation(item.variation)})`
  );

  const body = [
    `Conta: ${account.getName()} (${account.getCustomerId()})`,
    `Período atual: ${dateForHuman(currentStart, timezone)} a ${dateForHuman(currentEnd, timezone)}`,
    `Período anterior: ${dateForHuman(previousStart, timezone)} a ${dateForHuman(previousEnd, timezone)}`,
    '',
    ...lines,
    '',
    significant.length
      ? `${significant.length} indicador(es) ultrapassaram o limite de ${CONFIG.ALERT_VARIATION_PERCENT}%.`
      : `Nenhum indicador ultrapassou o limite de ${CONFIG.ALERT_VARIATION_PERCENT}%.`,
    'Mudança não significa problema por si só. Verifique mix de campanha, sazonalidade, atraso de conversão e CRM.'
  ].join('\n');

  Logger.log(body);

  if (!significant.length) {
    return;
  }

  MailApp.sendEmail(
    CONFIG.EMAIL,
    `[Google Ads] Variação relevante em 7 dias, ${account.getName()}`,
    body
  );
}

function getMetrics(startDate, endDate, timezone) {
  const query = `
    SELECT
      metrics.cost_micros,
      metrics.conversions,
      metrics.conversions_value
    FROM customer
    WHERE segments.date BETWEEN '${dateForQuery(startDate, timezone)}'
      AND '${dateForQuery(endDate, timezone)}'
  `;

  const rows = AdsApp.search(query);
  const total = {cost: 0, conversions: 0, conversionValue: 0};

  while (rows.hasNext()) {
    const row = rows.next();
    total.cost += Number(row.metrics.costMicros || 0) / 1e6;
    total.conversions += Number(row.metrics.conversions || 0);
    total.conversionValue += Number(row.metrics.conversionsValue || 0);
  }

  return total;
}

function compareMetric(name, currentValue, previousValue, formatter) {
  return {
    name,
    currentText: formatter(currentValue),
    previousText: formatter(previousValue),
    variation: percentageChange(currentValue, previousValue)
  };
}

function percentageChange(currentValue, previousValue) {
  if (currentValue === null || previousValue === null) return null;
  if (previousValue === 0) return currentValue === 0 ? 0 : null;
  return ((currentValue - previousValue) / Math.abs(previousValue)) * 100;
}

function cpa(metrics) {
  return metrics.conversions > 0 ? metrics.cost / metrics.conversions : null;
}

function roas(metrics) {
  return metrics.cost > 0 ? metrics.conversionValue / metrics.cost : null;
}

function formatVariation(value) {
  if (value === null) return 'sem base comparável';
  const sign = value > 0 ? '+' : '';
  return `${sign}${value.toFixed(1)}%`;
}

function addDays(date, days) {
  const copy = new Date(date.getTime());
  copy.setDate(copy.getDate() + days);
  return copy;
}

function dateForQuery(date, timezone) {
  return Utilities.formatDate(date, timezone, 'yyyy-MM-dd');
}

function dateForHuman(date, timezone) {
  return Utilities.formatDate(date, timezone, 'dd/MM/yyyy');
}

function money(value) {
  return Number(value || 0).toLocaleString('pt-BR', {
    style: 'currency',
    currency: AdsApp.currentAccount().getCurrencyCode()
  });
}

function nullableMoney(value) {
  return value === null ? 'sem cálculo' : money(value);
}

function nullableRatio(value) {
  return value === null ? 'sem cálculo' : `${value.toFixed(2)}x`;
}

function decimal(value) {
  return Number(value || 0).toLocaleString('pt-BR', {
    maximumFractionDigits: 2
  });
}

function validateConfig() {
  if (!/@/.test(CONFIG.EMAIL)) {
    throw new Error('Configure um e-mail válido em CONFIG.EMAIL.');
  }
  if (!(CONFIG.ALERT_VARIATION_PERCENT > 0)) {
    throw new Error('ALERT_VARIATION_PERCENT precisa ser maior que zero.');
  }
}

Os três scripts extras da biblioteca

ScriptO que verificaCuidado necessário
URLs dos anúncios ativosRespostas HTTP das URLs finais de anúncios ativos.Firewall e proteção contra robôs podem gerar falso positivo.
Anúncios reprovadosAnúncios com status de aprovação reprovado.O motivo e o recurso devem ser conferidos no Gerenciador de políticas.
Histórico no Google SheetsRegistra diariamente custo, cliques, conversões, CPA e ROAS.A planilha não substitui CRM nem fechamento financeiro.

Qual script faz sentido para cada tipo de conta?

Conta pequena: comece com ritmo de orçamento, gasto sem conversão e resumo diário. Não faz sentido instalar dez automações para uma conta que ainda precisa corrigir conversões básicas.

Conta com muitas campanhas: adicione anomalias, reprovações e URLs. O ganho principal é reduzir o tempo entre o problema surgir e alguém perceber.

Operação com CRM: use os scripts como alerta de mídia, mas confronte tudo com leads qualificados, vendas e receita. Uma conversão no Google Ads pode ser um formulário, não uma venda.

Como manter os scripts confiáveis ao longo do tempo

Scripts operacionais precisam de responsável, documentação, visualização antes da execução e limites ajustados à realidade da conta. O ganho vem de detectar desvios cedo sem transformar um alerta em decisão automática.

Revise permissões, consultas, horários, destinatários e mudanças na API do Google Ads. Registre cada alteração e confronte os alertas com conversões qualificadas, CRM, margem e sazonalidade.

Posso usar ChatGPT para criar ou adaptar Google Ads Scripts?

Sim, como apoio para explicar código, adaptar campos ou criar uma primeira versão. Mas o código precisa ser confrontado com a documentação atual do Google Ads Scripts, executado primeiro em Visualizar e validado com dados reais da conta. Um modelo pode sugerir métodos antigos, campos inválidos ou uma automação agressiva demais para o contexto.

Perguntas frequentes

Google Ads Scripts podem alterar campanhas automaticamente?

Podem, mas os scripts desta página são deliberadamente de leitura e alerta. Eles não pausam campanhas, não mudam lances e não adicionam palavras negativas.

É preciso saber programar para usar?

Não para executar modelos simples, mas você precisa editar as configurações, autorizar permissões, usar a visualização e entender o indicador antes de agendar.

Os scripts funcionam em Performance Max?

Os relatórios de conta e campanha podem incluir PMax quando os campos são compatíveis. A search_term_view tradicional usada no script de termos não inclui Performance Max.

Um script substitui o gestor de tráfego?

Não. Ele reduz tarefa repetitiva e acelera alertas. A decisão depende de oferta, margem, sazonalidade, tracking, CRM e qualidade da conversão.

Posso usar os códigos em contas de clientes?

Sim, adaptando as configurações e realizando a visualização em cada conta. Não trate um limite de custo ou variação como regra universal.

Thiago Scarmeloto

Thiago Scarmeloto

Consultor de marketing digital e gestor de tráfego pago. Atua com Google Ads, Meta Ads, tracking e CRO, conectando dados da plataforma ao resultado que a empresa consegue reconhecer.

Conheça a experiência e a metodologia

Fontes oficiais consultadas

Script não corrige uma conta sem diagnóstico.

Quando o problema está no tracking, na estrutura, na oferta ou na qualidade do lead, automatizar o painel só faz o erro acontecer com mais velocidade.

Solicitar diagnóstico inicial

Biblioteca gratuita · Google Ads

Receba os oito scripts em arquivos separados.

Cadastre-se para liberar a biblioteca e receber as próximas atualizações sobre automação, mídia e mensuração.