INP (Interaction to Next Paint) — deep dive 2026
INP (Interaction to Next Paint) zastąpił FID w marcu 2024 jako Core Web Vital responsywności. INP mierzy worst-case opóźnienie interakcji w całej sesji — nie tylko pierwszej. Cel <200ms na mobile. Wysokie INP = ranking penalty + frustrated users. W 2026 to jeden z najważniejszych ranking factors, ale w audytach, które robimy, wciąż też najmniej rozumiany — klienci pytają o LCP, prawie nikt nie pyta o INP, dopóki nie pokażemy, gdzie boli.
TL;DR — INP
| Element | Detale |
|---|---|
| Co mierzy | Czas od interakcji (kliknięcie) do następnego painta |
| Granice | Good <200ms, Needs Improvement 200-500ms, Poor >500ms |
| Wprowadzony | Marzec 2024 (zastąpił FID) |
| Mobile vs desktop | Mobile 2-3x wyższe INP (słabszy CPU) |
| Ranking factor | Tak — Page Experience update |
| Główne przyczyny | Heavy JavaScript, long tasks, inefficient handlers |
| Optymalizacja | Code splitting, defer, web workers, optimize handlers |
Czym INP różni się od FID?
FID (First Input Delay) — deprecated
Mierzył opóźnienie pierwszej interakcji użytkownika. Problem: jeśli pierwszy klik był szybki (50ms), ale każdy następny 800ms — FID nadal pokazywał „good". To była metryka, która pozwalała stronie wyglądać dobrze na papierze, mimo że realny użytkownik po piątym kliknięciu miał już dość.
INP (Interaction to Next Paint) — current
Mierzy interakcje w całej sesji. Bierze 75th percentile (lub max przy <50 interakcji). Pokazuje realny user experience.
Praktyka:
- FID: 1 measurement
- INP: aggregated z 10+ interakcji
- INP > FID typowo (FID was forgiving)
Co to jest „Next Paint"?
User klika button → strona musi:
- Process event (event listener fires)
- Run JavaScript (callback execution)
- Update DOM (state change)
- Re-render (browser paints new state)
INP = czas od step 1 do step 4 (next paint po interakcji).
Granice INP
Good (<200ms)
- Interakcja czuje się instant
- User nie zauważa opóźnienia
- Ranking factor passing
Needs Improvement (200-500ms)
- Interakcja czuje się laggy
- User zauważa opóźnienie
- Ranking factor warning
Poor (>500ms)
- Interakcja czuje się broken
- User clicka multiple times (więcej events!)
- Ranking penalty significant
Dlaczego INP jest hard?
Cztery rzeczy sprawiają, że INP jest trudniejsze do ogarnięcia niż LCP czy CLS — i dlatego regularnie widzimy strony, które mają zielone LCP i CLS, a mimo to tracą pozycje.
1. Mobile devices are slower
iPhone 12 vs MacBook M2 — INP 5-10x wyższe na mobile. Devs testują na M2, mobile users sufferują. To najczęstszy powód, dla którego klient jest zaskoczony wynikiem audytu — na jego laptopie strona „działa świetnie".
2. Real user data
Lab tests (Lighthouse) nie capture real INP. CrUX (Chrome User Experience Report) data przeważa.
3. Long tail
INP = worst case. 99% interakcji może być szybkie, 1 slow click rejestruje INP.
4. Third-party scripts
Analytics, chat, ads — często źródło long tasks. Hard to remove (business need). To jest ten rodzaj problemu, gdzie techniczna odpowiedź (usuń skrypt) zderza się z biznesową (marketing potrzebuje danych z tego skryptu) — i trzeba szukać kompromisu, nie tylko fixu w kodzie.
Główne przyczyny wysokiego INP
1. Heavy JavaScript
Główna przyczyna. Frameworks (React, Vue, Angular) + business logic + tracking = 200-500KB+ JS execution.
Fix:
- Code splitting (load tylko tego co potrzebne)
- Lazy loading components
- Tree shaking (usuń unused code)
- Smaller bundle (Astro, Next.js + RSC)
2. Long tasks (>50ms)
Browser blocks UI gdy JS task running. Long tasks = JS execution longer than 50ms.
Fix:
- Break long tasks:
setTimeout,requestIdleCallback - Web Workers dla heavy compute
requestAnimationFramefor visual updates
3. Inefficient event handlers
// Złe — heavy work na każdy click
button.addEventListener('click', () => {
// 200ms of computation
for (let i = 0; i \< 10000; i++) {
expensiveOperation();
}
updateUI();
});
// Dobre — defer heavy work
button.addEventListener('click', () => {
// UI feedback immediate
showLoadingSpinner();
// Heavy work async
setTimeout(() => {
for (let i = 0; i \< 10000; i++) {
expensiveOperation();
}
hideLoadingSpinner();
updateUI();
}, 0);
});
4. Layout thrashing
Reading + writing DOM in same frame causes forced reflows.
// Złe — thrashing
elements.forEach(el => {
const height = el.offsetHeight; // read
el.style.height = height + 10 + 'px'; // write — forces reflow
});
// Dobre — batch reads, then writes
const heights = elements.map(el => el.offsetHeight); // all reads first
elements.forEach((el, i) => {
el.style.height = heights[i] + 10 + 'px'; // all writes after
});
5. Third-party scripts
Chat widgets, analytics, ads. Often blocked main thread.
Fix:
- Defer loading (
<script defer>lubasync) - Self-host when possible
- Replace heavy chat with lightweight alternatives
- Audit usage — czy używasz wszystko?
6. React synchronous re-renders
Big React tree + frequent state changes = blocking renders.
Fix:
- React.memo for pure components
- useMemo / useCallback dla expensive calculations
- React Concurrent Mode / Suspense (React 18+)
- Virtualization dla long lists (react-window)
Jak debugować INP
Zanim cokolwiek naprawimy, chcemy zobaczyć konkretną interakcję, która psuje wynik — nie ogólny score, tylko klik, który trwa najdłużej.
1. PageSpeed Wnioski
pagespeed.web.dev → mobile tab. Pokazuje:
- INP score
- Interactions causing high INP
- Recommendations
2. Chrome DevTools — Skuteczność tab
- Open DevTools (F12)
- Skuteczność tab
- Click record
- Interact z stroną (10-15 razy różne actions)
- Stop recording
- Look for Long Tasks (>50ms — orange/red)
- Drill into specific task — what's slow?
3. Web Vitals Chrome Extension
Real-time INP w Chrome toolbar. Mierzy actual user interactions na Twojej stronie.
4. Web Vitals JS library
<script type="module">
import {onINP} from 'https://unpkg.com/web-vitals?module';
onINP(metric => {
console.log('INP:', metric.value);
// Send to analytics
gtag('event', 'web_vitals', {
name: 'INP',
value: metric.value,
});
});
</script>
Real User Monitoring (RUM) — capture INP od actual users.
5. CrUX (Chrome User Experience Report)
https://pagespeed.web.dev/
Compare your INP vs competitors using real user data z Chrome.
Strategie optymalizacji INP
Kolejność, w jakiej podchodzimy do tych siedmiu strategii, zależy od tego, co pokazał debugging wyżej — nie warto zaczynać od web workerów, jeśli problemem jest jeden ciężki skrypt analityczny.
Strategy 1: Reduce JavaScript bundle
- Tree shaking — remove unused exports
- Code splitting — load chunks per route
- Bundle analysis (webpack-bundle-analyzer) — co jest big?
- Replace heavy libraries (moment.js → date-fns, lodash → native)
Strategy 2: Defer non-critical JS
<!-- Defer = wait for HTML parse, then execute in order -->
<script src="/main.js" defer></script>
<!-- Async = execute as soon as loaded -->
<script src="/analytics.js" async></script>
Strategy 3: Web Workers
Heavy compute → separate thread, doesn't block main thread:
// main.js
const worker = new Worker('/heavy-task.js');
worker.postMessage({data: largeArray});
worker.onmessage = (e) => {
console.log('Result:', e.data);
};
// heavy-task.js
self.onmessage = (e) => {
const result = expensiveProcessing(e.data.data);
self.postMessage(result);
};
Strategy 4: Optimize React
- React 18 + Concurrent rendering
- React.memo dla components
- useMemo, useCallback
- Virtualization dla list (>100 items)
- Suspense dla data fetching
Strategy 5: Reduce third-party impact
- Audit third-party scripts (Lighthouse → Third-party usage)
- Replace heavy with light (e.g. Crisp Chat → custom WhatsApp link)
- Self-host analytics (server-side tracking)
- Lazy load chat widgets (only after first scroll)
Strategy 6: Optimize event handlers
- Throttle / debounce frequent events (scroll, resize)
- Pasywne event listeners gdzie OK
- Use
onClickper element rather niż delegated parent
Strategy 7: Minimize DOM size
Large DOM (>1500 nodes) = slow layout calculations.
- Pagination (less items per page)
- Virtualization
- Reduce nesting levels
INP w różnych frameworks
Next.js / React
Common INP issues:
- Large bundle (default 200-500KB JS)
- Hydration cost
- Frequent re-renders
Fix:
- React Server Components (Next.js 13+)
- Dynamic imports
next/scriptz defer
Astro
Best dla INP — ships zero JS by default. Component „islands" hydrated only when needed. Jeśli klient pyta, jak w ogóle uniknąć problemu z INP zamiast go leczyć, to jest odpowiedź.
WordPress
INP often poor due to:
- Plugin JS bloat
- Theme JS
- Third-party (analytics, social, ads)
Fix:
- Aggressive lazy loading
- Caching plugin (WP Rocket)
- Plugin audit (remove unused)
- Lighter theme
Vanilla JS
Best control, lowest INP możliwe. Ale wymaga more dev time.
INP optimization checklist
- Bundle size <300KB JS (gzipped)
- No JavaScript blocking >50ms tasks
- Critical path JS deferred or async
- Third-party scripts lazy loaded
- Event handlers debounced/throttled gdzie applicable
- React components memoized
- Lists virtualized (>100 items)
- DOM <1500 nodes per page
- No layout thrashing
- Web Workers dla heavy compute
- Mobile-first testing (real devices)
- RUM monitoring deployed
Najczęstsze błędy w optymalizacji INP
- Testing tylko na desktop — mobile dwukrotnie wolniejsze
- Lab data only — Lighthouse nie capture real INP
- Synchronous heavy compute — blocks main thread
- Premature optimization — fix główne problemy first
- Removing analytics blindly — utrata data
- Brak monitoring — nie wiesz czy się poprawia
- Single optimization — cumulative impact = many small fixes
INP a Core Web Vitals overall
INP jest jednym z 3 CWV:
- LCP (Largest Contentful Paint) — loading speed
- CLS (Cumulative Layout Shift) — visual stability
- INP — responsiveness (zastąpiło FID)
Wszystkie muszą passing dla good Page Experience score.
Podsumowanie
INP 2026:
- Cel <200ms na 75th percentile mobile
- Główna przyczyna — heavy JavaScript blocking main thread
- Debug w DevTools — Skuteczność tab + Long tasks
- Real User Monitoring — Web Vitals library
- Optymalizacje: code splitting, defer, web workers
- Mobile-first testing — emulate slow CPU
- Continuous monitoring — INP changes z każdym deployment
Z tego, co widzimy w praktyce, INP to metryka, którą klienci najczęściej ignorują aż do momentu, gdy zobaczą, że strona konkurenta reaguje na kliknięcie natychmiast, a ich własna z opóźnieniem. To ranking factor, ale przede wszystkim user experience. Strona z INP 600ms frustruje users, którzy clickają multiple times — zwiększając INP further. Spirala. INP <200ms = smooth UX, retention, konwersje.
Audyt Core Web Vitals + INP — sprawdzimy obecną skuteczność i przygotujemy roadmap optymalizacji.
Chcesz osiągnąć podobne rezultaty? Zamów bezpłatną wycenę.