Przejdź do treści

Skrypty Google Ads, które wyłapią anomalie w budżecie, zanim zrobi to klient

Google Ads może jednego dnia wydać nawet dwukrotność średniego budżetu dziennego, a literówka w budżecie potrafi kosztować tysiące złotych. Pokazujemy trzy skrypty, które wychwycą takie sytuacje w ciągu godziny.

Redakcja Pixel Insider8 min czytaniaPoziom: średni

  • Google Ads Scripts
  • JavaScript
  • GAQL
Spis treści
  1. Dlaczego budżet w Google Ads potrafi wymknąć się spod kontroli
  2. Jakie anomalie budżetowe warto wykrywać
  3. Skrypt Google Ads do kontroli tempa wydatków godzina po godzinie
  4. Skrypt do kontroli budżetu miesięcznego z automatyczną pauzą
  5. Alert o dużych zmianach budżetu w historii zmian
  6. Jak wdrożyć skrypt i ustawić harmonogram krok po kroku
  7. Jak ustawić progi, żeby alerty nie były szumem
  8. Najczęściej zadawane pytania

Skrypt Google Ads do kontroli budżetu to fragment kodu JavaScript uruchamiany automatycznie na koncie, który porównuje bieżące wydatki z typowym poziomem i wysyła alert albo wstrzymuje kampanie, gdy coś odbiega od normy. Jest potrzebny, bo budżet dzienny w Google Ads nie jest twardym limitem: w pojedynczym dniu kampania może wydać do dwóch razy więcej niż średni budżet dzienny, a o pomyłce w ustawieniach często dowiadujesz się dopiero z faktury. Poniżej znajdziesz trzy gotowe skrypty: kontrolę tempa wydatków godzina po godzinie, limit miesięczny z automatyczną pauzą i alert o nagłych zmianach budżetów.

Najważniejsze w skrócie

  • W jednym dniu kampania może wydać do 2× średniego budżetu dziennego, a w skali miesiąca do 30,4× tego budżetu, więc sam budżet dzienny nie chroni przed anomaliami.
  • Najskuteczniejszy alert porównuje koszt od początku dnia z kosztem z tych samych godzin w poprzednich 14 dniach, a nie z budżetem.
  • Limit miesięczny z automatyczną pauzą chroni przed przekroczeniem budżetu klienta, ale stosuj go tylko do kampanii oznaczonych etykietą.
  • Historia zmian (zasób change_event) pozwala wyłapać budżet zmieniony o kilkaset procent, zanim zdąży się wydać.
  • Najczęstszy harmonogram uruchamiania skryptów to co godzinę; dane kosztowe z bieżącego dnia mogą jednak docierać z kilkugodzinnym opóźnieniem.

Dlaczego budżet w Google Ads potrafi wymknąć się spod kontroli

Budżet dzienny w Google Ads to średnia, a nie limit. System może w danym dniu wydać do dwóch razy więcej, jeśli przewiduje lepsze wyniki, a w skali miesiąca pilnuje tylko, by suma nie przekroczyła średniego budżetu dziennego pomnożonego przez 30,4. Dla kampanii z budżetem 1000 zł dziennie dzienny koszt 2000 zł jest więc zgodny z zasadami – ale dla Ciebie lub klienta może być niespodzianką.

Do tego dochodzą zmiany, które w 2026 roku zwiększyły dynamikę wydatków. We wrześniu kwalifikujące się kampanie w sieci wyszukiwania zostały automatycznie przeniesione do AI Max, co u części reklamodawców rozszerzyło zasięg zapytań – szczegóły opisujemy w tekście o AI Max for Search. Strategie Smart Bidding z eksploracją mogą celowo licytować wyżej na nowych zapytaniach. A Ask Advisor potrafi po Twojej akceptacji zmienić budżet dzienny w kilka sekund, o czym piszemy w artykule o Ask Advisor i agentach AI w Google Ads.

Najczęstsze przyczyny anomalii są jednak prozaiczne: dodatkowe zero w budżecie, kampania włączona po teście, wspólny budżet przypisany do nowej kampanii, wysoka stawka ustawiona omyłkowo w kampanii z ręcznym CPC. Skrypt nie zapobiegnie pomyłce, ale skróci czas jej wykrycia z dni do godzin.

Jakie anomalie budżetowe warto wykrywać

Nie każda zmiana wydatków jest problemem, dlatego skrypty powinny szukać konkretnych wzorców. Poniższa tabela pokazuje sytuacje, które warto monitorować, i proponowaną reakcję.

