SteerAds
GuideOptimisationGoogle Ads

Google Ads Scripts: 10 ready-to-copy

Google Ads Scripts = JavaScript executed by Google on their infra with native access to the Google Ads API. Spend alerts, automatic negatives, account audits, weekly reports — here are the 10 most profitable scripts to install in 2026, with key code snippet, recommended schedule and estimated time savings.

Matt
MattTracking & Data Lead
···13 min read

Accounts running at least 5 Google Ads Scripts spend 18 to 26% less wasted budget — parasitic search terms, undetected 404s, inconsistent bids. Yet only 12-18% of SMBs in France use them in 2026. The gap is the biggest automation ROI available, for a few hours of install.

Google Ads Scripts remains in 2026 one of the most under-exploited platform features. Across our 2025 audited accounts, only 12-18% of French SMBs actively use Google Ads Scripts (per source), while about ten well-designed scripts save 10 to 15 hours per week for ops. The entry ticket is yet minuscule: beginner-level JavaScript, free execution hosted by Google, zero infra to maintain.

This guide lists the 10 most profitable scripts to install immediately, with for each the key code snippet, recommended cron schedule, average time gain and suitable use case. Not a complete copy-paste — for that, the official Google Ads Scripts documentation remains the reference. Here, we focus on the what and the why, with the snippets that kill. For a broader overview on piloting without an agency, also read our Piloting Google Ads without an agency guide.

What can a Google Ads Script do (and not do)?

Google Ads Scripts is JavaScript hosted and executed by Google on their infrastructure, with native access to Google Ads account objects via a wrapped API. No Node server to maintain, no OAuth key to manage, no external cron to rent. You write a main() function, paste the code into the account's Scripts interface, authorize the required permissions, and Google executes it for you — in preview mode (dry-run) or on cron schedule (hourly, daily, weekly). It's free, and it runs on Google's servers.

Use cases where Scripts shines: monitoring (spend alerts, anomalies, 404s), lightweight automation (adding negatives, pausing low-CVR keywords), custom reporting (weekly digest by email, Sheets export), scheduled audits (missing extensions, broken tracking, QS falling). Any repetitive and bounded ops task — read stats, make a simple decision, send an alert or modify an entity — is an ideal candidate.

Cases where Scripts is inadequate: deep statistical analysis (no scientific libs like numpy), third-party npm dependencies (impossible to install), sub-second real-time piloting (minimum 1 execution per hour), workflows exceeding 30 minutes (hard timeout). For these cases, switch to the Google Ads API backend (Python, Go) or to a pilot SaaS that covers monitoring + alerts + actions infra without code.

Key insight :

across the accounts we observe, accounts with 5+ active scripts spend on average 18-26% less in wasted budget (per maturity) (parasitic search terms, inconsistent bids, undetected 404s) than accounts without automation. The ROI of a 2-3 hour investment to install the stack below is measured in weeks, not months.

Google Ads Script workflow — cron, pull, decision, actionCron schedulehourly / daily / weeklyPull dataAdsApp.currentAccount()Decisionif / else, thresholdsAlertemail, Slack, webhookActionnegative, pause, bid

Technical limits to remember: 30-minute timeout per run, daily API quota on bulk mutations, minimum frequency of 1 execution per hour, no npm package (everything must be pure ES5+ JavaScript Rhino-compatible), and slightly proprietary syntax on AdsApp objects. Nothing blocking for the 10 scripts below, but keep in mind if you design a custom script that must process a large catalog. For workflows that exceed these limits, the official Google Ads API (Python, Java, Go) remains the backend fallback.

Total estimated: 10 to 15 hours per week saved if the 10 scripts run in parallel, on an average account (3-8 active campaigns). It's the equivalent of a third of a junior ops full-time — for 3 hours of initial install.

How do you automatically detect a spend anomaly?

The script that detects in under an hour an abnormal spend spike — budget leak, bidding bug, bot attack, or simply a poorly anticipated seasonality shift. We compare current hourly spend to the rolling 7-day average, trigger the alert if it exceeds a threshold (here 1.5× the average). Finer version: compute the standard deviation, alert above 2σ.

