Rubriky
Blog o webové analytice

Používáš ve svém kódu slovo „ads“? Připrav se na neviditelný web a nebo jeho část!

Možná si myslíš, že prefix ad- v CSS je neškodný. Vždyť je to jen pár písmen, jasně čitelné i pro juniory. Jenže právě těch pár písmen dokáže tvému frontendu udělat dokonale prázdnou stránku.
Ještě horší? O chybě se dozvíš až od zuřivého klienta. V produkci. V pátek odpoledne. S GA4 tichým jako pěna, protože se nenačetl ani pixel.

Takže: chceš-li přežít a zachovat si UX (a duševní zdraví), čti dál. Dnes ti ukážu, proč ad-blokátory loví všechno, co zavání reklamou, kde přesně se pálíme nejčastěji a jak se tomu vyhnout bez šarlatánství typu „anti-ad-block skript“.

Audio verze článku

Délka záznamu 8 minut

Proč na tom záleží?

EasyList – základní muničák většiny ad-blokátorů – obsahuje tisíce pravidel, která se spouštějí ještě dřív, než blikne první pixel tvého layoutu. A mezi nimi i zdánlivě nevinné řádky jako:

##[id^="ad-"]
##[class*=" ads-"]

Pozn. ## je zápis z adblockeru, normální css selector je bez něj.

Tahle regexová kudla skryje každý element, jehož id začíná na ad- nebo class obsahuje samostatné „ads“ .

Podobně síťové filtry stopnou requesty na URL typu /ads/, /banner/, nebo subdoménu ads.example.com (easylist.to). Výsledek? Soubor se nenačte, JavaScript hodí chybu, a ty dumáš, proč je komponenta rozbitá jen „u některých uživatelů“.

Varování: nejsou to jen ID a class

Blokátory dnes umí „kosmetické“ filtry i nad textovým obsahem – třeba :-abp-contains() schová <span>Reklama</span> čistě podle vnitřního textu (help.adblockplus.org). Jednoduché? Ani náhodou.

Jak loví blokátory tvé selektory?

  1. CSS injection – v manifestu extension se přidá stylopis s globálními selektory (viz výše).
  2. URL rewrite & cancel – pokud request odpovídá filtru, padá rovnou na síťové vrstvě.
  3. Scriptlet hijacking – uBlock Origin dovede vložit JS, jenž selektivně ruší či mění DOM.

Bacha, tady se chybuje nejčastěji: Když prvek nejdřív není v DOMu (lazy render) a ad-blokátor mezitím stihl nasypat filtr, skryje se okamžitě po injectu. Přepočet layoutu ti pak celé UI posune a pixel-perfektní grid je v háji.

Příklady z praxe

  1. U projektu, který prodává SaaS pro SMB, bylo tlačítko „Add-ons“ (id="addons_btn"). Nevinné, že?  Dostali skvělý nápad mu dát novou třídu class="ads-variant"a konverze spadla o 32 %. Proč? Uživatelé s uBlockem tlačítko prostě neviděli. Víte jak se to blbě debaguje 🙂 ?
  2. Několikrát jsem jsem viděl, třeba subdoménu pro Server GTM pojmenovanou GTM, analytics, 🙂 etc. a pak takové server GTM je blokované asi i více než to základní 🙂 . Proto doporučuji do takových subdomén dávat jména jako „chleba“, „zarovka“, „auto“ a nebo cokoliv náhodného, ale rozhodně nic spojeného s analytikou nebo reklamou.
  3. Znám projekt kde dali do názvu hlavní domény slovíčko analytics a pokud jste kliknuli na odkaz směřující na tuto doménu, tak vám to házelo varování 🙂 .  To nebylo dobry, myslím si že ten projekt časem umřel.
  4. Tip od Robin Pokorný: I generovaný hash class HTML prvku může obsahovat slov „ad“ třeba hodnota „ad01“. Aneb další malá podmínku do kódu 🙂 .
  5. Tip od Martin Maly: Bacha i na názvy cookies, web vytvářel cookies obsahující ve jméně „ident“ a ty byli u uživatelů v prohlížeči mazány. Za mě i bacha na názvy jako „ga“, „analytics“ „id“ u názvů cookies, občas jsou bloknuté taky.
  6. A jelikož existují i blokátory cookie lišt, tak je velmi dobré se v nich vyhnout názvům a ID jako je cookie, consent etc. Aneb uživatel, co ani neuvidí vaši cookie lištu, tak vám jistě souhlas nedá.

Kde děláme chyby nejčastěji?

  • Adresářová struktura: /static/**ads**/banner.png
  • Hasherem generované ID: gtm-ad-1234
  • WordPress šablony: theme-adwise, widget_banner
  • Alt a title: alt="Advertisement"
  • Data atributy: data-ad-slot="header"
  • Subdoména: ads.mydomain.cz

A vždy stejný scénář: „U mě na lokále to funguje, v produkci u 30 % návštěv ne.“

Jak z toho ven?

1. Pojmenuj to jinak

Používej projektově-specifické aliasy: místo ad-slot třeba slotHero, slotSidemenu. Uvnitř slova nevadí (he*ad*er, ro*ad*map) – filtry většinou vyžadují hranice slova.

2. Hashuj cesty k assetům

Pokud CDN vyžaduje strukturu /img/ads/…, zaveď reverse-proxy přepis na /img/a1b2c3/…. Je to jeden Nginx rewrite a máš klid.

Z praxe webového analytika: Dříve se dokonce detekovali adblockery přes soubor pojmenovaný „ads.js“ a pokud se nenašetl a nezapsala se proměnné, tak jste věděli, že uživatel blokuje reklamu.