Anomalia Sygnał w danych Proponowany próg Reakcja
Za szybkie tempo wydatków koszt od rana vs ta sama pora w poprzednich dniach +50% i min. 100 zł alert do specjalisty
Zatrzymane wydatki koszt bliski zera w godzinach, gdy zwykle jest ruch -60% alert: płatności, odrzucenia, wyłączone kampanie
Przekroczenie limitu miesięcznego koszt od początku miesiąca vs limit 90% limitu – alert, 100% – pauza automatyczna pauza kampanii z etykietą
Prognoza powyżej limitu koszt dzienny × dni do końca miesiąca prognoza > 105% limitu alert z prośbą o decyzję
Gwałtowna zmiana budżetu historia zmian zasobu budżetu zmiana o 50% w górę lub w dół alert z nazwą użytkownika
Wydatki bez konwersji koszt kampanii w danym dniu przy zerowych konwersjach 2–3× docelowy CPA alert lub przegląd kampanii

Progi w tabeli to punkt wyjścia. Na małym koncie 50% wzrostu może oznaczać kilkadziesiąt złotych i nie warto o tym alarmować, dlatego zawsze łącz próg procentowy z minimalną kwotą. Ostatni typ anomalii, czyli koszt bez konwersji, opisujemy razem z innymi kontrolami w artykule o 10 skryptach do monitorowania konta Google Ads.

Skrypt Google Ads do kontroli tempa wydatków godzina po godzinie

Ten skrypt porównuje koszt od początku dnia z przeciętnym kosztem z tych samych godzin w ostatnich 14 dniach. Dzięki temu uwzględnia naturalny rozkład ruchu w ciągu dnia: o 10:00 wydatki są zawsze niższe niż o 20:00, więc porównywanie ich z całym budżetem dziennym dawałoby fałszywe alarmy.

var CONFIG = {
  EMAIL: 'alerty@twojsklep.pl',
  SLACK_WEBHOOK: '',      // opcjonalnie adres webhooka Slacka
  DNI_HISTORII: 14,
  PROG_WZROSTU: 0.5,      // +50% względem typowego poziomu
  PROG_SPADKU: 0.6,       // -60% względem typowego poziomu
  MIN_KOSZT: 100          // nie alarmuj przy niższych kwotach (PLN)
};

function main() {
  var tz = AdsApp.currentAccount().getTimeZone();
  var teraz = new Date();
  var godzina = parseInt(Utilities.formatDate(teraz, tz, 'H'), 10);
  if (godzina < 2) return; // za mało danych na początku doby

  var dzis = Utilities.formatDate(teraz, tz, 'yyyy-MM-dd');
  var wczoraj = Utilities.formatDate(new Date(teraz.getTime() - 86400000), tz, 'yyyy-MM-dd');
  var start = Utilities.formatDate(new Date(teraz.getTime() - CONFIG.DNI_HISTORII * 86400000), tz, 'yyyy-MM-dd');

  var kosztDzis = koszt("segments.date = '" + dzis + "' AND segments.hour < " + godzina);
  var kosztHist = koszt("segments.date BETWEEN '" + start + "' AND '" + wczoraj + "' AND segments.hour < " + godzina);
  var typowy = kosztHist / CONFIG.DNI_HISTORII;

  var odchylenie = typowy > 0 ? (kosztDzis - typowy) / typowy : 0;
  var opis = 'Koszt do godz. ' + godzina + ':00: ' + kosztDzis.toFixed(2) + ' zł, typowo: ' + typowy.toFixed(2) + ' zł';

  if (odchylenie >= CONFIG.PROG_WZROSTU && kosztDzis >= CONFIG.MIN_KOSZT) {
    alert('Wydatki szybsze niż zwykle (+' + Math.round(odchylenie * 100) + '%)', opis);
  } else if (odchylenie <= -CONFIG.PROG_SPADKU && typowy >= CONFIG.MIN_KOSZT) {
    alert('Wydatki wyraźnie niższe niż zwykle (' + Math.round(odchylenie * 100) + '%)', opis);
  }
}

function koszt(warunek) {
  // segments.hour musi być w SELECT, bo występuje w WHERE
  var rows = AdsApp.search('SELECT segments.hour, metrics.cost_micros FROM customer WHERE ' + warunek);
  var suma = 0;
  while (rows.hasNext()) suma += Number(rows.next().metrics.costMicros) / 1e6;
  return suma;
}