Use case: any account with daily budget > $100. Critical for seasonal-peak e-commerce and for SaaS where a feed error can wreck the budget in 4 hours.

function main() {
  var today = AdsApp.currentAccount().getStatsFor("TODAY").getCost();
  var avg7d = AdsApp.currentAccount().getStatsFor("LAST_7_DAYS").getCost() / 7;
  if (today > avg7d * 1.5) {
    MailApp.sendEmail(
      "ops@example.com",
      "[SPEND ALERT] Anomaly detected",
      "Today: " + today.toFixed(2) + "€ vs 7d avg: " + avg7d.toFixed(2) + "€"
    );
  }
}

Schedule: hourly. Time saved: around 1 hour per week (no more manual dashboard checks every morning). Level-2 improvement: replace the 1.5× threshold with a real standard deviation computation over 30 days to avoid false positives linked to end-of-month spikes.

How do you automatically add negatives from search terms?

The script that scans search terms of the last 30 days and automatically adds as negatives those that cost more than $X with 0 conversions. Immediate profitability: in our audits, it's on average 8 to 15% of Search budget that leaks to out-of-scope queries. The script doesn't replace the weekly manual review — it captures the worst offenders immediately.

Use case: Search accounts with broad match or phrase match active, diversified catalog. Less useful if you run 100% exact match tightly locked down.

function main() {
  var report = AdsApp.report(
    "SELECT search_term_view.search_term, metrics.cost_micros, metrics.conversions " +
    "FROM search_term_view WHERE segments.date DURING LAST_30_DAYS " +
    "AND metrics.cost_micros > 20000000 AND metrics.conversions = 0"
  );
  var rows = report.rows();
  var campaign = AdsApp.campaigns().withIds(["123456789"]).get().next();
  while (rows.hasNext()) {
    var r = rows.next();
    campaign.createNegativeKeyword('[' + r["search_term_view.search_term"] + ']');
  }
}

Schedule: daily. Time saved: around 2 hours per week (no more manual hunt for parasitic search terms). Indispensable guardrail: log the list of negatives added each run, and wrap createNegativeKeyword in a try/catch — a bug here can negative converted queries if you invert an operator.

Script 3 · Quality Score decay alert

The script that exports your top keywords' Quality Score daily to a Google Sheet, compares to the prior week's score, and alerts if a keyword drops more than 1 point. Essential for reacting before CPC explodes — a QS going from 8 to 6 increases average CPC by 40 to 60%. To dig into Quality Score mechanics, see our Google Ads audit checklist.

Use case: mature Search accounts with 50+ active keywords. Lets you quickly identify a degrading landing page or an ad losing its relevance.

function main() {
  var sheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/XXX").getActiveSheet();
  var keywords = AdsApp.keywords()
    .withCondition("Status = ENABLED")
    .withCondition("Impressions > 100")
    .forDateRange("LAST_7_DAYS").get();
  while (keywords.hasNext()) {
    var kw = keywords.next();
    sheet.appendRow([new Date(), kw.getText(), kw.getQualityScore()]);
    // Compare vs the D-7 value here, alert if drop > 1 pt
  }
}

Schedule: daily. Time saved: around 45 minutes per week, but mainly prevention of budget losses: reacting in 24h on a dropping QS avoids 2 weeks of paying inflated CPC.

How do you monitor budget pacing year-round?

The script that compares the month's cumulative spend to the prorata theoretical budget (current day ÷ days in month × monthly budget) and triggers an alert if the delta exceeds ±15%. Underspend = campaigns throttled by bids too low or poorly sized daily budget; overspend = aggressive pacing that will burn the budget mid-month. Both scenarios cost dearly. See also our dedicated guide on Google Ads budget pacing.

Use case: all accounts with fixed monthly budget (agencies with monthly-retained clients, internal marketing departments with capped envelope).