3. Odděl semantiku od layoutu

Potřebuješ-li prvek označit kvůli legislativnímu „Sponsored” štítku, dej mu dvě třídy:

<span class="slotA1 sponsorLabel">Sponsored</span>

Při sty­lování počítej, že sponsorLabel může zmizet – velikost a padding nech raději na rodiči.

4. Detect & fallback

const slot = document.querySelector('#slotHero');
if (!slot || slot.offsetHeight === 0) {
 console.warn('Adblock? Switching to fallback.');
 renderFallback(slot);
}

Žádná detekce API? Využij starý dobrý DOM.

Začni hned – budoucí já ti poděkuje.

Checklist před releasem

  1. Audit názvů – projdi build artefakty (grep -R --line-number -E '\\b(ad|banner|promo|sponsor|analytics)\\b' dist/).
  2. Lokální test – nainstaluj uBlock Origin a AdGuard. Obojí, občas mají různé feedy.
  3. Spusť Lighthouse + ad-block – sleduj rozdíl v JS errors.
  4. Check GA4 hits – trafí měření i s blokátorem? Pokud ne, zvaž server-side GTM proxy.
  5. E2E test na CI – Cypress + uBlock ve headless Chrome.
  6. Monitoruješ rozbitý layout? – jednoduchý visual-diff screenshot test.
  7. Log fallbacků – když se spustí renderFallback, pošli event do Sentry.
  8. Nastav alerty – 5% nárůst fallbacků == Slack ping.
  9. Re-audit při každém major refactoru frontendu.
  10. Dokumentuj – ať příští kolega ví, proč existuje slotHero a ne adHeader.

Osobní tipy, které mi zachránily karieru

„Pojmenuj to nejdřív ošklivě, pak zkrášli“

Když vymýšlím ID komponent, napíšu schválně hnusný placeholder: XXX_NEJSEM_AD. Refakto­ruju teprve, jakmile vidím layout na dev serveru. Pomáhá to zabránit reflexu napsat první, co mě napadne („adBox“).

„Mockni si ad-blokátor v API“

Potřebuješ-li ladit bez extension, nech reverse-proxy mazat /ads/ requesty. Rychlejší iterace, stejný výsledek.

„Neustále grepuj diff“

Hook v pre-commit, který zakáže commity obsahující \bads?\b v nových souborech, ti ušetří studené poty.

Shrnutí

  • Ad-blokátory nečtou úmysly, jen regexy.
  • Klíčová slova ad, ads, banner, promo a slova příbuzná stejného významu v ID, class, URL či souboru ⇒ prvek zmizí.
  • K pádu layoutu stačí jeden skrytý wrapper.
  • Řešení je primitivní: přejmenovat a fallbackovat.
  • Automatizuj detekci, jinak na to zapomeneš.

Co máte udělat po přečtení článku?

  • Udělat si kontrolu u sebe na webu.
  • Přidat si to do dokumentace pro vývojáře,

Jak to vidíte vy? Máte vlastní horror-story s id="adBanner" nebo jste ustáli nasazení bez ztrát? Podělte se v komentářích na sociálních sítích, ať se příště smějeme společně, ne jednotně plačeme.

 

Zkrácena verze, co jsem dal k nám do dokumentace:

Vyhýbejte se slovům „ad“, „ads“, „advert“, „banner“… v identifikátorech a cestách

Platí pro: id, class, atributy data-*, názvy souborů a adresářů, subdomény, URL parametrů

Pravidlo

  • Nikdy nepoužívejte uvedená klíčová slova ani jejich zkrácené/rozšířené varianty (ad, ads, adv, advert, banner, promo, sponsor…)
    • …pokud stojí na začátku nebo za oddělovačem (-, _, /, .).
  • Povoleno je, když řetězec leží uvnitř jiného slova (header, roadmap).

Proč

  1. Blokátory reklamy (uBlock Origin, AdBlock Plus, AdGuard…) se řídí seznamy jako EasyList.
    • Obsahují globální CSS filtry skrývající prvky podle selektorů typu ##[id^="ad-"], ##.ads-banner stackoverflow.com
    • A síťové filtry, které ruší požadavky na URL s částmi /ads/, /banner/ či doménami ads.example.com adblockplus.org
  2. Jakmile blokátor pravidlo trefí, prvek dostane display:none nebo se request vůbec nespustí → layout se rozpadne či kód selže „beze stopy“.
  3. Incidenty s ID ad_holder, tématem „adwise“ apod. ukazují, že jde o častý zdroj skrytých chyb.

Důsledky porušení

  • Neviditelné komponenty (tlačítka, modaly, ikony…)
  • Chybějící JS/CSS soubory ⇒ JS errors, rozhozený design
  • Obtížné ladění – poskytovatelé i QA často nemají ad-block zapnutý

Výjimky

Kde je to bezpečnéProč
Viditelný text („Reklama“, „Sponsored“)Filtry umísťují slovo do layoutu jen kosmeticky; nespoléhejte na jeho rozměry
Komentáře v HTML/JS, interní proměnnéBlokátory je neparsují

Příklady

❌ Nesprávně✅ Správně
<div id="ad_holder"><div id="slotHero">
/static/ads/logo.svg/static/assets/logo.svg
class="banner_top"class="heroTop"

Dodržováním tohoto pravidla předejdete nečekanému skrývání prvků a ušetříte hodiny pátrání po „záhadně mizících“ komponentech.

Protože to zaujalo i lidi z mezinárodních teamů, tak tu mám i verzi v angličtině.

.