function alert(temat, tresc) {
  var konto = AdsApp.currentAccount().getName() + ' (' + AdsApp.currentAccount().getCustomerId() + ')';
  MailApp.sendEmail(CONFIG.EMAIL, '[Google Ads] ' + temat + ' – ' + konto, tresc);
  if (CONFIG.SLACK_WEBHOOK) {
    UrlFetchApp.fetch(CONFIG.SLACK_WEBHOOK, {
      method: 'post', contentType: 'application/json',
      payload: JSON.stringify({ text: '*' + temat + '* – ' + konto + '\n' + tresc })
    });
  }
}

Skrypt porównuje tylko pełne godziny (warunek segments.hour < godzina), bo bieżąca godzina jest niekompletna. Jeśli Twoje konto ma wyraźnie inny ruch w weekendy, zmodyfikuj zapytanie historyczne tak, by brało pod uwagę tylko te same dni tygodnia – wtedy zwiększ DNI_HISTORII do 28, żeby mieć cztery dni porównawcze. Jak wysyłać bardziej rozbudowane wiadomości na Slacka, pokazujemy w artykule o automatycznych raportach Google Ads.

Skrypt do kontroli budżetu miesięcznego z automatyczną pauzą

Drugi skrypt pilnuje limitu miesięcznego dla grupy kampanii oznaczonych etykietą. Wysyła ostrzeżenie przy 90% limitu i przy prognozie przekroczenia, a po osiągnięciu limitu wstrzymuje kampanie. Automatyczna pauza to ostateczność – stosuj ją tam, gdzie przekroczenie budżetu jest gorsze niż utrata sprzedaży, np. przy stałym budżecie klienta.

var LIMIT_PLN = 30000;                // limit miesięczny dla kampanii z etykietą
var ETYKIETA = 'limit-miesieczny';
var EMAIL = 'alerty@twojsklep.pl';

function main() {
  var tz = AdsApp.currentAccount().getTimeZone();
  var teraz = new Date();
  var dzien = parseInt(Utilities.formatDate(teraz, tz, 'd'), 10);
  var rok = parseInt(Utilities.formatDate(teraz, tz, 'yyyy'), 10);
  var miesiac = parseInt(Utilities.formatDate(teraz, tz, 'M'), 10);
  var dniWMiesiacu = new Date(rok, miesiac, 0).getDate();

  var lab = AdsApp.search("SELECT label.resource_name FROM label WHERE label.name = '" + ETYKIETA + "'");
  if (!lab.hasNext()) { Logger.log('Brak etykiety ' + ETYKIETA); return; }
  var labelRn = lab.next().label.resourceName;

  var rows = AdsApp.search(
    "SELECT campaign.resource_name, campaign.name, metrics.cost_micros FROM campaign " +
    "WHERE segments.date DURING THIS_MONTH AND campaign.status = 'ENABLED' " +
    "AND campaign.labels CONTAINS ANY ('" + labelRn + "')");

  var suma = 0, kampanie = [];
  while (rows.hasNext()) {
    var r = rows.next();
    suma += Number(r.metrics.costMicros) / 1e6;
    kampanie.push({ rn: r.campaign.resourceName, nazwa: r.campaign.name });
  }
  var prognoza = suma / dzien * dniWMiesiacu;
  var info = 'Koszt od 1. dnia miesiąca: ' + suma.toFixed(0) + ' zł z ' + LIMIT_PLN +
             ' zł. Prognoza na koniec miesiąca: ' + prognoza.toFixed(0) + ' zł.';

  if (suma >= LIMIT_PLN) {
    kampanie.forEach(function (k) {
      AdsApp.mutate({ campaignOperation: { update: { resourceName: k.rn, status: 'PAUSED' }, updateMask: 'status' } });
    });
    MailApp.sendEmail(EMAIL, '[Google Ads] Limit osiągnięty – wstrzymano ' + kampanie.length + ' kampanii', info);
  } else if (suma >= 0.9 * LIMIT_PLN || prognoza > 1.05 * LIMIT_PLN) {
    MailApp.sendEmail(EMAIL, '[Google Ads] Ryzyko przekroczenia limitu miesięcznego', info);
  }
}

Prognoza jest liniowa, więc w miesiącach z wyraźną sezonowością (Black Friday, święta) będzie zaniżona w pierwszej połowie miesiąca. Na ten okres lepiej przygotować plan wydatków z korektą sezonowości, który opisujemy w poradniku o budżecie na Black Friday i Q4. Pamiętaj też, że w trybie podglądu skrypt nie wprowadza zmian na koncie, więc pauzę przetestujesz bezpiecznie dopiero na kampanii testowej z niskim limitem.