function main() {
  var MONTHLY_BUDGET = 10000; // € — to configure
  var now = new Date();
  var dayOfMonth = now.getDate();
  var daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();
  var expected = MONTHLY_BUDGET * (dayOfMonth / daysInMonth);
  var actual = AdsApp.currentAccount().getStatsFor("THIS_MONTH").getCost();
  var delta = (actual - expected) / expected;
  if (Math.abs(delta) > 0.15) {
    MailApp.sendEmail("ops@example.com", "[PACING] Delta " + (delta * 100).toFixed(0) + "%",
      "Spent: " + actual + "€ vs expected: " + expected.toFixed(0) + "€");
  }
}

Schedule: daily (end of day). Time saved: around 1h30 per week, plus the safety of avoiding an embarrassing annual budget overrun on the finance side.

Script 5 · Ad copy fatigue detector (falling CTR)

The script that detects ads whose CTR over the last 7 days drops more than 25% vs the CTR over the last 30 days. Classic creative fatigue symptom: your audience has seen the ad too many times, they scroll without clicking. Reaction: refresh the copy, test a new headline, rotate RSA assets.

Use case: budget-scaling accounts, Display retargeting, always-on campaigns on the same audience. Not useful on ultra-diversified cold acquisition.

function main() {
  var ads = AdsApp.ads().withCondition("Status = ENABLED").get();
  while (ads.hasNext()) {
    var ad = ads.next();
    var ctr7 = ad.getStatsFor("LAST_7_DAYS").getCtr();
    var ctr30 = ad.getStatsFor("LAST_30_DAYS").getCtr();
    if (ctr30 > 0 && ctr7 < ctr30 * 0.75) {
      Logger.log("FATIGUE: ad " + ad.getId() + " | 7d=" + ctr7 + " | 30d=" + ctr30);
      // Optional: label the ad "to-refresh"
    }
  }
}

Schedule: weekly. Time saved: around 1 hour per week on manual ad stats review, and above all earlier detection that avoids 2-3 weeks of low CTR.

Script 6 · Competitor bid anomaly (top IS dropped)

The script that monitors your Impression Share (top and absolute top) on your core campaigns and alerts if you lose more than 10 points in 24h. Typical signal: a competitor just boosted their bids, or a new entrant took position. Quick reaction possible: adjust your Target CPA, push a differentiating asset, activate a competitive sitelink.

Use case: competitive verticals (insurance, health insurance, B2B SaaS, fashion e-commerce). Less critical in low-competition niches.

function main() {
  var campaigns = AdsApp.campaigns().withCondition("Status = ENABLED").get();
  while (campaigns.hasNext()) {
    var c = campaigns.next();
    var statsYd = c.getStatsFor("YESTERDAY");
    var stats7d = c.getStatsFor("LAST_7_DAYS");
    var isYd = statsYd.getSearchImpressionShare();
    var is7d = stats7d.getSearchImpressionShare();
    if (is7d > 0 && (is7d - isYd) > 0.10) {
      MailApp.sendEmail("ops@example.com", "[IS DROP] " + c.getName(),
        "IS dropped from " + (is7d * 100).toFixed(0) + "% to " + (isYd * 100).toFixed(0) + "%");
    }
  }
}

Schedule: daily. Time saved: around 1 hour per week of active competitive monitoring, replaced by a passive alert.

How do you detect 404 landing pages in your ads?

The script that fetches HTTP GET on each final URL of active ads, checks the status code, and alerts immediately if a URL returns 404, 500 or a broken redirect. Paying to send traffic to a broken page is the most humiliating error of a campaign. In practice, 3% of audited accounts have at least one permanently active 404 URL, often after a redesign or CMS change.

Use case: e-commerce with product rotation (stock-outs, end-of-collection), recently migrated sites, multi-sites with dynamic URLs.

