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 też najmniej rozumiany.
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".
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?
1. Mobile devices are slower
iPhone 12 vs MacBook M2 — INP 5-10x wyższe na mobile. Devs testują na M2, mobile users sufferują.
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).
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
1. PageSpeed Insights
pagespeed.web.dev → mobile tab. Pokazuje:
- INP score
- Interactions causing high INP
- Recommendations
2. Chrome DevTools — Performance tab
- Open DevTools (F12)
- Performance 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://crux-compare.web.app/
Compare your INP vs competitors using real user data z Chrome.
Strategie optymalizacji INP
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.
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 — Performance 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
INP 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, conversions.
Audyt Core Web Vitals + INP — sprawdzimy obecną performance i przygotujemy roadmap optymalizacji.