Modelowane listy odbiorców nie zawierają konkretnych osób, tylko prawdopodobieństwa. Wyjaśniam, jak powstają, gdzie ich szukać w panelu i jak czytać ich raporty.
Od marca zeszłego roku INP jest pełnoprawnym wskaźnikiem Core Web Vitals i przez ten rok zdążył zepsuć raporty niejednemu sklepowi, który wcześniej wyglądał przyzwoicie. Z LCP i CLS pracuje się inaczej — tam zwykle da się dojść do porządnego wyniku kilkoma konkretnymi ruchami po stronie obrazków, fontów i rezerwowania miejsca na elementy.
INP jest trudniejszy, bo nie mierzy tego, jak strona się pokazuje, tylko tego, jak szybko odpowiada na dotknięcie. A sklep jest najbardziej „klikalnym” rodzajem serwisu, jaki istnieje: filtry, wybór wariantu, dodanie do koszyka, wyszukiwarka z podpowiedziami. Każde z tych miejsc to osobne wąskie gardło i osobna przyczyna.
Opisuję tu sposób pracy, którego używam, kiedy dostaję do naprawy duży sklep z czerwonym INP. Co zmierzyć na początku, w jakiej kolejności szukać przyczyn i które zmiany faktycznie przekładają się na dane z pola, a nie tylko na wynik jednorazowego testu.
INP bierze wszystkie interakcje użytkownika na stronie — kliknięcia, dotknięcia i wciśnięcia klawiszy — i raportuje praktycznie najgorszą z nich. Nie średnią. To fundamentalna różnica względem wskaźnika, na którego miejsce wszedł: tamten patrzył wyłącznie na pierwszą interakcję i tylko na to, ile czekała, zanim przeglądarka zaczęła się nią zajmować.
Tu liczy się cały czas od dotknięcia do momentu, w którym użytkownik widzi na ekranie efekt. Progi są proste: do 200 milisekund to wynik dobry, powyżej 500 milisekund słaby, między nimi strefa „wymaga poprawy”. Ocena dotyczy 75. percentyla realnego ruchu, więc jeden zepsuty element klikany przez co czwartego użytkownika potrafi zdecydować o statusie całej grupy adresów.
Warto od początku rozbić opóźnienie na trzy części, bo od tego zależy, gdzie szukać winy. Pierwsza to czas oczekiwania na wolny wątek — przeglądarka jest zajęta czymś innym i nie zaczęła jeszcze obsługiwać zdarzenia. Druga to wykonanie kodu przypisanego do tego zdarzenia. Trzecia to czas potrzebny na przeliczenie układu strony i narysowanie nowej klatki.
Z mojego doświadczenia w sklepach dominuje część pierwsza i trzecia, a nie druga — czyli nie sam kod obsługi kliknięcia jest problemem, ale to, co dzieje się wokół niego.
Strona firmowa albo blog mają kilka interakcji na sesję: rozwinięcie menu, przewinięcie, klik w link. Sklep ma ich dziesiątki i większość z nich uruchamia jednocześnie logikę interfejsu, przeliczenie ceny, zapytanie do serwera i kilka zdarzeń analitycznych.
Dochodzi do tego rozmiar dokumentu. Lista kategorii z sześćdziesięcioma produktami, rozbudowanym panelem filtrów i megamenu to bardzo często kilka tysięcy węzłów w drzewie strony. Przy takim dokumencie każda zmiana klasy CSS oznacza dla przeglądarki dużo więcej pracy przy przeliczaniu układu niż na prostej podstronie. Efekt widać właśnie w trzeciej części opóźnienia.
Trzecia rzecz to warstwa integracji. Sklepy noszą na sobie menedżer tagów, pikselki reklamowe, wyszukiwarkę zewnętrznego dostawcy, personalizację, testy A/B i zwykle jeszcze parę wtyczek dorzuconych po drodze. Każdy z tych skryptów walczy o ten sam wątek, na którym musi wykonać się reakcja na kliknięcie.
I ostatnie, o czym się rzadko mówi: urządzenia. Ruch mobilny w handlu to w dużej części telefony ze średniej i niskiej półki, kilkuletnie. Ten sam kod, który na moim laptopie odpowiada natychmiast, na takim sprzęcie liczy się wielokrotnie dłużej. Dlatego wynik z pola bywa dramatycznie gorszy niż wrażenie z własnych testów.
Kolejność jest tu nienegocjowalna, bo bez danych z pola naprawia się rzeczy, które nikomu nie przeszkadzają.
Wyniki z biblioteki warto wysyłać do własnego zbioru danych i patrzeć na nie w rozbiciu na typ urządzenia i szablon strony. Dopiero wtedy dyskusja z zespołem technicznym przestaje być wymianą opinii.
Jeśli dominuje czas oczekiwania na wolny wątek, problem leży poza obsługą kliknięcia. Ktoś zajmuje przeglądarkę długimi zadaniami — najczęściej inicjalizacją skryptów zewnętrznych, wczytywaniem danych do karuzeli albo jednorazową operacją na całej liście produktów. Naprawa polega na dzieleniu tych zadań na mniejsze fragmenty i oddawaniu kontroli przeglądarce między nimi, a także na przesunięciu wszystkiego, co nie jest potrzebne od razu, na później.
Jeśli dominuje wykonanie kodu, patrzę na to, co dzieje się w reakcji na zdarzenie. Klasyczny wzorzec do naprawy: w jednym miejscu wywoływane są naraz aktualizacja stanu, odczyt z pamięci lokalnej, przeliczenie koszyka i wysłanie zdarzenia do analityki. Wystarczy zostawić w obsłudze kliknięcia wyłącznie zmianę tego, co użytkownik ma zobaczyć, a resztę wykonać po narysowaniu klatki.
Jeśli dominuje czas na narysowanie klatki, sprawcą jest zwykle rozmiar i złożoność dokumentu. Tu pomaga skracanie list renderowanych naraz, ograniczanie zagnieżdżeń, unikanie animowania właściwości wymuszających przeliczenie układu i wskazanie przeglądarce, których fragmentów strony nie musi liczyć, dopóki nie są widoczne.
Rozróżnienie tych trzech przypadków oszczędza tygodnie pracy. Zespół, który bez pomiaru „optymalizuje JavaScript”, zwykle poprawia część, która i tak zajmowała najmniej.
Filtry na listingu kategorii to numer jeden. Zaznaczenie jednego pola potrafi uruchomić przeliczenie liczników przy wszystkich pozostałych filtrach, przerysowanie całej listy i zmianę adresu. Rozwiązanie, które sprawdza mi się najlepiej: natychmiast pokazać zmianę stanu samego pola, a wynik listy podmienić chwilę później, bez blokowania interfejsu.
Drugie miejsce to wybór wariantu na karcie produktu. Rozmiar i kolor często przebudowują pół strony: galerię, cenę, dostępność, tabelę rozmiarów. Warto sprawdzić, czy naprawdę wszystko musi się przeliczyć od nowa.
Trzecie to wyszukiwarka z podpowiedziami. Każde wciśnięcie klawisza liczy się do INP, a podpowiedzi zwykle wiszą na zewnętrznej usłudze. Bez ograniczenia częstotliwości zapytań i przerywania nieaktualnych ten element sam potrafi zepsuć wynik całej witryny.
Czwarte to podglądowy koszyk. Dodanie produktu bywa najdroższą interakcją w sklepie, bo łączy zapytanie do serwera, aktualizację licznika, otwarcie panelu i kilka zdarzeń pomiarowych. Interfejs powinien pokazać reakcję od razu i dopiero potem uzgodnić stan z serwerem.
Część opóźnienia nie należy do Ciebie. Skrypty dostawców zewnętrznych wykonują się na tym samym wątku i nie masz wpływu na ich wnętrze — możesz jedynie zdecydować, czy i kiedy się wczytają. To osobny temat, któremu poświęcam oddzielny wpis, bo decyzja o wyłączeniu narzędzia rzadko jest wyłącznie techniczna.
Nie da się też sensownie „dogonić” wskaźnika na urządzeniach, które są po prostu wolne. Można natomiast przestać wysyłać do nich kod, którego nie potrzebują — na przykład dzielić paczki JavaScriptu tak, żeby karta produktu nie ładowała logiki kreatora zamówienia.
Trzecie ograniczenie jest organizacyjne. INP mierzy się na żywym ruchu z ostatnich dwudziestu ośmiu dni, więc po wdrożeniu poprawki wynik w raportach zmienia się z opóźnieniem. Trzeba to powiedzieć wprost przed startem prac, inaczej po dwóch tygodniach ktoś uzna, że zmiany nie zadziałały.
I rzecz, którą powtarzam przy każdym takim projekcie: dobry wskaźnik nie jest celem. Celem jest sklep, w którym da się wygodnie wybrać rozmiar na telefonie w tramwaju. Wskaźnik jest tylko sposobem sprawdzenia, czy to się udało.
Największym problemem nie jest doprowadzenie wskaźnika do zieleni, ale utrzymanie go tam. Sklepy żyją: dochodzą wtyczki, banery, nowe narzędzia marketingowe, kolejne testy. Każde takie wdrożenie potrafi cofnąć efekt kilku tygodni pracy.
Dlatego zostawiam po sobie dwie rzeczy. Pierwsza to stały pomiar w polu, z podziałem na szablony, przeglądany raz w miesiącu razem z resztą raportu. Druga to prosta zasada w procesie wdrożeń: każdy nowy skrypt na stronie ma przypisaną osobę, która potrafi odpowiedzieć na pytanie, po co on tam jest.
Brzmi banalnie, ale to właśnie brak tej drugiej rzeczy jest przyczyną, dla której u większości przejmowanych przeze mnie sklepów wydajność interfejsu z czasem systematycznie się pogarsza.
Używamy plików cookies, aby ułatwić Ci nawigację oraz wykonywanie określonych funkcji. Szczegółowe informacje o wszystkich plikach cookies znajdziesz w każdej kategorii zgody poniżej.
Pliki cookies oznaczone jako "Niezbędne" są przechowywane w Twojej przeglądarce, ponieważ są one kluczowe dla zapewnienia podstawowych funkcji strony.
Używamy również plików cookies firm trzecich, które pomagają nam analizować, w jaki sposób korzystasz z tej strony, zapamiętują Twoje preferencje oraz dostarczają treści i reklamy odpowiednie dla Ciebie. Te pliki cookies będą przechowywane w Twojej przeglądarce tylko za Twoją uprzednią zgodą.
Możesz zdecydować, czy chcesz włączyć lub wyłączyć niektóre bądź wszystkie te pliki cookies, jednak wyłączenie niektórych z nich może wpłynąć na Twoje doświadczenia podczas przeglądania strony.
| Cookie | Czas przechowywania | Opis |
|---|---|---|
| __cf_bm | 13 minutes | Cloudflare bot management — distinguishes humans from bots. |
| rc::* | Persistent | Google reCAPTCHA — localStorage holding anti-bot challenge state. |
| Cookie | Czas przechowywania | Opis |
|---|---|---|
| wpEmojiSettingsSupports | Session | WordPress — sessionStorage flag caching whether the browser can render emoji (feature detection). |
| ytidb* | Persistent | YouTube — IndexedDB storing playback/search state for embedded videos. |
| Cookie | Czas przechowywania | Opis |
|---|---|---|
| _ga_* | 400 days | Google Analytics 4 — persists session state per property. |
| _ga | 400 days | Google Analytics — distinguishes unique users via a client id. |
| Cookie | Czas przechowywania | Opis |
|---|---|---|
| NID | 183 days | Google — stores preferences for personalized ads. |
| fr | 90 days | Meta — encrypted Facebook id and browser id for ads. |
| _gcl_au | 90 days | Google AdSense/Ads — experiments with advertising efficiency (conversion linker). |
| Cookie | Czas przechowywania | Opis |
|---|---|---|
| __Secure-YNID | 180 days | |
| YSC | Session | |
| __Secure-ROLLOUT_TOKEN | 180 days | |
| VISITOR_INFO1_LIVE | 180 days | |
| VISITOR_PRIVACY_METADATA | 180 days | |
| datr | 400 days | |
| sb | 400 days | |
| wd | 7 days |