CÓDIGO DE PRODUÇÃO & AUTOMAÇÃO
Script Auditor: Detector Automático de Erros 404 em Anúncios
Script Google Ads para varredura diária de URLs finais de anúncios e detecção imediata de páginas de destino com erro 404 por Wagner Hörlle.
/**
* SCRIPT 4: AUDITOR AUTOMÁTICO DE LINKS QUEBRADOS (404 / 500) E PÁGINAS SEM ESTOQUE
* Pacote de Proteção de Conta Google Ads - Growth OS
*
* Finalidade:
* Testa as URLs finais de todos os anúncios ativos da conta.
* Se uma página retornar código HTTP de erro (404 Not Found, 500 Server Error)
* ou contiver strings críticas como "Produto Esgotado", ele pausa o anúncio
* imediatamente e envia um e-mail de alerta, evitando queimar verba em páginas mortas.
*/
const CONFIG = {
// Pausar o anúncio automaticamente se a URL estiver quebrada?
PAUSE_BROKEN_ADS: true,
// Criar e aplicar uma etiqueta nos anúncios pausados pelo robô
LABEL_NAME: 'ALERTA_URL_QUEBRADA',
// Expressões no texto da página que indicam ruptura de estoque
OUT_OF_STOCK_PHRASES: [
'produto esgotado',
'produto indisponível',
'fora de estoque',
'avise-me quando chegar'
],
EMAIL_ALERTS: 'seu-email@dominio.com.br'
};
function main() {
Logger.log('Iniciando auditoria de integridade de URLs e estoque...');
ensureLabelExists(CONFIG.LABEL_NAME);
const brokenAds = [];
const adIterator = AdsApp.ads()
.withCondition('Status = ENABLED')
.withCondition('CampaignStatus = ENABLED')
.withCondition('AdGroupStatus = ENABLED')
.get();
while (adIterator.hasNext()) {
const ad = adIterator.next();
const finalUrl = ad.urls().getFinalUrl();
if (!finalUrl) continue;
try {
const response = UrlFetchApp.fetch(finalUrl, {
muteHttpExceptions: true,
followRedirects: true
});
const statusCode = response.getResponseCode();
const content = response.getContentText().toLowerCase();
let isProblem = false;
let reason = '';
if (statusCode >= 400) {
isProblem = true;
reason = `Erro HTTP ${statusCode}`;
} else {
// Checar por ruptura de estoque
for (let i = 0; i < CONFIG.OUT_OF_STOCK_PHRASES.length; i++) {
if (content.indexOf(CONFIG.OUT_OF_STOCK_PHRASES[i]) !== -1) {
isProblem = true;
reason = `Detectado "${CONFIG.OUT_OF_STOCK_PHRASES[i]}" no HTML`;
break;
}
}
}
if (isProblem) {
Logger.log(`🚨 Anúncio com falha detectado: ID ${ad.getId()} | Motivo: ${reason} | URL: ${finalUrl}`);
if (CONFIG.PAUSE_BROKEN_ADS) {
ad.pause();
ad.applyLabel(CONFIG.LABEL_NAME);
Logger.log(`-> Anúncio ${ad.getId()} pausado e etiquetado com ${CONFIG.LABEL_NAME}`);
}
brokenAds.push(`Anúncio ID: ${ad.getId()} | ${reason} | URL: ${finalUrl}`);
}
} catch (fetchErr) {
Logger.log(`Falha de conexão na URL ${finalUrl}: ` + fetchErr.toString());
brokenAds.push(`Falha de conexão: ${finalUrl}`);
}
}
Logger.log(`Auditoria finalizada. Total de links com falha: ${brokenAds.length}`);
if (brokenAds.length > 0 && CONFIG.EMAIL_ALERTS) {
MailApp.sendEmail(
CONFIG.EMAIL_ALERTS,
`[Alerta Google Ads] ${brokenAds.length} anúncios com links quebrados ou sem estoque!`,
`Os seguintes anúncios foram pausados automaticamente para proteger o orçamento:\n\n` +
brokenAds.join('\n')
);
}
}
function ensureLabelExists(labelName) {
const labelIterator = AdsApp.labels().withCondition(`Name = "${labelName}"`).get();
if (!labelIterator.hasNext()) {
AdsApp.createLabel(labelName, 'Anúncios pausados pelo script de auditoria de URL', '#d93025');
}
}