INP zamiast FID — case study sklepu WooCommerce z problemem interaktywności
Od marca 2024 INP zastąpił FID jako Core Web Vital. Case study: sklep WooCommerce z INP 890 ms (fail) — co zdiagnozowaliśmy, co naprawiliśmy, INP po 2 tygodniach: 180 ms.

Do marca 2024 w Core Web Vitals mieliśmy FID (First Input Delay) — mierzył opóźnienie pierwszej interakcji użytkownika. FID dla większości stron był „zielony”, bo mierzy tylko pierwszą klikniętą rzecz. Google zastąpił go przez INP (Interaction to Next Paint), który mierzy najgorsze opóźnienie reakcji strony na dowolną interakcję w całej sesji. Próg zielony: < 200 ms. Próg czerwony: > 500 ms.
I nagle 40% stron, które wcześniej miały „zielony FID”, ma teraz czerwony INP. Poniżej — case z naszego klienta, sklep WooCommerce ok. 3500 produktów, który przyszedł do nas z INP 890 ms w PageSpeed mobile. Przedstawiam cały proces: diagnoza → fix → wynik.
Punkt wyjścia: co znaleźliśmy
PageSpeed Mobile dla home + PDP + cart:
| Metryka | Home | PDP | Cart |
|---|---|---|---|
| LCP | 3.2 s | 2.8 s | 2.4 s |
| INP | 890 ms | 720 ms | 1240 ms |
| CLS | 0.08 | 0.11 | 0.15 |
Cart był najgorszy. Każda interakcja (zmiana ilości, usunięcie produktu, zastosowanie kuponu) trwała > 1 sekundy. User widział, że coś się dzieje — czekał — frustrowal się — opuszczał koszyk. W praktyce: porzucanie koszyka 68% (średnia branży ~70%, ale klient wcześniej miał 61%, więc coś się pogorszyło).
Diagnoza — gdzie zjada się czas
INP mierzy trzy fazy opóźnienia przy każdej interakcji:
- Input delay — czas od input eventu do start event handlera (event jest w kolejce czekając na wolny main thread).
- Processing time — ile sam handler zajmuje.
- Presentation delay — czas od końca handlera do kolejnego paintu.
Do audytu używamy Chrome DevTools → Performance panel → Record → kliknij w problematyczny element. Dostajesz wykres czasu (tzw. “flame chart”) pokazujący, gdzie każdy ms poszedł.
Co znaleźliśmy w naszym sklepie:
1. jQuery 1.12 + jQuery Migrate 1.4
Motyw z 2018, dwie stare wersje jQuery ładujące się przy każdym request. jQuery na klik przycisku „+ 1” w koszyku wykonywał event bubbling + selektor global $(document).on(...) → 180 ms input delay.
2. Heartbeat API WooCommerce
Co 15 sekund WooCommerce wysyła POST /wp-admin/admin-ajax.php?action=heartbeat z sesją koszyka. Handler po stronie PHP trwał 320 ms (bo checkował cart expiry, sprawdzał dostępność produktów, odnawiał token). Przy kliku na koszyk w trakcie heartbeat → main thread zablokowany.
3. Google Tag Manager z 18 tagami
Każdy tag to event listener. Handler klika na produkt wysyłał dataLayer.push(...) → 6 tagów reagowało → każdy po 40 ms → razem 240 ms sam GTM.
4. Mini-cart fragment update
WooCommerce default pattern: po dodaniu do koszyka wraca AJAX z fragmentami HTML, które wymieniają mini-cart. Parsowanie 2-3 KB HTML string przez jQuery’s .replaceWith() → 80 ms.
5. Revolution Slider na homepage
Nie bezpośrednio w koszyku, ale konsumował pamięć i CPU cykle tła. Wpływał na input delay na wszystkich stronach.
Fixy — w kolejności impaktu
A. Zdjęcie jQuery (biggest win)
WooCommerce działa bez jQuery od wersji 8.5 (kwiecień 2024). W motywie znaleźliśmy 3 miejsca, które go wymagały — przepisaliśmy na vanilla JS (fetch + event listeners). wp_dequeue_script('jquery') + wp_dequeue_script('jquery-migrate') w functions.php.
Efekt: -45 KB gzipped JS z bundle, -250 ms TBT.
B. Przeniesienie GTM przez Partytown
Z plain <script> w <head> na type="text/partytown". GTM + wszystkie tagi lądują na web worker thread, nie blokują main thread przy interakcjach.
Efekt: -200 ms INP przypadek krytyczny na koszyku.
C. Heartbeat API throttling
W functions.php:
add_filter('heartbeat_settings', function($settings) {
$settings['interval'] = 60; // was 15
return $settings;
});
add_action('init', function() {
if (!is_admin()) {
wp_deregister_script('heartbeat');
}
});Heartbeat wyłączony na froncie, w admin panelu co 60 s zamiast co 15 s.
Efekt: -150 ms przypadek krytyczny INP, ~40% redukcja requestów do admin-ajax.
D. Debounce na zmianie ilości w koszyku
Default WooCommerce po każdym +/- wysyła AJAX update cart. Jeśli user klika +++++ (5 razy) → 5 requestów → ostatni wygrywa, ale main thread zapchany.
Dodaliśmy debounce 400 ms:
let qtyTimeout;
document.querySelectorAll('.qty-input').forEach(input => {
input.addEventListener('input', () => {
clearTimeout(qtyTimeout);
qtyTimeout = setTimeout(() => {
updateCartQty(input.dataset.productId, input.value);
}, 400);
});
});Efekt: -300 ms INP w przypadek krytyczny koszyk przy szybkim klikaniu.
E. Rewrite Revolution Slider → Swiper
Revolution Slider 2018 = 120 KB + jQuery dependency. Zastąpiliśmy Swiper.js (native, 30 KB). Poza tym zgodne z accessibility (nawigacja klawiaturą), bez CVE w historii.
Efekt: -90 KB z home, ale INP na stronach bez slidera bez zmian.
F. React mini-cart zamiast fragmentów
Tu była większa praca — zamiast jQuery fragments, mini-cart jako niezależny komponent React z własnym state (reaguje na custom event wc-cart-updated). Zero fragment parsing, zero replaceWith — tylko state update → React re-render.
Efekt: -80 ms na każdej aktualizacji koszyka.
Wyniki — po 2 tygodniach
| Metryka | Home (przed → po) | PDP (przed → po) | Cart (przed → po) |
|---|---|---|---|
| LCP | 3.2 s → 1.8 s | 2.8 s → 1.6 s | 2.4 s → 1.4 s |
| INP | 890 ms → 140 ms | 720 ms → 180 ms | 1240 ms → 220 ms |
| CLS | 0.08 → 0.05 | 0.11 → 0.06 | 0.15 → 0.08 |
Wszystkie zielone. INP na koszyku 220 ms — granica, ale już zielona. W praktyce: porzucanie koszyka spadło z 68% do 54% w ciągu 4 tygodni po wdrożeniu.
Co zrobić samemu — w kolejności wpływu
- Mierzyć INP field data — w PageSpeed Insights sekcja „Real users (CrUX)”. Jeśli > 200 ms — masz problem. Jeśli brak danych — w Chrome DevTools → Performance → nagraj typową interakcję.
- Zdejmij jQuery gdzie się da — WooCommerce od 8.5 działa bez. Old themes wymagają audytu.
- GTM przez Partytown — w Astro dodajesz integrację jedną linijką, w WordPressie — plugin „WP-Rocket” z opcją delay JS lub bezpośrednio attrybut
type="text/partytown"+ biblioteka Partytown. - Heartbeat throttling albo wyłączenie na froncie — WordPress wysyła heartbeat w tle nawet na frontpage.
- Debounce interakcji formularzy / koszyka — custom JS, ale 20 linijek kodu.
- Revolution Slider / Slider Revolution → Swiper — single biggest JavaScript cleanup move dla starych motywów.
Kiedy INP to nie jest problem kodu, tylko hostingu
Jeśli Twój serwer jest za wolny (TTFB > 500 ms), AJAX update koszyka trwa długo nie z powodu JS, tylko czekania na response. Przed ukryciem INP zawsze sprawdź TTFB. Jeśli TTFB > 600 ms → najpierw wąskie gardło backendu (inny artykuł o hostingu i przyspieszaniu WordPressa).
W Devance INP audit to standardowa część naszego darmowego audytu WordPress. Jeśli masz sklep WooCommerce z pogorszoną konwersją bez zmian w produkcie czy cenach — zwykle winne jest INP. Pokażemy gdzie konkretnie i ile będzie kosztował fix.

Doświadczony WordPress Developer z ponad 14-letnim stażem w tworzeniu zaawansowanych stron i sklepów internetowych. Specjalizuje się w WordPressie, dedykowanych wtyczkach i motywach.
Więcej o autorze