function main() {
  var ads = AdsApp.ads().withCondition("Status = ENABLED").get();
  var broken = [];
  while (ads.hasNext()) {
    var ad = ads.next();
    var url = ad.urls().getFinalUrl();
    if (!url) continue;
    try {
      var resp = UrlFetchApp.fetch(url, { muteHttpExceptions: true, followRedirects: false });
      if (resp.getResponseCode() >= 400) broken.push(url + " → " + resp.getResponseCode());
    } catch (e) { broken.push(url + " → FETCH ERROR"); }
  }
  if (broken.length) MailApp.sendEmail("ops@example.com", "[404] Broken landing pages", broken.join("\n"));
}

Schedule: hourly if e-commerce, daily otherwise. Time saved: around 2 hours per week, plus the direct saving on budget spent on a broken page (which can reach hundreds of dollars in a day).

Script 8 · Conversion tracking drift (rate drop)

The script that computes the conversion rate over the last 24 hours vs the 14-day average, and alerts if the rate drops more than 40% without volume explanation. Main symptom: broken tracking — GTM tag that no longer fires, misconfigured consent mode, disconnected GA4. The absolute nightmare when Smart Bidding loses its conversion signal. For the complete tracking re-audit, see our conversion tracking guide.

Use case: all accounts with active Smart Bidding. Critical whenever a technical redesign is planned on the site.

function main() {
  var acct = AdsApp.currentAccount();
  var clicks1 = acct.getStatsFor("YESTERDAY").getClicks();
  var conv1 = acct.getStatsFor("YESTERDAY").getConversions();
  var clicks14 = acct.getStatsFor("LAST_14_DAYS").getClicks();
  var conv14 = acct.getStatsFor("LAST_14_DAYS").getConversions();
  if (clicks1 === 0 || clicks14 === 0) return;
  var rate1 = conv1 / clicks1;
  var rate14 = conv14 / clicks14;
  if (rate14 > 0 && rate1 < rate14 * 0.6) {
    MailApp.sendEmail("ops@example.com", "[TRACKING] Conversion drift",
      "CVR 24h=" + (rate1 * 100).toFixed(2) + "% vs 14d=" + (rate14 * 100).toFixed(2) + "%");
  }
}

Schedule: daily. Time saved: around 1 hour per week, but mainly the huge saving of a Smart Bidding going sideways for 7 days before manual detection.

Script 9 · Extensions audit (missing sitelinks)

The script that lists all active Search campaigns and verifies the presence of key extensions: sitelinks (minimum 4), callouts (minimum 4), structured snippets, business info. Alert if a campaign has no extensions or fewer than the minimum. Extensions boost CTR by 10 to 15% on average — forgetting them is pure waste. Documentation at Google Ads support on extensions.

Use case: agency MCCs with 20+ accounts to oversee, or marketing teams regularly launching new campaigns without strict process.

function main() {
  var missing = [];
  var campaigns = AdsApp.campaigns().withCondition("Status = ENABLED").get();
  while (campaigns.hasNext()) {
    var c = campaigns.next();
    var sitelinks = c.extensions().sitelinks().get().totalNumEntities();
    var callouts = c.extensions().callouts().get().totalNumEntities();
    if (sitelinks < 4 || callouts < 4) {
      missing.push(c.getName() + " → sitelinks=" + sitelinks + ", callouts=" + callouts);
    }
  }
  if (missing.length) MailApp.sendEmail("ops@example.com", "[EXT] Missing extensions", missing.join("\n"));
}

Schedule: weekly. Time saved: around 30 minutes per week of manual audit replaced, but mainly systematic coverage ensuring no new campaign stays without extensions.

Script 10 · Weekly performance digest email

The script that aggregates every Monday morning the key metrics of the past week (spend, clicks, conversions, CTR, CPA, ROAS) and sends a summary HTML email to stakeholders. End of the 45 minutes every Monday building the weekly PowerPoint. Bonus: add the week-over-week variation, highlight top/flop campaigns, top 3 converting search terms.

Use case: all structures with a recurring weekly reporting (agency, in-house, freelance). Replaces a manual deliverable of 30 to 60 minutes.

