TL;DR: PPC kampane sa v Google Ads v tomto prípade optimalizujú na maržu, nie na obrat. Maržu počíta naša serverová infraštruktúra (server-side GTM) a posiela ju Googlu ako „hodnotu konverzie”. Jeden večerný deployment zmenil výpočet a namiesto marže sa začala posielať celá hodnota objednávky — číslo, ktoré sme Googlu hlásili, zo dňa na deň vyskočilo takmer o 80 %. Algoritmus to prečítal ako „darí sa nám lepšie” a začal v aukciách pridávať vyššie ponuky. Nikto si to nevšimol, pretože to bolo v polovici výpredaja a dashboard vyzeral skvele (vyšší ROAS!) — v skutočnosti sme však za rovnaký obrat platili viac. Z incidentu vznikol jednoduchý denný strážca: skript, ktorý porovnáva priemernú hodnotu objednávky s predošlým obdobím a pri výchylke nad 40 % pošle email.

Najprv si predstavte tachometer, ktorý začne klamať

Predstavte si auto s tempomatom. Tempomat si na svoju prácu pýta jediný údaj — aktuálnu rýchlosť — a podľa neho pridáva alebo uberá plyn, aby udržal vašu nastavenú rýchlosť, povedzme 100 km/h.

A teraz si predstavte, že tachometer z nejakého technického dôvodu začne ukazovať dvojnásobné čísla. Idete päťdesiatkou, on ukazuje stovku. Tempomat sa pozrie a povie si: „výborne, sme na cieľovej rýchlosti.” Vy za volantom vidíte to isté — že idete stovkou. Lenže v skutočnosti idete päťdesiatkou. Palivo míňate dvakrát rýchlejšie, než by ste mali, ale na palubnej doske vyzerá všetko v poriadku.

Presne toto sa môže stať aj v Google Ads. Namiesto tachometra je to hodnota konverzie, ktorú do Google Ads posiela váš tracking, a namiesto tempomatu bidding algoritmus, ktorý podľa nej pridáva alebo uberá ponuky v aukciách. Stačí, aby sa niečo v dátovej vrstve zlomilo, a algoritmus začne pridávať plyn na základe nesprávneho čísla. A nemusí ísť len o maržu — hodnota konverzie môže byť v dátovej vrstve nafúknutá, môže byť po jednej chybnej objednávke extrémne vysoká, alebo nemusí chodiť vôbec. Platí to bez ohľadu na to, či posielate maržu alebo úplne klasický obrat objednávky.

A tu je dôležité si uvedomiť jednu vec: túto chybu môžete mať práve teraz a ani o nej neviete — a nemusí byť v marži. Stačí jeden deployment v ľubovoľnej vrstve, ktorá počíta a posiela hodnotu konverzie, a bidding začne optimalizovať na nesprávne číslo. Práve preto sa oplatí mať jednoduchý alert, ktorý takúto výchylku zachytí za pár dní — a presne taký si v tomto článku postavíme.

Čo presne sa pokazilo

Aby celý príbeh dával zmysel, krátky kontext k nášmu nastaveniu. (Sľubujem, technické len natoľko, koľko je nevyhnutné.)

V Google Ads platíte za kliky v aukciách. Ako vysoké ponuky algoritmus dáva, závisí od toho, akú hodnotu konverzii systému povieme. Firmy zvyčajne posielajú ako hodnotu konverzie obrat (cenu objednávky bez DPH alebo aj s DPH) — Google ich potom optimalizuje na čo najvyšší obrat za euro výdavkov (ROAS).

My ideme o krok ďalej. Namiesto obratu posielame maržu — teda peniaze, ktoré nám reálne ostanú po odpočítaní nákladov na tovar a ďalších variabilných nákladov. Naše PPC kampane sa tak optimalizujú na skutočný zisk, nie na obrat. Pre biznis je to lepšie (algoritmus tlačí ziskové produkty, nielen tie drahé), ale technicky náročnejšie — maržu treba vypočítať v reálnom čase a poslať do trackingu.

Tento výpočet robí server-side Google Tag Manager (sGTM). Pri každej objednávke zavolá interné margin API, dostane maržu, prenásobí ju koeficientom a výslednú hodnotu pošle do Google Ads ako „hodnotu konverzie”. Google ju prijme, agreguje a podľa nastaveného Target ROAS (povedzme 2,5) určuje ponuky.

Čo sa stalo:

  • deployment zmenil logiku odosielania,
  • namiesto marže sa začala posielať celá hodnota objednávky (obrat),
  • hodnota konverzie posielaná do Google Ads zo dňa na deň vyskočila takmer o 80 %,
  • náš Target ROAS (nastavený na margin ROAS) ostal nezmenený, povedzme 2,5,
  • Google Ads si to vyhodnotil takto: „prichádza výrazne vyššia hodnota, target plním ľahko, môžem priháňať vyššie ponuky”,
  • PMAX kampaň teda zvýšila ponuky o nemalý kus,
  • reálny obrat zostal rovnaký, náklady ale vyleteli hore.

