SEO aplikacji jednostronicowych: dlaczego SPA nie pozycjonują się dobrze, jak naprawiają to SSR, generowanie statyczne i prerendering oraz jak sprawić, by aplikacja była czytelna dla robotów AI.

W skrócie
aplikacja jednostronicowa (SPA) ładuje jedną powłokę HTML i buduje każdy widok za pomocą JavaScriptu w przeglądarce. Google potrafi renderować JavaScript, ale renderowanie jest opóźnione i kruche, a roboty stojące za ChatGPT, Claude i Perplexity w ogóle go nie wykonują. Aby SPA mogła się pozycjonować i być cytowana, każdy jej widok potrzebuje własnego adresu URL, prawdziwego linku z href, unikalnego tytułu i opisu, poprawnego kodu statusu oraz przede wszystkim głównej treści obecnej w HTML wysyłanym przez serwer, dzięki renderowaniu po stronie serwera, generowaniu statycznemu lub prerenderingowi.
Chcesz dowiedzieć się więcej? Zapytaj
SEO aplikacji jednostronicowych to zestaw technik, dzięki którym aplikacja JavaScript zbudowana w React, Vue, Angular lub Svelte jest tak samo łatwa do indeksowania jak klasyczna witryna. Problem jest dobrze udokumentowany: Google wyjaśnia w podstawach SEO dla JavaScriptu, że przetwarza strony JavaScript w trzech fazach (indeksowanie, renderowanie, zapis do indeksu), a każda słabość SPA leży gdzieś w tym potoku. Ten poradnik skupia się na SPA. O witrynach JavaScript w ogóle przeczytaj w naszym poradniku o SEO dla JavaScriptu.
Tradycyjna witryna zwraca kompletny dokument HTML dla każdego adresu URL. SPA zwraca niemal ten sam dokument dla każdego adresu URL: pusty <div id="root">, kilka metatagów i duży pakiet JavaScriptu. Przeglądarka pobiera pakiet, wywołuje API, a potem rysuje stronę. Gdy odwiedzający kliknie link, JavaScript podmienia treść bez przeładowania.
Dla człowieka z szybkim telefonem efekt wydaje się natychmiastowy. Dla robota pierwsza odpowiedź to pusta powłoka: bez nagłówka, tekstu i linków. Wszystko zależy od tego, czy bot wykona JavaScript i kiedy. Ten jeden fakt tłumaczy większość problemów SEO w SPA:
/#/pricing), a część po # nigdy nie jest wysyłana do serwera, więc wszystkie widoki zlewają się w jeden adres.<title>, a jeśli router go nie aktualizuje, każda strona ma ten sam.href: przyciski i obsługa onClick nawigują użytkowników, ale nie dają robotom nic do podążania.Googlebot najpierw pobiera surowy HTML i odczytuje znalezione tam linki i dyrektywy. Strony zwracające status 200 trafiają następnie do kolejki Web Rendering Service, bezgłowego Chromium. Google stwierdza, że strona „może pozostać w tej kolejce przez kilka sekund, ale może to potrwać dłużej”. Po wyrenderowaniu powstały HTML jest ponownie analizowany pod kątem treści i linków, a potem indeksowany.
Cztery szczegóły z dokumentacji Google mają znaczenie dla SPA:
<a> z href. Linki wstrzyknięte przez JavaScript są w porządku, o ile mają ten format.pushState) zamiast tras z #. Wycofało swój stary schemat indeksowania AJAX (adresy z #!) w październiku 2015 roku.noindex w oryginalnym HTML wygrywa. Google może pominąć renderowanie, gdy zobaczy noindex, więc usunięcie go później przez JavaScript nie działa.Praktyczny wniosek: Google może zaindeksować SPA renderowaną po stronie klienta, ale dodajesz do każdej strony drugi krok, opóźnienie i punkt awarii. Przekroczenie czasu, zablokowane wywołanie API lub błąd JavaScriptu podczas renderowania pozostawia zaindeksowaną wersję pustą. Sprawdź, co widzi Google, narzędziem do kontroli adresu URL w Search Console, a jeśli strony pozostają poza indeksem, przeczytaj nasz poradnik o tym, jak działa indeksowanie w Google.
W większości nie. W badaniu opublikowanym w grudniu 2024 roku na ruchu własnej sieci Vercel i MERJ stwierdziły, że „żaden z głównych robotów AI obecnie nie renderuje JavaScriptu”: GPTBot, OAI-SearchBot i ChatGPT-User (OpenAI), ClaudeBot (Anthropic), PerplexityBot, Meta-ExternalAgent i Bytespider czytają tylko surowy HTML. Pobierają pliki JavaScript (około 11,5% żądań ChatGPT i 23,8% żądań Claude), ale ich nie uruchamiają. Wyjątkiem są Gemini, który korzysta z infrastruktury renderowania Google, oraz AppleBot, który używa robota opartego na przeglądarce.
W przypadku SPA renderowanej po stronie klienta oznacza to, że roboty AI zasilające ChatGPT, Claude i Perplexity widzą pustą stronę. Twój produkt może pozycjonować się w Google i mimo to być niewidoczny w odpowiedziach AI, bo asystent nie przeczytał z niego ani słowa. To samo dotyczy większości botów podglądu linków w sieciach społecznościowych i komunikatorach, które czytają tagi Open Graph w surowym HTML. Gdy treść jest już w HTML, sprawdź też, czy Twój robots.txt zezwala na roboty AI, na których Ci zależy.
Rozwiązaniem jest wysyłanie prawdziwego HTML w pierwszej odpowiedzi. Google nazywa dynamiczne renderowanie (serwowanie wstępnie wyrenderowanej wersji tylko botom) „obejściem, a nie zalecanym rozwiązaniem” w swojej dokumentacji dynamicznego renderowania i wskazuje zamiast tego renderowanie po stronie serwera, renderowanie statyczne lub hydrację. Poniższe definicje opierają się na opracowaniu Rendering on the Web z web.dev.
| Strategia | Jak działa | Treść w pierwszym HTML | Najlepsza do | Ograniczenia |
|---|---|---|---|---|
| Renderowanie po stronie klienta (CSR) | Przeglądarka buduje stronę z JavaScriptu i API | Nie | Paneli i stron za logowaniem | Opóźnione indeksowanie w Google, niewidoczne dla większości robotów AI |
| Renderowanie po stronie serwera (SSR) | Serwer renderuje HTML przy każdym żądaniu, a potem JavaScript go hydruje | Tak | Katalogów, listingów, treści często zmieniających się lub spersonalizowanych | Koszt serwera, wolniejszy czas odpowiedzi bez pamięci podręcznej |
| Generowanie statyczne (SSG) | HTML jest generowany w czasie budowania dla każdego adresu URL i serwowany z CDN | Tak | Stron marketingowych, bloga, dokumentacji, stron docelowych | Konieczność przebudowy przy zmianie treści (istnieją opcje przyrostowe) |
| Prerendering w czasie budowania | Bezgłowa przeglądarka zapisuje stan początkowy każdej trasy jako statyczny HTML | Tak | Istniejących SPA z ograniczoną liczbą tras publicznych | Dane zamrożone w czasie budowania, trasy trzeba wypisać |
| Dynamiczne renderowanie | Boty otrzymują wstępnie wyrenderowaną migawkę, użytkownicy SPA | Tak, tylko dla wymienionych botów | Tymczasowej poprawki starszej aplikacji | Oficjalnie obejście, koszt utrzymania, ryzyko serwowania botom innej treści |
Większość nowoczesnych frameworków pozwala mieszać strategie według trasy: statyczne dla stron marketingowych, renderowane na serwerze dla katalogu, renderowane po stronie klienta dla aplikacji po zalogowaniu. Taki układ hybrydowy daje robotom pełny HTML tam, gdzie pojawia się ruch z wyszukiwarki, i zachowuje doświadczenie SPA tam, gdzie wnosi wartość.
| Biblioteka | Framework lub funkcja zapewniająca HTML przy pierwszym ładowaniu |
|---|---|
| React | Next.js (komponenty serwerowe, SSR i generowanie statyczne), React Router w trybie frameworka, Gatsby |
| Vue | Nuxt (domyślnie renderowanie uniwersalne, dostępne generowanie statyczne) |
| Angular | Angular SSR (renderowanie na serwerze i prerendering w czasie budowania) |
| Svelte | SvelteKit (domyślnie renderowanie na serwerze, prerendering per trasa) |
| Dowolna z nich | Astro (domyślnie statyczny HTML, interaktywne wyspy ładowane tylko tam, gdzie trzeba) |
Osobnej wzmianki wymagają witryny generowane przez kreatory stron oparte na AI: wiele z nich eksportuje aplikację React renderowaną po stronie klienta. Jeśli zbudowałeś witrynę takim narzędziem, zobacz nasze uwagi o SEO i GEO w Lovable, zanim założysz, że Google i ChatGPT potrafią ją przeczytać.
Używaj History API (/pricing, nigdy /#/pricing), jednego adresu URL na jedną treść i tego samego adresu niezależnie od tego, czy odwiedzający przychodzi bezpośrednio, czy przez nawigację w aplikacji. Każdy adres URL musi ładować właściwą treść po otwarciu w nowej karcie, bo taki test wykonuje robot.
Każdy element nawigacji prowadzący do indeksowalnej strony powinien być <a href="/path">. Komponenty linków frameworków (Link, NuxtLink, routerLink) generują taki kod, a własne obsługi kliknięć na elementach div lub button nie. Dobre linki niosą też Twoją architekturę witryny: jeśli strona nie jest podlinkowana, roboty rzadko ją znajdują.
Każda trasa potrzebuje własnego tytułu, meta description, canonicala i tagów Open Graph, w miarę możliwości generowanych na serwerze. Nasza strona o metatagach wylicza, co ustawić. Utrzymuj jeden tag canonical: Google zaleca ustawienie go w HTML, a jeśli JavaScript go zmienia, wynik nie może zaprzeczać oryginałowi.
Brakujące produkty i usunięte artykuły nie mogą odpowiadać 200 z komunikatem o błędzie. Przy SSR zwracaj prawdziwy kod 404 lub 410 z serwera. W czystej SPA Google akceptuje dwa rozwiązania awaryjne: przekierowanie JavaScriptem na adres zwracający 404 lub dodanie metatagu robots noindex do widoku błędu.
Nagłówki, tekst, ceny, FAQ i dane strukturalne JSON-LD powinny znajdować się w odpowiedzi serwera, a nie ładować się po kliknięciu lub przewinięciu. Treść za kartami renderowanymi na żądanie lub za przyciskami „załaduj więcej” jest często pomijana.
Dziel pakiet według tras, odkładaj to, co niepotrzebne do pierwszego widoku, i unikaj ponownego renderowania całej strony podczas hydracji. Pamiętaj, że dane terenowe Chrome (CrUX) przypisują metryki nawigacji w aplikacji do adresu URL, który odwiedzający załadował jako pierwszy, więc testuj kluczowe szablony osobno.
Porównaj trzy wersje każdego kluczowego szablonu: surowy HTML (podgląd źródła lub pobranie strony narzędziem wiersza poleceń), HTML wyrenderowany przez Google (kontrola adresu URL, potem „Wyświetl przeszukaną stronę”) i stronę z wyłączonym JavaScriptem. Jeśli główny tekst pojawia się tylko w drugiej wersji, roboty AI go nie widzą. Nasz bezpłatny audyt dostępności dla robotów AI i kontroler indeksowalności wykonują te kontrole dla dowolnego adresu URL.
| Objaw | Prawdopodobna przyczyna | Rozwiązanie |
|---|---|---|
| Search Console pokazuje wiele stron „Przeskanowane, obecnie nie zindeksowane” | Pusty lub niemal identyczny HTML przed renderowaniem | SSR, SSG lub prerendering dla tras publicznych |
Każdy wynik wyszukiwania site: pokazuje ten sam tytuł | Tytuł nie jest aktualizowany dla trasy | Zarządzanie sekcją head na poziomie trasy po stronie serwera |
| Zaindeksowana jest tylko strona główna | Routing z hashem lub linki bez href | History API i prawdziwe linki <a> |
| Strony błędów pojawiają się w indeksie | Soft 404 (status 200 wszędzie) | 404 z serwera, przekierowanie JavaScriptem na adres 404 lub noindex |
| Pozycjonuje się w Google, ale nigdy nie jest cytowana przez ChatGPT ani Perplexity | Treść widoczna dopiero po wykonaniu JavaScriptu | Treść w pierwszej odpowiedzi HTML |
| Stara treść w widoku wyrenderowanym przez Google | Buforowane pliki JavaScript lub CSS | Nazwy plików z odciskiem |
Przez lata renderowanie po stronie klienta było ryzykiem do opanowania, bo Google w końcu renderowało JavaScript. Skoro część odkrywania odbywa się teraz w ChatGPT, Claude, Gemini i Perplexity, koszt się zmienił: strona istniejąca dopiero po wykonaniu JavaScriptu jest nieobecna w źródłach, które większość asystentów potrafi odczytać. Dostępność dla robotów w surowym HTML stała się pierwszym warunkiem optymalizacji pod silniki generatywne.
Gdy HTML jest kompletny, reszta podlega zwykłym zasadom: strony, które jasno odpowiadają na jedno pytanie, z faktami popartymi źródłami i danymi strukturalnymi, to te, które cytują asystenci. Funkcje optymalizacji GEO w Sorank pomagają pisać i publikować taką treść, a śledzenie wzmianek w AI pokazuje, czy ChatGPT, Claude i Gemini cytują Twoją markę po poprawce renderowania.
Kluczowa zasada SEO aplikacji jednostronicowych mieści się w jednym zdaniu: wszystko, co chcesz, by Google pozycjonowało, a AI cytowało, musi znajdować się w HTML wysyłanym przez serwer. Zostaw SPA do doświadczenia po zalogowaniu, renderuj strony publiczne na serwerze lub w czasie budowania, a potem testuj, co otrzymują boty, przed każdą wersją i po niej.
Aplikacja jednostronicowa nie jest karana przez Google, ale jej domyślna konfiguracja, renderowanie po stronie klienta z jedną powłoką HTML, sprawia, że indeksowanie jest wolniejsze i mniej niezawodne. Większość robotów AI nie wykonuje JavaScriptu, więc widzą pustą stronę. Dzięki renderowaniu po stronie serwera, generowaniu statycznemu lub prerenderingowi na trasach publicznych SPA może pozycjonować się tak dobrze jak każda klasyczna witryna.
Sam React jest neutralny: liczy się to, gdzie powstaje HTML. Aplikacja React renderowana tylko w przeglądarce ma zwykłe problemy SPA, a te same komponenty renderowane na serwerze w Next.js lub React Router w trybie frameworka dostarczają robotom kompletny HTML. Wybierz framework obsługujący renderowanie serwerowe lub statyczne dla stron, które chcesz zaindeksować.
Tylko jako środek tymczasowy. Google opisuje dynamiczne renderowanie jako obejście, a nie zalecane rozwiązanie, bo utrzymywanie osobnej wersji dla botów dodaje koszt i ryzyko. Renderowanie po stronie serwera, generowanie statyczne lub prerendering w czasie budowania dają ten sam HTML każdemu odwiedzającemu i są rozwiązaniami długoterminowymi.
WYPRÓBOWALI SORANK PRZED TOBĄ
