uplyo-os/Scripts Library

## Scripts Library

Scripts Google Ads prêts à l'emploi. Copiez, adaptez, déployez.

Pause low-performing keywords
Pause automatiquement les mots-clés avec un CPA supérieur au seuil défini sur les 30 derniers jours.
KeywordsCPAAutoOptimisation
JavaScript · Google Ads Script
function main() {
  const CPA_THRESHOLD = 50; // €
  const DAYS = 30;
  
  const keywords = AdsApp.keywords()
    .withCondition("Status = ENABLED")
    .forDateRange("LAST_30_DAYS")
    .get();
  
  while (keywords.hasNext()) {
    const kw = keywords.next();
    const stats = kw.getStatsFor("LAST_30_DAYS");
    const cost = stats.getCost();
    const conv = stats.getConversions();
    
    if (conv > 0 && (cost / conv) > CPA_THRESHOLD) {
      kw.pause();
      Logger.log("Paused: " + kw.getText() + " CPA: " + (cost/conv).toFixed(2));
    }
  }
}
Budget pacing alert
Envoie un email d'alerte si le rythme de dépense dépasse le budget mensuel prévu.
BudgetAlertEmailMonitoring
JavaScript · Google Ads Script
function main() {
  const MONTHLY_BUDGET = 5000;
  const EMAIL = "you@agency.com";
  
  const today = new Date();
  const dayOfMonth = today.getDate();
  const daysInMonth = new Date(today.getFullYear(), today.getMonth()+1, 0).getDate();
  
  const account = AdsApp.currentAccount();
  const stats = account.getStatsFor("THIS_MONTH");
  const spent = stats.getCost();
  
  const expectedPace = (MONTHLY_BUDGET / daysInMonth) * dayOfMonth;
  const paceRatio = spent / expectedPace;
  
  if (paceRatio > 1.15) {
    MailApp.sendEmail(EMAIL, "⚠️ Budget Pacing Alert", 
      "Dépense: " + spent.toFixed(2) + "€ (" + (paceRatio*100).toFixed(0) + "% du pace)");
  }
}
Negative keywords from Search Terms
Identifie les termes de recherche non convertissants et les ajoute en négatifs.
NégatifsSearch TermsAutoOptimisation
JavaScript · Google Ads Script
function main() {
  const MIN_CLICKS = 10;
  const MIN_COST = 20;
  
  const report = AdsApp.report(
    "SELECT Query, Clicks, Cost, Conversions " +
    "FROM SEARCH_QUERY_PERFORMANCE_REPORT " +
    "WHERE Clicks > " + MIN_CLICKS +
    " AND Conversions = 0 " +
    "DURING LAST_30_DAYS"
  );
  
  const rows = report.rows();
  while (rows.hasNext()) {
    const row = rows.next();
    if (parseFloat(row["Cost"]) > MIN_COST) {
      Logger.log("Negative candidate: " + row["Query"]);
    }
  }
}
Quality Score tracker
Exporte le Quality Score de tous les mots-clés actifs dans un Google Sheet pour suivi historique.
QSSheetTrackingReporting
JavaScript · Google Ads Script
function main() {
  const SHEET_URL = "YOUR_SHEET_URL";
  const ss = SpreadsheetApp.openByUrl(SHEET_URL);
  const sheet = ss.getActiveSheet();
  
  const keywords = AdsApp.keywords()
    .withCondition("Status = ENABLED")
    .withCondition("QualityScore > 0")
    .get();
  
  const today = Utilities.formatDate(new Date(), "Europe/Paris", "yyyy-MM-dd");
  
  while (keywords.hasNext()) {
    const kw = keywords.next();
    sheet.appendRow([
      today,
      kw.getText(),
      kw.getQualityScore(),
      kw.getCampaign().getName()
    ]);
  }
}
Auto-pause zero impression ads
Pause les annonces avec 0 impression depuis 14 jours pour nettoyer les ad groups.
AdsCleanupAutoOptimisation
JavaScript · Google Ads Script
function main() {
  const ads = AdsApp.ads()
    .withCondition("Status = ENABLED")
    .withCondition("Impressions = 0")
    .forDateRange("LAST_14_DAYS")
    .get();
  
  while (ads.hasNext()) {
    const ad = ads.next();
    ad.pause();
    Logger.log("Paused ad in: " + ad.getAdGroup().getName());
  }
}
Bid adjustment by device
Ajuste les enchères par device (mobile/desktop/tablet) selon les performances CPA.
BidsDeviceCPAOptimisation
JavaScript · Google Ads Script
function main() {
  const TARGET_CPA = 40;
  const campaigns = AdsApp.campaigns()
    .withCondition("Status = ENABLED").get();
  
  while (campaigns.hasNext()) {
    const camp = campaigns.next();
    const devices = camp.targeting().platforms().get();
    while (devices.hasNext()) {
      const device = devices.next();
      const stats = device.getStatsFor("LAST_30_DAYS");
      const conv = stats.getConversions();
      if (conv > 0) {
        const cpa = stats.getCost() / conv;
        const adj = Math.round((TARGET_CPA / cpa - 1) * 100);
        device.setBidModifier(1 + adj / 100);
      }
    }
  }
}
RSA performance grader
Analyse la performance de chaque titre et description RSA et exporte les résultats.
RSAAnnoncesExportReporting
JavaScript · Google Ads Script
function main() {
  const SHEET_URL = "YOUR_SHEET_URL";
  const ss = SpreadsheetApp.openByUrl(SHEET_URL);
  const sheet = ss.getActiveSheet();
  
  const report = AdsApp.report(
    "SELECT CampaignName, AdGroupName, HeadlinePart1, " +
    "HeadlinePart2, Description, Impressions, Clicks, Conversions " +
    "FROM AD_PERFORMANCE_REPORT " +
    "WHERE AdType = RESPONSIVE_SEARCH_AD " +
    "DURING LAST_30_DAYS"
  );
  
  const rows = report.rows();
  while (rows.hasNext()) {
    const row = rows.next();
    sheet.appendRow([
      row["CampaignName"], row["AdGroupName"],
      row["HeadlinePart1"], row["Impressions"],
      row["Clicks"], row["Conversions"]
    ]);
  }
}
Campaign daily spend tracker
Log quotidien des dépenses par campagne dans un Google Sheet pour suivi historique.
BudgetSheetDailyReporting
JavaScript · Google Ads Script
function main() {
  const SHEET_URL = "YOUR_SHEET_URL";
  const ss = SpreadsheetApp.openByUrl(SHEET_URL);
  const sheet = ss.getActiveSheet();
  const today = Utilities.formatDate(new Date(), "Europe/Paris", "yyyy-MM-dd");
  
  const campaigns = AdsApp.campaigns()
    .withCondition("Status = ENABLED").get();
  
  while (campaigns.hasNext()) {
    const camp = campaigns.next();
    const stats = camp.getStatsFor("TODAY");
    sheet.appendRow([
      today, camp.getName(),
      stats.getCost(), stats.getClicks(),
      stats.getConversions(), stats.getImpressions()
    ]);
  }
}
Broken URL checker
Vérifie toutes les URLs de destination et alerte si un code HTTP 4xx/5xx est détecté.
URLs404AlertMonitoring
JavaScript · Google Ads Script
function main() {
  const EMAIL = "you@agency.com";
  const broken = [];
  
  const ads = AdsApp.ads()
    .withCondition("Status = ENABLED").get();
  
  while (ads.hasNext()) {
    const ad = ads.next();
    const urls = ad.urls();
    const finalUrl = urls.getFinalUrl();
    if (finalUrl) {
      try {
        const resp = UrlFetchApp.fetch(finalUrl, {muteHttpExceptions: true});
        if (resp.getResponseCode() >= 400) {
          broken.push(finalUrl + " → " + resp.getResponseCode());
        }
      } catch(e) {
        broken.push(finalUrl + " → ERROR");
      }
    }
  }
  
  if (broken.length > 0) {
    MailApp.sendEmail(EMAIL, "⚠️ Broken URLs",
      broken.join("\n"));
  }
}
Conversion lag report
Compare les conversions à 1j, 7j et 30j pour identifier le délai de conversion moyen.
ConversionsLagAnalysisReporting
JavaScript · Google Ads Script
function main() {
  const periods = ["LAST_7_DAYS", "LAST_14_DAYS", "LAST_30_DAYS"];
  
  periods.forEach(function(period) {
    const stats = AdsApp.currentAccount().getStatsFor(period);
    Logger.log(period + ":");
    Logger.log("  Cost: " + stats.getCost());
    Logger.log("  Conv: " + stats.getConversions());
    Logger.log("  CPA: " + (stats.getCost() / Math.max(stats.getConversions(), 1)).toFixed(2));
  });
}
Auto-label high performers
Ajoute un label aux mots-clés avec un CPA inférieur au seuil et +5 conversions.
LabelsKeywordsAutoOptimisation
JavaScript · Google Ads Script
function main() {
  const CPA_TARGET = 35;
  const MIN_CONV = 5;
  const LABEL = "★ Top Performer";
  
  // Create label if needed
  try { AdsApp.createLabel(LABEL); } catch(e) {}
  
  const keywords = AdsApp.keywords()
    .withCondition("Status = ENABLED")
    .forDateRange("LAST_30_DAYS")
    .get();
  
  while (keywords.hasNext()) {
    const kw = keywords.next();
    const stats = kw.getStatsFor("LAST_30_DAYS");
    const conv = stats.getConversions();
    if (conv >= MIN_CONV) {
      const cpa = stats.getCost() / conv;
      if (cpa <= CPA_TARGET) {
        kw.applyLabel(LABEL);
        Logger.log("Labeled: " + kw.getText());
      }
    }
  }
}
Impression share tracker
Exporte le taux d'impression perdu (budget + rank) par campagne dans un Sheet.
ISSheetTrackingReporting
JavaScript · Google Ads Script
function main() {
  const SHEET_URL = "YOUR_SHEET_URL";
  const ss = SpreadsheetApp.openByUrl(SHEET_URL);
  const sheet = ss.getActiveSheet();
  const today = Utilities.formatDate(new Date(), "Europe/Paris", "yyyy-MM-dd");
  
  const report = AdsApp.report(
    "SELECT CampaignName, SearchImpressionShare, " +
    "SearchBudgetLostImpressionShare, SearchRankLostImpressionShare " +
    "FROM CAMPAIGN_PERFORMANCE_REPORT " +
    "WHERE CampaignStatus = ENABLED DURING LAST_7_DAYS"
  );
  
  const rows = report.rows();
  while (rows.hasNext()) {
    const row = rows.next();
    sheet.appendRow([today, row["CampaignName"],
      row["SearchImpressionShare"],
      row["SearchBudgetLostImpressionShare"],
      row["SearchRankLostImpressionShare"]]);
  }
}
Shopping feed error alert
Vérifie les erreurs du feed Merchant Center et alerte par email.
ShoppingFeedAlertMonitoring
JavaScript · Google Ads Script
function main() {
  const EMAIL = "you@agency.com";
  
  const report = AdsApp.report(
    "SELECT CampaignName, OfferId, MerchantId, " +
    "Title, CustomLabel0 " +
    "FROM SHOPPING_PERFORMANCE_REPORT " +
    "WHERE Impressions = 0 DURING LAST_7_DAYS"
  );
  
  const issues = [];
  const rows = report.rows();
  while (rows.hasNext()) {
    const row = rows.next();
    issues.push(row["OfferId"] + " — " + row["Title"]);
  }
  
  if (issues.length > 10) {
    MailApp.sendEmail(EMAIL,
      "⚠️ " + issues.length + " produits sans impression",
      issues.slice(0, 50).join("\n"));
  }
}
Ad schedule performance
Analyse les performances par créneau horaire pour optimiser les ad schedules.
ScheduleHorairesBidsOptimisation
JavaScript · Google Ads Script
function main() {
  const report = AdsApp.report(
    "SELECT HourOfDay, Clicks, Impressions, Cost, " +
    "Conversions, ConversionRate " +
    "FROM ACCOUNT_PERFORMANCE_REPORT " +
    "DURING LAST_30_DAYS"
  );
  
  const rows = report.rows();
  Logger.log("Hour | Clicks | Conv | CPA | CVR");
  while (rows.hasNext()) {
    const r = rows.next();
    const conv = parseFloat(r["Conversions"]);
    const cost = parseFloat(r["Cost"]);
    const cpa = conv > 0 ? (cost / conv).toFixed(2) : "N/A";
    Logger.log(r["HourOfDay"] + "h | " +
      r["Clicks"] + " | " + r["Conversions"] + " | " +
      cpa + "€ | " + r["ConversionRate"]);
  }
}
Duplicate keywords finder
Détecte les mots-clés en doublon entre différents ad groups ou campagnes.
KeywordsDuplicatesCleanupOptimisation
JavaScript · Google Ads Script
function main() {
  const kwMap = {};
  const dupes = [];
  
  const keywords = AdsApp.keywords()
    .withCondition("Status = ENABLED").get();
  
  while (keywords.hasNext()) {
    const kw = keywords.next();
    const text = kw.getText().toLowerCase();
    const camp = kw.getCampaign().getName();
    const ag = kw.getAdGroup().getName();
    const key = text + "|" + kw.getMatchType();
    
    if (kwMap[key]) {
      dupes.push(text + " [" + kw.getMatchType() + "] → " +
        kwMap[key] + " & " + camp + "/" + ag);
    } else {
      kwMap[key] = camp + "/" + ag;
    }
  }
  
  dupes.forEach(d => Logger.log("DUPE: " + d));
  Logger.log("Total duplicates: " + dupes.length);
}
ROAS par campagne (weekly)
Calcule le ROAS hebdomadaire par campagne et l'exporte pour suivi des tendances.
ROASWeeklyE-comReporting
JavaScript · Google Ads Script
function main() {
  const SHEET_URL = "YOUR_SHEET_URL";
  const ss = SpreadsheetApp.openByUrl(SHEET_URL);
  const sheet = ss.getActiveSheet();
  const today = Utilities.formatDate(new Date(), "Europe/Paris", "yyyy-MM-dd");
  
  const campaigns = AdsApp.campaigns()
    .withCondition("Status = ENABLED").get();
  
  while (campaigns.hasNext()) {
    const camp = campaigns.next();
    const stats = camp.getStatsFor("LAST_7_DAYS");
    const cost = stats.getCost();
    const convValue = stats.getConversionValue();
    const roas = cost > 0 ? (convValue / cost).toFixed(2) : "N/A";
    
    sheet.appendRow([today, camp.getName(),
      cost.toFixed(2), convValue.toFixed(2),
      roas, stats.getConversions()]);
  }
}
Geo performance analyzer
Analyse les performances par zone géographique et recommande des ajustements de bid.
GeoBidsAnalysisReporting
JavaScript · Google Ads Script
function main() {
  const report = AdsApp.report(
    "SELECT CountryCriteriaId, RegionCriteriaId, " +
    "Clicks, Cost, Conversions " +
    "FROM GEO_PERFORMANCE_REPORT " +
    "DURING LAST_30_DAYS"
  );
  
  const rows = report.rows();
  while (rows.hasNext()) {
    const row = rows.next();
    const conv = parseFloat(row["Conversions"]);
    const cost = parseFloat(row["Cost"]);
    if (conv > 0) {
      Logger.log(row["RegionCriteriaId"] + 
        " | CPA: " + (cost/conv).toFixed(2) + "€");
    }
  }
}
Extension sitelink auditor
Vérifie que chaque campagne a au moins 4 sitelinks actifs et alerte si non.
ExtensionsAuditAlertMonitoring
JavaScript · Google Ads Script
function main() {
  const EMAIL = "you@agency.com";
  const issues = [];
  
  const campaigns = AdsApp.campaigns()
    .withCondition("Status = ENABLED").get();
  
  while (campaigns.hasNext()) {
    const camp = campaigns.next();
    const sitelinks = camp.extensions().sitelinks().get();
    let count = 0;
    while (sitelinks.hasNext()) { sitelinks.next(); count++; }
    if (count < 4) {
      issues.push(camp.getName() + ": " + count + " sitelinks");
    }
  }
  
  if (issues.length > 0) {
    MailApp.sendEmail(EMAIL, "⚠️ Sitelinks manquants",
      issues.join("\n"));
  }
}
Shopping product partition optimizer
Analyse les performances par product group dans Shopping et identifie les top/flop.
ShoppingProductsROASE-commerce
JavaScript · Google Ads Script
function main() {
  const report = AdsApp.report(
    "SELECT OfferId, Impressions, Clicks, Cost, " +
    "Conversions, ConversionValue " +
    "FROM SHOPPING_PERFORMANCE_REPORT " +
    "DURING LAST_30_DAYS"
  );
  
  const rows = report.rows();
  while (rows.hasNext()) {
    const r = rows.next();
    const cost = parseFloat(r["Cost"]);
    const value = parseFloat(r["ConversionValue"]);
    const roas = cost > 0 ? (value / cost).toFixed(2) : "N/A";
    Logger.log(r["OfferId"] + " | ROAS: " + roas +
      " | Cost: " + cost.toFixed(2));
  }
}
PMax asset group performance
Exporte les performances des asset groups Performance Max dans un Sheet.
PMaxAssetsSheetE-commerce
JavaScript · Google Ads Script
function main() {
  const SHEET_URL = "YOUR_SHEET_URL";
  const ss = SpreadsheetApp.openByUrl(SHEET_URL);
  const sheet = ss.getActiveSheet();
  const today = Utilities.formatDate(
    new Date(), "Europe/Paris", "yyyy-MM-dd");
  
  const campaigns = AdsApp.performanceMaxCampaigns()
    .withCondition("Status = ENABLED").get();
  
  while (campaigns.hasNext()) {
    const camp = campaigns.next();
    const stats = camp.getStatsFor("LAST_7_DAYS");
    sheet.appendRow([today, camp.getName(),
      stats.getCost(), stats.getConversions(),
      stats.getConversionValue()]);
  }
}
Ad strength checker
Identifie les annonces RSA avec un Ad Strength faible (Poor/Average) pour optimisation.
RSAAd StrengthAuditOptimisation
JavaScript · Google Ads Script
function main() {
  const weak = [];
  const ads = AdsApp.ads()
    .withCondition("Type = RESPONSIVE_SEARCH_AD")
    .withCondition("Status = ENABLED").get();
  
  while (ads.hasNext()) {
    const ad = ads.next();
    // Note: Ad Strength via API requires Reports
    const camp = ad.getCampaign().getName();
    const ag = ad.getAdGroup().getName();
    const stats = ad.getStatsFor("LAST_30_DAYS");
    const ctr = stats.getCtr();
    if (ctr < 0.02) { // Low CTR proxy for weak ad
      weak.push(camp + "/" + ag + " CTR: " +
        (ctr * 100).toFixed(2) + "%");
    }
  }
  
  weak.forEach(w => Logger.log("⚠️ " + w));
  Logger.log("Total weak ads: " + weak.length);
}
Consent Mode v2 checker
Vérifie que le Consent Mode v2 est correctement configuré via les tags de conversion.
ConsentRGPDTrackingMonitoring
JavaScript · Google Ads Script
function main() {
  // Check conversion actions for consent mode
  const EMAIL = "you@agency.com";
  const account = AdsApp.currentAccount();
  
  Logger.log("Account: " + account.getName());
  Logger.log("Checking conversion tracking...");
  
  const report = AdsApp.report(
    "SELECT ConversionTypeName, ConversionCategoryName " +
    "FROM ACCOUNT_PERFORMANCE_REPORT " +
    "DURING LAST_7_DAYS"
  );
  
  const rows = report.rows();
  let hasConversions = false;
  while (rows.hasNext()) {
    const r = rows.next();
    hasConversions = true;
    Logger.log("Conv: " + r["ConversionTypeName"]);
  }
  
  if (!hasConversions) {
    MailApp.sendEmail(EMAIL,
      "⚠️ Pas de conversions détectées",
      "Vérifiez le Consent Mode v2 et les tags GTM.");
  }
}