Alert o dużych zmianach budżetu w historii zmian

Trzeci skrypt raz na godzinę przegląda historię zmian i wyłapuje budżety zmienione o co najmniej 50% w górę lub w dół. W alercie podaje autora zmiany i typ klienta, czyli informację, czy zmianę wprowadzono w interfejsie, przez Edytora, API, regułę automatyczną czy skrypt.

var EMAIL = 'alerty@twojsklep.pl';

function main() {
  var tz = AdsApp.currentAccount().getTimeZone();
  var teraz = new Date();
  var od = Utilities.formatDate(new Date(teraz.getTime() - 2 * 3600000), tz, 'yyyy-MM-dd HH:mm:ss');
  var doo = Utilities.formatDate(teraz, tz, 'yyyy-MM-dd HH:mm:ss');

  var rows = AdsApp.search(
    "SELECT change_event.change_date_time, change_event.user_email, change_event.client_type, " +
    "change_event.change_resource_name, change_event.old_resource, change_event.new_resource " +
    "FROM change_event WHERE change_event.change_date_time >= '" + od + "' " +
    "AND change_event.change_date_time <= '" + doo + "' " +
    "AND change_event.change_resource_type = 'CAMPAIGN_BUDGET' " +
    "ORDER BY change_event.change_date_time DESC LIMIT 500");

  var linie = [];
  while (rows.hasNext()) {
    var e = rows.next().changeEvent;
    var stary = e.oldResource && e.oldResource.campaignBudget;
    var nowy = e.newResource && e.newResource.campaignBudget;
    if (!stary || !nowy || !stary.amountMicros || !nowy.amountMicros) continue;
    var a = Number(stary.amountMicros) / 1e6, b = Number(nowy.amountMicros) / 1e6;
    if (b >= a * 1.5 || b <= a * 0.5) {
      linie.push(e.changeDateTime + ' | ' + a.toFixed(0) + ' → ' + b.toFixed(0) + ' zł | ' +
                 e.userEmail + ' | ' + e.clientType + ' | ' + e.changeResourceName);
    }
  }
  if (linie.length) {
    MailApp.sendEmail(EMAIL, '[Google Ads] Duże zmiany budżetów: ' + linie.length, linie.join('\n'));
  }
}

Okno dwóch godzin przy uruchamianiu co godzinę daje zakładkę, która chroni przed pominięciem zmian, jeśli jedno uruchomienie się opóźni. Ceną jest możliwość podwójnego alertu o tej samej zmianie. Zasób change_event wymaga ograniczenia daty do ostatnich 30 dni i klauzuli LIMIT. Zmiany wprowadzane przez asystentów AI mogą być oznaczone różnymi typami klienta, dlatego przez pierwsze tygodnie sprawdzaj w alertach, jak opisane są zmiany z Ask Advisor na Twoim koncie.

Jak wdrożyć skrypt i ustawić harmonogram krok po kroku

Wdrożenie każdego z trzech skryptów wygląda tak samo i zajmuje kilkanaście minut.

  1. Otwórz edytor skryptów. W Google Ads przejdź do sekcji narzędzi, a następnie do działań zbiorczych i skryptów. Dodaj nowy skrypt.
  2. Wklej kod i uzupełnij konfigurację. Zmień adres e-mail, progi i limity. Przy limicie miesięcznym utwórz etykietę i przypisz ją do kampanii.
  3. Autoryzuj skrypt. Przy pierwszym uruchomieniu Google poprosi o zgodę na dostęp do konta i wysyłanie e-maili.
  4. Uruchom podgląd. Sprawdź w logach, czy zapytania zwracają dane i czy obliczone wartości są sensowne. Podgląd nie wprowadza zmian na koncie.
  5. Ustaw harmonogram. Dla tempa wydatków i historii zmian wybierz uruchamianie co godzinę, dla limitu miesięcznego – co godzinę w okresach wzmożonej sprzedaży, poza nimi wystarczy kilka razy dziennie.
  6. Przetestuj alert. Tymczasowo obniż próg, żeby upewnić się, że wiadomość dociera do właściwych osób i nie trafia do spamu.
  7. Udokumentuj skrypt. Zapisz w opisie konta lub w dokumentacji zespołu, jakie skrypty działają, kto jest ich właścicielem i jakie mają progi.