Podstatné je, že to nie je o marži. Presne ten istý typ poruchy vás dobehne aj s úplne bežnou hodnotou objednávky — stačí deployment v GTM, server-side GTM, v pixeli alebo v API, ktoré hodnotu počíta. Hodnota môže zrazu chodiť dvojnásobná, môže prísť extrémne vysoká po jednej rozbitej objednávke, alebo prestane chodiť úplne. Vo všetkých týchto prípadoch bidding stratí pôdu pod nohami — a všetky ich zachytí ten istý jednoduchý strážca, ktorý popíšem nižšie.

Tu sa príbeh stáva nepríjemným. Bol to incident, na ktorý sa dashboard nepozeral správnym smerom.

Tri dôvody, prečo nám ušiel:

1. Dashboard ukazoval zlepšenie, nie zhoršenie.

ROAS v Google Ads = hodnota konverzie / náklady. Keď hodnota konverzie vyskočila a náklady stúpli len o malú časť, ROAS narástol. Náš PPC dashboard ukazoval pekné zelené čísla. Samozrejme, v inom dashboarde — napríklad z dát GA4 — to už nevyzeralo tak dobre ako v Google Ads.

2. Relatívna zmena sa pre náš objem zdala možná.

Priemerná hodnota objednávky (AOV) o približne 80 % vyššia je v rozsahu, ktorý by sme mohli vidieť pri sezónnej zmene produktového mixu alebo pri zmene zákazníckej štruktúry. Bez kontextu „toto je oproti predošlým týždňom” to nepôsobilo podozrivo.

3. Nemali sme automatickú porovnávaciu metriku.

Áno, mali sme týždenné reporty. Áno, mali sme dashboardy. Ale nikto sa pravidelne nepozerá na priemernú hodnotu objednávky a nepýta sa: „nezmenila sa od minulého týždňa o viac ako 20 %?” Je to custom metrika v Google Ads, na ktorú sa nikto sám od seba nepozerá. A keď sa na ňu náhodou pozrel, povedal si „aha, zaujímavé, treba to preveriť” — a tým sa začalo pátranie.

Anatómia ekonomickej škody

Keď sa po incidente pozriete na sezónny graf, výsledok je jasný — porovnanie obdobia po incidente s predošlou baseline:

MetrikaZmena oproti baseline
Hodnota / konverzia (AOV)+80 %
ROAS (v Google Ads)+24 %
Počet konverzií−29 %
Náklady+10 %

Pozrite si tabuľku ešte raz. Náklady rastú, počet konverzií klesá, ale ROAS rastie. To je klasický incident, pri ktorom sa nafúkla metrika hodnoty, no reálny biznis stagnuje alebo klesá.

Konkrétne číslo sa dá vypočítať, ale to nie je pointa článku. Pointa je, že incident vďaka skriptu rýchlo odhalíme, hoci po jeho identifikácii bolo riešenie technicky triviálne — oprava výpočtu v sGTM, jeden pull request.

Lekcia: keď bidding optimalizuje, signál musí byť pod kontrolou

Toto je staršia, ale dôležitá pravda v systémoch s automatickým rozhodovaním. Platí pre PPC, ale rovnako pre rizikové skóre v bankovníctve, detekciu podvodov, moderovanie obsahu — pre akýkoľvek systém, ktorý sa učí na našom signáli a podľa neho mení správanie.

Keď algoritmus optimalizuje na metriku, ktorá je interná a kontrolujeme si ju my:

  1. metrika musí byť stabilne počítaná,
  2. zmeny v jej výpočte musia byť zámerné a koordinované s tým, čo dostane bidding,
  3. akýkoľvek nezámerný posun v jej hodnote sa stane druhotnou poruchou — bidding zareaguje, ale škoda sa prejaví inde (vo výdavkoch, v efektivite, vo viditeľnej kvalite).

Druhé pravidlo často padá pri deploymentoch. Niekto si povie „je to drobný fix”, urobí merge, deploy — a netušiac tým posunie hodnotu o 80 %. Z pohľadu kódu je to platná zmena. Z pohľadu systému, ktorý sa na tomto signáli učí, je to ako náhly šok v dátach.

Riešenie: jednoduchý denný strážca

Aby sa takáto situácia odhalila do dvoch-troch dní, netreba pokročilý ML model, ani alertovaciu infraštruktúru nad BigQuery, ani drahé observability nástroje. Stačí jedna jednoduchá vec:

Každý deň sa pozrieť na priemernú hodnotu objednávky v každom účte a spýtať sa: „nezmenila sa o podozrivo veľa?”

