TL;DR
INP (Interaction to Next Paint) mierzy opóźnienie od interakcji użytkownika (klik, tap, klawisz) do następnego malowania UI, nie tylko „czas do pierwszego handlera”. Od 2024 INP zastąpiło FID w Core Web Vitals; w 2026 Google nadal ocenia strony po progu dobry ≤ 200 ms, wymaga poprawy 200–500 ms, słaby > 500 ms (75. percentyl). Typowe zabójce w React/Next.js: ciężki JS na main thread, synchroniczne setState kaskady, duże listy bez wirtualizacji, third-party na kliknięciu, wolne Server Actions bez optimistic UI. Mierz CrUX + RUM; poprawiaj profilowaniem Performance. Aplikacja na DevStudioIT Cloud, telemetria eventów w Postgres (Branchly). To nie jest ogólny przewodnik LCP/CLS, skupiamy się wyłącznie na INP.
Dla kogo to jest
- Zespołów Next.js z żółtym/czerwonym INP w Search Console / PageSpeed
- Frontendowców React po migracji App Router / RSC
- Produktów z bogatymi formularzami, filtrami, menu mobile
- Tech leadów ustalających budget „po kliknięciu” na money pages
Fraza (SEO)
INP Interaction to Next Paint 2026, Core Web Vital INP React, poprawa INP Next.js, wolny klik main thread, web-vitals INP pomiar, optymalizacja interakcji React
Co dokładnie mierzy INP
INP bierze pod uwagę całą interakcję:
- Input delay, czekanie aż main thread będzie wolny
- Processing duration, Twój event handler + React commit
- Presentation delay, stylowanie + paint do następnej klatki
Raportowana wartość to zwykle najgorsza (lub wysoki percentyl) interakcja w sesji, nie średnia wszystkich kliknięć. Dlatego jeden wolny „Wyślij formularz” psuje INP nawet jeśli menu jest szybkie.
| Ocena (p75) | INP |
|---|---|
| Good | ≤ 200 ms |
| Needs improvement | 200–500 ms |
| Poor | > 500 ms |
Gdzie w React/Next.js INP najczęściej umiera
1. Za dużo pracy synchronicznej w handlerze
// Źle: ciężkie filtrowanie + setState w tym samym ticku co klik
function onFilter(value: string) {
const next = hugeCatalog.filter(/* CPU-heavy */);
setItems(next);
setFacetCounts(computeFacets(next));
analytics.track('filter', { value }); // sync XHR?
}Lepsze: startTransition dla niepilnych update’ów, odłóż analytics na requestIdleCallback / kolejkę, dziel pracę (scheduler).
2. Re-rendery całego drzewa
Klik w toggle w headerze przerenderowuje 200 kart produktów. Rozwiązania: izolacja stanu (bliżej liścia), kompozycja children, unikaj Contextów „na wszystko”, w RSC trzymaj interaktywność w małych Client Components.
3. Hydration i „klik zanim ready”
Użytkownik klika zanim hydracja skończy, kolejka eventów + ciężki hydrate = zły INP. Preferuj Server Components, mniejszy client bundle, loading.tsx / selective hydration.
4. Third-party na ścieżce interakcji
Chat widget, heatmap, A/B SDK ładujące się w handlerze CTA. Ładuj defer / po idle; nie blokuj first interaction na money page.
5. Formularze i Server Actions bez feedbacku
Długi round-trip bez optimistic UI sprawia wrażenie „zamarcia”; INP obejmuje czas do paint wskaźnika ładowania. Natychmiast pokaż pending state (useFormStatus / useTransition).
Pomiar: lab vs field
| Źródło | Co daje | Limit |
|---|---|---|
| Chrome DevTools Performance | dokładny call stack | nie jest p75 użytkowników |
| Lighthouse / PSI | lab estimate | inne urządzenie niż CrUX |
| CrUX / Search Console | real users p75 | wolna aktualizacja |
web-vitals RUM |
per URL / device | musisz zbierać sam |
import { onINP } from 'web-vitals';
onINP((metric) => {
// wyślij do swojego endpointu → Branchly
navigator.sendBeacon('/api/rum', JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
pathname: location.pathname,
}));
});Zapis RUM w Branchly pozwala korelować INP z konkretnym CTA (formularz vs menu), nie tylko „cała domena czerwona”.
Profilowanie: jak znaleźć winnego
- DevTools → Performance → nagraj klik problematyczny
- Szukaj długich Tasks (czerwone) między input a paint
- Rozwiń call stack: React
commit, Twój handler, third-party - React Profiler: które komponenty commit’ują przy tym kliknięciu
- Coverage / bundle: czy handler importuje ciężki moduł (lodash full, moment, chart)?
Na stagingu DevStudioIT Cloud testuj na throttled CPU 4–6×, desktop „instant” ukrywa mobile INP.
Konkretne poprawki (checklista kodu)
| Problem | Fix |
|---|---|
| Ciężki setState na klik | startTransition / useDeferredValue |
| Duża lista | wirtualizacja (@tanstack/react-virtual) |
| Globalny context | split context lub props drilling lokalnie |
| Sync analytics | beacon / idle queue |
| Duży client component | split + dynamic ssr: false tylko gdy konieczne |
| CSS thrash | unikaj layout read/write na przemian w handlerze |
| Obrazy w menu | priority tylko LCP; reszta lazy |
| Debounce input | dla search-as-you-type; dla przycisku nie delay’uj paint |
'use client';
import { useTransition, useState } from 'react';
export function FacetButton({ id, label }: { id: string; label: string }) {
const [active, setActive] = useState(false);
const [isPending, startTransition] = useTransition();
return (
<button
data-pending={isPending}
onClick={() => {
setActive((v) => !v); // pilny feedback UI
startTransition(() => {
applyFacet(id); // ciężkie filtrowanie listy
});
}}
>
{label}
</button>
);
}Natychmiastowy paint atrybutu / klasy = lepsze INP; ciężka praca w transition.
INP a SEO, co realnie się dzieje
Google używa field data (CrUX) dla CWV w rankingach jako jeden z wielu sygnałów. Słabe INP na kluczowych URL (homepage, oferta, kontakt) może pogarszać UX i pośrednio konwersję niezależnie od pozycji. Naprawiaj URL z ruchem i leadami, nie każdą podstronę bloga z 12 sesjami/miesiąc.
FAQ
Czy INP dotyczy tylko mobile?
Raporty CrUX rozdzielają mobile/desktop. Mobile zwykle gorsze, priorytet napraw. Desktop też bywa słaby przy ciężkich dashboardach.
Czy loading.tsx poprawia INP?
Pomaga UX nawigacji (Suspense), ale nie zastępuje optymalizacji handlerów na tej samej stronie. INP = interakcje, nie tylko route transitions.
Czy React Compiler / memo wszystko naprawi?
Zmniejsza zbędne re-rendery, ale nie usuwa 200 ms synchronicznego JSON.parse w onClick. Najpierw skróć pracę w handlerze.
FID vs INP, muszę jeszcze patrzeć na FID?
Dla CWV 2026 fokus to INP. FID jest historyczne; narzędzia mogą jeszcze pokazywać FID, nie optymalizuj tylko pod FID.
Chcesz obniżyć INP na produkcji?
- Skontaktuj się z nami, profilowanie interakcji, refaktor Client Components i RUM pod Next.js
- Lighthouse 100 w Next.js, szerszy performance (gdy LCP też boli)
- Performance budget w zespole, progi i ownership
O autorze
Budujemy szybkie strony WWW, aplikacje web/mobile, chatboty AI i hosting — z naciskiem na SEO i konwersję.
Przydatne linki
Od teorii do produkcji — Branchly, hosting i realizacje.
