Jak si (ne)zabít eshop měřícím kódem

Posted 13. 11. 2016 / By Petr Soukup / Eshop

Pro klienty do eshopů nasazujeme nejrůznější měřící kódy, personalizační služby a podobně. Bohužel velká část těchto služeb má kód velmi špatně řešený a použitím podle oficiálních instrukcí se můžete připravit o část tržeb.

Typický špatný kód

U služeb, které vůbec neřeší rychlost webu, můžete narazit na instrukce pro vložení zhruba v této podobě:

<html>
<head>
    <script src="https://tracking-1948.org/tracking.js"></script>
    <script>
        _anal = new Analytics();
        _anal.trackProductView({
            id: 123
        });
        _anal.personalize(function(html){
            document.getElementById('personalize').innerHTML = html;
        });
    </script>
</head>
<body>
 ... obsah eshopu
</body>
</html>

Problém tohoto způsobu vložení je, že dokud se nenačte měřící skript tracking.js, nenačte se ani nic dalšího. Skript bývá navíc typicky hostovaný v Kalifornii, která je 200ms daleko. Načítání skriptu tak hravě zablokuje načítání na vteřinu, a protože má zakázané cachování, tak se to děje při každém načtení stránky.

Pokud pak chcete volat kód například po nějaké akci návštěvníka, tak musíte pořád dokola kontrolovat, jestli je měřící kód vůbec načtený - mohl ho zablokovat AdBlock nebo jen výpadek služby a volání neexistující funkce vám může eshop znefunkčnit.

Nejde ale jen o samotné čekání na skript. Zablokováním vykreslování se ve skutečnosti načítání zpomalí výrazně více. Můžete to porovnat na videu níže. Vlevo je web se správně vloženým kódem a vpravo je kód blokující vykreslování.

Vzniká potom paradoxní situace - vložíte si skript, který vám má zlepšit konverze, ale okamžitě si je naopak snížíte. V případě služeb na A/B testování (například Optimizely) pak nemáte ani možnost porovnání, protože nesledujete vliv změny barvy tlačítka, ale vliv zpomalení.

Tento způsob vkládání uvidíte hlavně u menších služeb. Snaží se vymýšlet kolo, místo aby se podívaly k větší konkurenci. On je tento způsob praktičtější pro programátory, ale je důvod, proč to velcí hráči dělají jinak.

Správné vložení kódu

U velkých služeb (Facebook, Google, ...) uvidíte vždy prakticky shodný způsob meření.

<html>
<body>
 ... obsah eshopu 
    <script>
        _anal = _anal || [];
        _anal.push(['trackProductView',{
            id: 123
        }]);
        _anal.push(['personalize', function(html){
            document.getElementById('personalize').innerHTML = html;
        }]);
    </script>
    <script src="https://tracking-1948.org/tracking.js" async defer></script>
</body>
</html>

Pro větší názornost ještě porovnání původní a vylepšené verze vedle sebe:

Na první pohled vypadají oba kódy podobně. Kritický rozdíl je ale u externího skriptu, který se načítá asynchronně. Nebude blokovat vykreslování stránky bez ohledu na to, kam ho vložíte (vkládat ho na konec stránky je jen konvence daná historií).

Pokud se bude externí skript načítat 10 sekund, je to celkem jedno - stránka se vykreslí bez něj a nebude čekat. Můžete s měřením navíc pracovat, aniž by bylo nutné na jeho načtení čekat. Bez problémů můžete například zaznamenat zvětšení fotky návštěvníkem před tím, než se vůbec skript načte. Nebo už může být klidně načtený - web nemusí nijak řešit, co se kdy načetlo a vše funguje vždycky stejně.

Když se externí měřící skript nenačte vůbec, tak je proměnná jen obyčejné pole a nic se nerozbije.

Magic!

Data můžeme zapisovat ještě před načtením měřícího skriptu a odešlou se po jeho načtení. Při zapisování po jeho načtení se odesílají hned. Jak to funguje uvnitř externího skriptu? Překvapivě jednoduše.

(function() {
_anal = {
    quee: _anal || [],
    push: function(item) {
        // odeslání dat na server         
    }
};
while(var item = _anal.quee.shift()) {
    _anal.push(item);
}
})();

Měřící skript přepíše proměnnou _anal, která se používá v kódy webu pro měření. Původně šlo o obyčejné pole a externí skript ho naradí za vlastní objekt, který se chová podobně jako původní pole. Takže když pak ve stránce voláte _anal.push(), může jít buď o obyčejné pole nebo měřící objekt - nemusí te to ale nijak řešit.

Při načtení také vezme frontu příkazů původně uloženou do pole _anal a odešle je na server.

Na tomto způsobu je geniální, jak je jednoduchý. Pokud služba má blokující synchronní kód, tak je otázkou pár řádků kódy doplnit podporu pro asynchronní zpracování.

Buďte nároční!

Nevkládejte si do webu měřící skript slepě. Jeden špatný skript vás může připravit o dost peněz. Hlavně na mobily jsou podobné detaily hrozně znát. Pamatujete, jak jste se snažili na FUP načíst web, ale 15 sekund jste viděli jen bílou stránku? Tohle byl důvod.

U špatně navrhnutých měřících skriptů ale musí úpravu nejdříve provést měřící služba u sebe. Nenechte se uchlácholit a vyžadujte podporu asynchronního zpracování. Pro službu je to minimální práce navíc a rozdíl je obrovský.

Jak to řešíme u nás

V administraci eshopů není žádné kouzelné pole, kam by šlo vložit měřící kód. A pokud má eshop přístup přímo k editaci šablony, tak ta ještě před publikováním prochází automatickou kontrolou, která kromě jiného kontroluje blokování vykreslování.

Více se nám osvědčilo, když kódy implementujeme přímo my. Můžeme je pak upravit, aby byly optimálnější (80% případů) a ideálně rovnou rozšířit o pokročilější možnosti implementace, které služba nabízí.



O blogu
Blog o provozování eshopů a technologickém zázemí.
Aktuálně řeším hlavně cloud, bezpečnost a optimalizaci rychlosti.

Rozjíždím službu pro propojení eshopů s dodavateli.