Na koncie menedżera (MCC) te same kontrole możesz uruchomić dla wielu kont naraz, korzystając z AdsManagerApp.accounts().executeInParallel(), który przetwarza do 50 kont równolegle. Pojedyncze uruchomienie skryptu może trwać maksymalnie 30 minut. Jeśli potrzebujesz monitoringu większej liczby kont albo integracji z własnymi systemami, rozważ Google Ads API po zmianach z września 2026.

Jak ustawić progi, żeby alerty nie były szumem

Alert, który przychodzi codziennie, po tygodniu przestaje być czytany. Dlatego progi trzeba dobrać do zmienności konta, a nie do intuicji.

Załóżmy, że sklep wydaje 20 000 zł miesięcznie, czyli średnio ok. 650 zł dziennie, a koszt z tych samych godzin w kolejnych dniach waha się zwykle o 20–30%. Próg 50% z minimum 100 zł będzie wtedy reagował na realne anomalie, a nie na zwykłe wahania. Na koncie wydającym 300 zł dziennie lepszy będzie próg 70–80% i minimum 50 zł.

Kilka zasad praktycznych:

  • Łącz próg procentowy z kwotowym. Sama wartość procentowa generuje fałszywe alarmy rano i na małych kontach.
  • Wyłączaj lub łagodź alerty w znanych okresach. Podczas Black Friday wzrost o 50% jest planem, a nie anomalią.
  • Kieruj alerty do właściciela konta. Wiadomość na wspólnej skrzynce, za którą nikt nie odpowiada, nie skróci czasu reakcji.
  • Nie reaguj pochopnie na każdą anomalię. Budżet zmieniony w panice też szkodzi. W październiku 2026 roku Google potwierdził, że zmiany celu i budżetu nie resetują okresu nauki, ale gwałtowne korekty wciąż zmieniają warunki działania strategii – więcej w tekście o okresie nauki Smart Bidding.

Anomalia wydatków bywa też objawem problemu z pomiarem: jeśli koszt rośnie, a konwersje nagle spadają do zera, przyczyną może być zepsuty tag, a nie kampania. Dlatego alerty budżetowe warto połączyć z monitoringiem tagów na produkcji i kontrolą zdarzeń kluczowych w GA4. Pozostałe poradniki o automatyzacji znajdziesz w podtemacie Skrypty i automatyzacja, a przegląd funkcji platformy – na stronie narzędzia Google Ads.

Najczęściej zadawane pytania

Czy Google Ads może wydać więcej niż budżet dzienny?

Tak. W pojedynczym dniu kampania może wydać do dwóch razy więcej niż średni budżet dzienny. Google pilnuje natomiast, by w miesiącu rozliczeniowym łączny koszt nie przekroczył średniego budżetu dziennego pomnożonego przez 30,4. Nadwyżkę ponad ten limit system kompensuje w rozliczeniu.

Jak często uruchamiać skrypt kontrolujący budżet?

Skrypty kontrolujące tempo wydatków i zmiany budżetów najlepiej uruchamiać co godzinę, bo to najczęstszy dostępny harmonogram. Limit miesięczny można sprawdzać rzadziej, np. kilka razy dziennie, ale w okresach dużej sprzedaży lepiej co godzinę. Pamiętaj, że dane z bieżącego dnia mogą mieć kilkugodzinne opóźnienie.

Czy skrypt może automatycznie wstrzymać kampanie?

Tak. Skrypt może zmienić status kampanii na wstrzymany, np. po przekroczeniu limitu miesięcznego. Stosuj to tylko do kampanii oznaczonych etykietą i tam, gdzie przekroczenie budżetu jest gorsze niż utrata sprzedaży. W trybie podglądu skrypt nie wprowadza zmian, więc pauzę testuj na kampanii z niskim limitem.

Czy skrypty Google Ads działają na koncie menedżera?

Tak. Na koncie menedżera (MCC) skrypt może przejść po kontach podrzędnych i wykonać te same kontrole dla każdego z nich. Funkcja executeInParallel() przetwarza do 50 kont równolegle. Przy większej liczbie kont lub złożonych integracjach lepiej sprawdza się Google Ads API.

Skąd wiadomo, kto zmienił budżet kampanii?

Z historii zmian w Google Ads albo z zasobu change_event w zapytaniu GAQL. Zawiera on adres e-mail autora, datę, typ klienta (interfejs, Edytor, API, skrypt, reguła) oraz wartości przed i po zmianie. Dane są dostępne za ostatnie 30 dni.