function main() {
  var s = AdsApp.currentAccount().getStatsFor("LAST_7_DAYS");
  var prev = AdsApp.currentAccount().getStatsFor("LAST_14_DAYS");
  var html = "<h2 data-speakable>Weekly digest</h2>" +
    "<p>Spend: " + s.getCost().toFixed(0) + "€</p>" +
    "<p>Conv: " + s.getConversions() + "</p>" +
    "<p>CPA: " + (s.getCost() / Math.max(s.getConversions(), 1)).toFixed(2) + "€</p>" +
    "<p>CTR: " + (s.getCtr() * 100).toFixed(2) + "%</p>";
  MailApp.sendEmail({
    to: "team@example.com",
    subject: "[Weekly digest] Google Ads — week " + new Date().toLocaleDateString(),
    htmlBody: html
  });
}

Schedule: weekly, Monday 8am. Time saved: around 1h30 per week, and guaranteed regularity (no more digests forgotten on busy weeks).

Fatal error to avoid :

a Google Ads Script without error handling can trigger a massive action in case of an API bug — imagine 500 broad negatives added across your entire structure because line 12 returned undefined. Absolute rule: any entity mutation (add, set, pause, remove) must be wrapped in a try/catch with error notification and an entity modification cap per run (e.g. max 50 negatives added/run).

These 10 scripts cover 90% of classic automation needs. If you want a richer monitoring layer (multi-criteria statistical anomaly detection, Slack/webhook alerts, deep historization, multi-account dashboards), most of these scripts are already built into SteerAds — our Monitoring module runs 24/7 without you having to maintain code, Auto-optimization adds the automatic actions (negatives, pacing, budget redistrib), and our free audit points out in 72h the scripts to install as priority on your account. For more structural scaling, follow with our complete Performance Max guide.

Sources

Official sources consulted for this guide:

FAQ

Do you need to know how to code to use Google Ads Scripts?

Basic JavaScript is enough to install and adapt the scripts we provide. AdsApp.* objects are well documented, the compiler built into the Google Ads interface surfaces errors before execution, and most useful scripts fit in 40 to 120 lines. You need to be able to read a function, understand a for loop, and manipulate JSON objects — nothing more. For non-technical teams, cautious copy-paste from our repo and 2-3 preview tests (without real execution) let you install a monitoring script in under 15 minutes. To develop a custom script with complex business logic, a junior developer is still preferable.

Are Google Ads Scripts secure?

Yes, on the execution side — Google runs them on their own sandboxed infrastructure, you have no server to maintain and no credentials to host. Main code-side risk: a buggy script that massively alters the account (e.g. pauses all campaigns, changes all bids) without error handling. Always test in preview mode before scheduling, wrap write operations in try/catch with error notification, and add guardrails (e.g. limit the number of entities modified per run). On our internal SteerAds benchmark, 14% of major Google Ads incidents encountered by clients in audit are tied to a script without guardrails.

How many scripts can you run on a Google Ads account?

At the individual account level, Google allows up to 250 active scripts, but you'll hit the usefulness ceiling well before — about ten well-designed scripts cover 90% of automation needs. The real quotas that will block you first are: 30-minute execution maximum per script, daily API operations limit (bulk mutations), and maximum frequency of 1 execution per hour for hourly scripts. An MCC (manager account) can execute a script that iterates across dozens of child accounts in a single run, which changes the game for agencies. Start small, measure impact, then scale.

Scripts vs SaaS tool (like SteerAds): which to choose?

The two are complementary. Scripts shine on one-off, hyper-custom actions where you already have precise business logic to encode — a SaaS will never reproduce your in-house exclusion rule. A SaaS like SteerAds covers the generic infrastructure (24/7 monitoring, multi-channel alerts, statistical anomaly detection, automatic audits, multi-account dashboards, deep historization) without requiring you to maintain code. On our internal SteerAds benchmark, accounts combining 2-3 business-custom scripts + a pilot SaaS save 10 to 15h/week, vs 4-5h for those with only scripts. The question isn't 'which', but 'where to set the cursor'.

Ready to optimize your campaigns?

Start a free audit in 2 minutes and discover the ROI potential of your accounts.

Start my free audit

Free audit — no credit card required

Keep reading