Plus pár ďalších zámerne jednoduchých kontrol:

  1. Hodnota objednávky (AOV) — výchylka ±40 % oproti priemeru za predošlé dva týždne → ALERT
  2. Náklady — +50 % nad priemer za predošlé dva týždne → ALERT (pre prípad „runaway” biddingu)
  3. Počet konverzií — −50 % pod priemer za predošlé dva týždne → ALERT (pre prípad, že tracking v jednom účte úplne vypadne)
  4. 0 konverzií dnes, ale 50+ minulý týždeň → ALERT (tracking je úplne pokazený)

Štyri pravidlá. Žiadne tiery podľa veľkosti účtov. Žiadne podmienky podľa krajiny. Jedna a tá istá kontrola naprieč všetkými účtami v MCC. Beží cez Google Ads Script ako natívny trigger, každé ráno o 7:00.

Dôležitá vlastnosť: deduplikácia

Ak by skript poslal alert v deň 1 a problém by trval ďalších sedem dní, naivné riešenie by poslalo sedem emailov za sebou. Tie sa stanú šumom — človek ich začne ignorovať a presne v tom momente sa stratí signál ďalšieho incidentu.

Náš skript preto vedie stavovú tabuľku (Google Sheet) — pri každom účte si pamätá, či bol v predošlom behu „v alerte”. Email sa pošle iba pri zmene stavu:

  • OK → ALERT = nový alert (email)
  • ALERT → OK = vyriešené (email — potvrdenie, že je po probléme)
  • ALERT → ALERT = pretrvávajúci problém (žiadny email, len kontextový riadok pri najbližšom prirodzenom maile)
  • OK → OK = nič (žiadny email)

Výsledok: dva emaily na incident (jeden keď začne, jeden keď skončí), nie sedem.

Zdravý rozum namiesto štatistiky

Pri menších účtoch je prirodzený šum AOV okolo 20 % — jedna veľká objednávka vie priemer poriadne posunúť. Pri väčších účtoch (s tisíckami objednávok týždenne) je šum okolo 2 %.

Prečo teda nerobiť tiery — pre malý účet vyšší prah, pre veľký nižší? Logika za jediným prahom je jednoduchá:

  • reálne incidenty (ako ten s nafúknutou hodnotou) sa prejavia výkyvom AOV rádovo o desiatky percent — často +80 % aj viac,
  • aj na malom účte takýto incident prah 40 % triviálne zachytí,
  • pod 30 % by sme dostávali falošné poplachy z malých účtov,
  • nad 50 % by prešli skutočné incidenty, ktoré si treba všimnúť.

Záver: jeden prah 40 % pre všetkých je dobrá voľba. Zachytí to, čo je reálne zlé. Mlčí, keď je všetko v poriadku. A keď do MCC pribudne nový účet, automaticky sa pridá do monitoringu bez akejkoľvek konfigurácie.

Niekedy je „jednoduché pravidlo aplikované všade” pragmaticky lepšie ako „presné pravidlo prispôsobené každému prípadu”.

Druhá vrstva ochrany: monitoring nesmie ohroziť to, čo stráži

Drobnosť na záver, ale dôležitá. Náš skript je read-only:

  • volá iba AdsApp.search() (GAQL dotaz — iba čítanie),
  • zapisuje do Sheetu mimo Google Ads,
  • posiela email cez MailApp.

Nemôže pozastaviť kampaň. Nemôže zmeniť rozpočet. Nemôže upraviť ponuku. Ani omylom.

Je to zámerné rozhodnutie. Monitorovacie skripty by mali mať zakázanú akciu — ich úloha je informovať, nie reagovať. Automatická reakcia (napríklad „keď AOV vyletí, automaticky pozastav kampaň”) je veľmi lákavá, ale veľmi nebezpečná. Falošný poplach plus automatické pozastavenie = niekoľko hodín stratených peňazí v reklame, ktorá fungovala. A v deň skutočného incidentu automatické pozastavenie pripraví tím o možnosť urobiť si vlastný úsudok.

Lepšie je, keď skript upozorní a človek sa pozrie. Pri štyroch alertovacích pravidlách a deduplikačnej logike je „kričanie” zriedkavé a vždy zaslúžené.


Praktický nadhľad pre tých, ktorí podobný systém zvažujú

  • Prevádzkové náklady: 0 €. Google Ads Scripts sú zadarmo, Sheet je zadarmo, email cez MailApp tiež.
  • Údržba: pri pridaní novej krajiny žiadna (skript iteruje cez všetky účty v MCC automaticky). Pri zmene prahov stačí upraviť jednu konštantu.

A keď budete nabudúce robiť deployment v službe, od ktorej závisí výkonový algoritmus — spomeňte si na tachometer. Nie každý dashboard ukazuje to, čo by ste čakali.