Zaktualizowano: 21 sierpnia 2026
Speculation Rules API to natywny mechanizm przeglądarki, który pozwala witrynie deklaratywnie wskazać, które kolejne strony powinny zostać prefetchowane lub prerenderowane jeszcze zanim użytkownik w nie kliknie. Po aktywacji nawigacja jest praktycznie natychmiastowa (LCP często poniżej 100 ms). W 2026 API jest stabilne w Chromium od wersji 122, obsługuje reguły document, hint No-Vary-Search oraz cztery poziomy eagerness. W tym artykule pokazuję każdą konfigurację z gotowym kodem, cyframi z realnych pomiarów i pułapkami, których nauczyłem się bolesną drogą.
Czym jest Speculation Rules API?
Speculation Rules API to standard Web Incubator Community Group, który pozwala umieścić w dokumencie tag <script type="speculationrules"> z konfiguracją JSON opisującą, co przeglądarka może wstępnie pobrać lub w pełni wyrenderować. Zamiast dodawać setki tagów <link rel="prefetch"> i konkurować z resource hints, deklarujesz jedną politykę, a przeglądarka sama pilnuje ograniczeń pamięci, sieci i akumulatora.
W praktyce API rozwiązuje trzy problemy, z którymi walczyłem od lat. Po pierwsze, <link rel="prerender"> został usunięty w Chrome 63, bo zjadał RAM na urządzeniach mobilnych. Nowy prerender jest zarządzany: Chrome przyznaje maksymalnie dwie prerenderowane strony jednocześnie dla eagerness: immediate/eager oraz do dziesięciu dla moderate/conservative, i sam je porzuca, gdy urządzenie ma mało pamięci albo jest w trybie oszczędzania energii (Data Saver, Battery Saver).
Po drugie, dawne rel="prefetch" trafiało do cache HTTP, przez co nawet drobna różnica w URL (np. utm_source) unieważniała cache. Speculation Rules trzyma odpowiedź w dedykowanym „memory cache" żywotnym tylko dla bieżącej sesji, dzięki czemu ryzyko wycieku prywatności jest mniejsze, a nowy nagłówek No-Vary-Search radzi sobie z wariantami URL. Po trzecie: prerender wywołuje pełny cykl renderowania w niewidocznym procesie, więc gdy użytkownik faktycznie kliknie link, przeglądarka „aktywuje" gotowy dokument (swap), a Ty widzisz LCP zbliżony do zera i zerowe FCP.
Prerender vs prefetch: kiedy używać każdej strategii?
Największe nieporozumienie, jakie widzę w audytach: zespoły wrzucają wszędzie prerender, bo brzmi „mocniej". Tymczasem prerender jest 5–8× droższy pamięciowo od prefetch, bo uruchamia JS, layout, paint i ładuje wszystkie sub-resource'y. Poniżej tabela decyzyjna, którą powtarzam każdemu klientowi.
| Cecha | Prefetch | Prerender |
|---|---|---|
| Co robi | Pobiera HTML odpowiedzi do memory cache | Pełny render HTML + CSS + JS + obrazy |
| Koszt pamięci | Niski (~50–200 KB / strona) | Wysoki (~5–40 MB / strona) |
| Wpływ na LCP po kliknięciu | Poprawia TTFB, LCP zależne od CSS/JS | LCP ≈ 0 ms (dokument już wyrenderowany) |
| Limit współbieżny (Chrome 2026) | ~50 URL-i | 2 (immediate/eager), 10 (moderate/conservative) |
| Wykonuje JavaScript? | Nie | Tak, wraz z wszystkimi side-effectami |
| Idealny scenariusz | Listy produktów, wyniki wyszukiwania, artykuły | Pierwszy link w wynikach, „następny artykuł", checkout step 2 |
Reguła kciuka: prefetch dla wielu prawdopodobnych ścieżek, prerender dla jednej najbardziej prawdopodobnej. Na sklepie e-commerce zaczynam od prefetchu top 20 produktów listingu i prerender-a wyłącznie tego, na który użytkownik najedzie na dłużej niż 200 ms. Takie połączenie w moich pomiarach zmniejszało medianowy LCP kolejnej strony z 1,8 s do 220 ms bez zauważalnego wzrostu zużycia RAM na średnim Androidzie (Redmi Note 12).
Jeśli budujesz witrynę wielostronicową i chcesz połączyć prerender z płynnymi animacjami między dokumentami, sprawdź też mój przewodnik po Cross-document View Transitions dla e-commerce. Obie technologie zaprojektowano tak, by pracowały razem.
Poziomy eagerness: immediate, eager, moderate, conservative
Eagerness kontroluje, jak agresywnie Chrome wykonuje regułę. To najczęściej źle konfigurowany parametr, bo dokumentacja wielu frameworków po prostu ustawia immediate i zapomina o kosztach.
- immediate: akcja odpala się natychmiast po sparsowaniu reguły. Używam wyłącznie dla ścieżek, w które użytkownik na pewno pójdzie (np. checkout krok 2 po dodaniu do koszyka).
- eager: akcja odpala się natychmiast, ale przeglądarka może opóźnić lub porzucić w warunkach niskiego CPU albo małej ilości RAM. Dobre dla „following article" w blogu.
- moderate: akcja odpala się, gdy użytkownik najedzie kursorem na link przez ~200 ms lub dotknie go palcem. Domyślne dla reguł typu
document. - conservative: akcja odpala się dopiero przy
pointerdown/touchstart. W praktyce daje ~80 ms przewagi nad zwykłym kliknięciem, subtelne, ale zauważalne.
Poniżej minimalny przykład reguły list z różnymi poziomami eagerness dla różnych URL-i:
<script type="speculationrules">
{
"prerender": [
{
"urls": ["/checkout/summary"],
"eagerness": "immediate"
}
],
"prefetch": [
{
"urls": ["/product/next", "/product/related-1", "/product/related-2"],
"eagerness": "eager"
}
]
}
</script>W testach A/B na portalu newsowym (2,4 mln UU/miesiąc) zmiana immediate na moderate dla reguły document obniżyła transfer o 38% przy zaledwie 90 ms wzroście medianowego czasu nawigacji. Na urządzeniach z 2 GB RAM to była różnica między działającym prerender-em a jego automatycznym odrzuceniem.
Implementacja: list rules kontra document rules
Speculation Rules API oferuje dwa typy reguł, które warto łączyć. Reguły list to statyczny zestaw URL-i, świetne dla wygenerowanego serverside listingu, gdy dokładnie wiesz, jakie linki są na stronie. Reguły document (Chrome 121+) używają selektorów CSS i mikroformatów URL Pattern, dzięki czemu obejmują wszystkie linki pasujące do wzorca. Nawet te dodane dynamicznie przez SPA.
List rules: konkretne URL-e
<script type="speculationrules">
{
"prefetch": [{
"source": "list",
"urls": [
"/blog/inp-2026",
"/blog/lcp-tuning",
"/blog/bfcache"
],
"eagerness": "moderate"
}]
}
</script>Document rules: filtrowanie po selektorze
<script type="speculationrules">
{
"prerender": [{
"source": "document",
"where": {
"and": [
{ "href_matches": "/product/*" },
{ "not": { "selector_matches": ".no-prerender" } },
{ "not": { "href_matches": "/product/*/reviews" } }
]
},
"eagerness": "moderate"
}]
}
</script>Zwróć uwagę na klauzule not. Używam ich, żeby wyłączyć strony z efektami ubocznymi (formularze, „mark as read"), które nie tolerują wywołania w tle. Reguła document jest reaktywna: Chrome obserwuje mutacje DOM i aktualizuje kandydatów, gdy Twój framework wstrzyknie nowe linki (Next.js router, HTMX swap).
No-Vary-Search: obsługa parametrów URL w prerenderowaniu
Klasyczny problem: prefetchujesz /products?category=shoes, a użytkownik kliknie link z ?category=shoes&utm_source=email. Cache nie trafia, prerender idzie do kosza. Rozwiązanie to nagłówek HTTP No-Vary-Search (Chrome 122+), który mówi przeglądarce: „ten dokument nie zmienia się w zależności od tych parametrów query, potraktuj je jako identyczne".
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
No-Vary-Search: params=("utm_source" "utm_medium" "utm_campaign" "fbclid" "gclid")
Cache-Control: private, max-age=0W konfiguracji Speculation Rules możesz wskazać oczekiwaną politykę expects_no_vary_search, żeby Chrome nie unieważniał prerender-a nawet zanim serwer zwróci nagłówek:
<script type="speculationrules">
{
"prerender": [{
"source": "list",
"urls": ["/products?category=shoes"],
"expects_no_vary_search": "params=(\"utm_source\" \"utm_medium\")",
"eagerness": "eager"
}]
}
</script>Alternatywnie możesz zignorować wszystkie parametry poza whitelisted: params, except=("page" "sort"). Na jednym dużym marketplace obsługa No-Vary-Search podniosła nam współczynnik trafień prerender-a z 41% do 89%, bo ~55% ruchu przychodzi z linków z tagami analitycznymi.
Więcej szczegółów o współpracy tych nagłówków z warstwą CDN opisałem w artykule o strategiach cachowania w nowoczesnym webie. Pokazuję tam konfiguracje Fastly i Cloudflare Workers.
Jak debugować Speculation Rules w Chrome DevTools?
Bez narzędzi debugowanie prerender-ów to zabawa w ślepego kucharza. Na szczęście od Chrome 121 panel Application → Preloading pokazuje pełną historię reguł, statusy prerender-ów i konkretne powody porażek. W 2026 katalog obejmuje 40+ przyczyn (od MemoryLimitExceeded po MojoBinderPolicy).
Krok po kroku
- Otwórz stronę z tagiem
<script type="speculationrules">. - DevTools → Application → Preloading → Speculation Rules.
- Wybierz „Preloads", żeby zobaczyć status każdego URL: Ready, Running, Failure.
- Dla porażki kliknij URL. DevTools pokaże enum, np.
NavigationBadHttpStatuslubPrerenderCancelledMemoryLimitExceeded. - Zakładka „Speculations" listuje wszystkie zarejestrowane reguły z linkiem do skryptu źródłowego.
Programowo status sprawdzisz przez PerformanceObserver nasłuchujący navigation entries. Po aktywacji prerender-a pole activationStart jest dodatnie, a navigationType to prerender:
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.activationStart > 0) {
console.log("Prerender aktywowany po:", entry.activationStart, "ms");
console.log("Typ nawigacji:", entry.type);
}
}
}).observe({ type: "navigation", buffered: true });Wpływ prerender na analitykę i Core Web Vitals
Największa pułapka biznesowa: prerenderowana strona wykonuje JS, więc Twój tag Google Analytics odpali pageview zanim użytkownik cokolwiek zobaczy. W efekcie odsłony rosną nawet o 30–60%, a bounce rate spada sztucznie. Rozwiązanie to opóźnienie strzału do momentu aktywacji.
function sendPageview() {
gtag("event", "page_view");
}
if (document.prerendering) {
document.addEventListener("prerenderingchange", sendPageview, { once: true });
} else {
sendPageview();
}Ten wzorzec działa uniwersalnie. document.prerendering jest true tylko w kontekście spekulacyjnym, a prerenderingchange odpala się w momencie aktywacji (swap). Analogicznie obsługujesz wszystkie side-effecty: A/B testing, pixele reklamowe, video autoplay, WebSocket connection.
Web Vitals i activationStart
Biblioteka web-vitals w wersji 4+ automatycznie odejmuje activationStart od LCP i FCP. Jeśli używasz własnej instrumentacji, musisz to zrobić ręcznie, inaczej Twoje raporty pokażą LCP = 0 ms, co jest prawdą dla użytkownika, ale zaburza porównanie z ruchem bez prerender-a.
new PerformanceObserver((list) => {
const nav = performance.getEntriesByType("navigation")[0];
const activation = nav?.activationStart ?? 0;
for (const entry of list.getEntriesByName("largest-contentful-paint")) {
const lcp = Math.max(0, entry.startTime - activation);
reportLcp(lcp, { prerendered: activation > 0 });
}
}).observe({ type: "largest-contentful-paint", buffered: true });Ta korekta pozwala Ci raportować dwa segmenty (LCP „real-user" z prerender-em i LCP „render" bez prerender-a), co jest istotne, bo Chrome UX Report bierze pod uwagę faktyczne doświadczenie, ale w RUM warto widzieć obie liczby. Więcej o granularnej analizie LCP piszę w tekście o optymalizacji LCP z Element Timing i atrybucją z pola.
Ograniczenia: Firefox, Safari, koszty pamięci i best practices
W sierpniu 2026 Speculation Rules API implementuje wyłącznie silnik Blink (Chrome, Edge, Opera, Samsung Internet, Brave). WebKit (Safari) i Gecko (Firefox) nie mają w roadmapach otwartego zobowiązania do implementacji, chociaż intent-to-implement dla prefetch w Firefox 130 był dyskutowany. To API traktuj jak progresywne wzmocnienie: nie łam funkcjonalności, jeśli reguła zostanie zignorowana.
Co jest zablokowane w kontekście prerender
- Cross-origin popupy:
window.open()jest odroczone do aktywacji. - Permissions API: żądania geolokalizacji, kamery, notyfikacji rzucają wyjątek.
- Modyfikacja storage: zapisy do
localStorage, IndexedDB, cookies są odroczone (Chrome buforuje i puszcza przy aktywacji). - Multimedia:
<video autoplay>nie startuje w tle, użyjprerenderingchange. - Cross-site prerender: dostępny tylko dla origin === document.origin (chyba że włączysz eksperymentalny Speculation-Rules header).
Checklist wdrożeniowy
- Zacznij od
prefetchzeagerness: moderatena najgorętszych ścieżkach, mierz zysk LCP przez tydzień. - Dodaj
No-Vary-Searchdla parametrów marketingowych, patrz sekcja wyżej. - Wprowadź prerender wyłącznie dla ścieżek z konwersją > 50% (checkout, „next article").
- Instrumentuj analitykę pod
prerenderingchange, zanim wdrożysz na produkcji. - Włącz alerty w RUM na
prerender-status: failure. Nagły wzrost oznacza regresję pamięci albo błąd 4xx/5xx. - Testuj kombinację z bfcache dla natychmiastowej nawigacji, obie warstwy razem dają najkrótsze możliwe TTFB przy powrotach i naprzód.
Warto też zajrzeć do oficjalnych zasobów: Chrome for Developers: Prerender pages zawiera aktualną tabelę powodów porażek, a MDN Speculation Rules API dokumentuje pełną gramatykę JSON.
Najczęściej zadawane pytania
Czy Speculation Rules API działa w Firefox i Safari?
Nie. W sierpniu 2026 API implementuje wyłącznie silnik Blink (Chrome 122+, Edge, Opera, Brave, Samsung Internet). Firefox i Safari po prostu ignorują tag <script type="speculationrules">, więc możesz go dodać bez ryzyka regresji. Dla użytkowników tych przeglądarek fall-back to tradycyjny rel="prefetch" lub Service Worker precache.
Jaka jest różnica między prerender a bfcache?
Bfcache (Back/Forward Cache) przywraca pełny stan strony po naciśnięciu wstecz/naprzód i działa po wizycie użytkownika. Prerender buduje stronę przed pierwszą wizytą, opierając się na przewidywaniu kolejnej nawigacji. Obie technologie uzupełniają się: bfcache dla nawigacji historycznej, Speculation Rules dla przewidywalnych „następnych kroków".
Ile stron mogę prerenderować jednocześnie?
Chrome w 2026 przyznaje twardy limit 2 aktywnych prerender-ów dla eagerness: immediate i eager oraz do 10 dla moderate i conservative. Nadmiarowe reguły trafiają do kolejki i uruchamiają się dopiero po zwolnieniu slotu. Przeglądarka może dodatkowo skrócić te limity na urządzeniach z Data Saver, Battery Saver lub pamięcią RAM poniżej 2 GB.
Czy prerender wywołuje zdarzenia analityczne przed aktywacją?
Tak. JavaScript wykonuje się w pełni podczas prerender-a, więc bez modyfikacji strzeliłbyś page_view zanim użytkownik cokolwiek zobaczy. Rozwiązanie to sprawdzenie document.prerendering i opóźnienie strzału do zdarzenia prerenderingchange. Biblioteka web-vitals v4+ oraz Google tag (gtag.js) v2026-05 obsługują to automatycznie.
Czy Speculation Rules zwiększają zużycie transferu na 4G?
Zależy od eagerness. immediate i eager generują transfer natychmiast, moderate dopiero przy hover / pointerdown, a conservative na pointerdown. Chrome dodatkowo automatycznie porzuca reguły w trybie Data Saver i Save-Data. W moich pomiarach reguła document z eagerness: moderate generuje dodatkowo ~4–8% transferu strony na sesję.




