SEO for single page applications: hvorfor SPA'er ikke rangerer, hvordan SSR, statisk generering og prerendering løser det, og hvordan du gør din app læselig for AI-crawlere.

På denne side
Kort fortalt
En single page application (SPA) indlæser én HTML-skal og bygger hver visning med JavaScript i browseren. Google kan køre JavaScript, men gengivelsen sker forsinket og skrøbeligt, og crawlerne bag ChatGPT, Claude og Perplexity kører det slet ikke. For at rangere og blive citeret skal hver visning i en SPA have sin egen URL, et rigtigt link med en href, en unik titel og beskrivelse, en korrekt statuskode og frem for alt sit hovedindhold til stede i den HTML, serveren sender, via server-side rendering, statisk generering eller prerendering.
Vil du vide mere? Spørg
Hurtig quiz
Hvem skal rette den tekniske side af dit site?
Vores anbefaling til dig
Giv hver visning en ren URL, som crawlere kan læse er den rigtige løsning for dig
Nummer 1 i denne rangering, det bedste match for dine svar.
Vores anbefaling til dig
Brug rigtige links er den rigtige løsning for dig
Nummer 2 i denne rangering, det bedste match for dine svar.
Vores anbefaling til dig
Opdater titel, beskrivelse og canonical pr. rute er den rigtige løsning for dig
Nummer 3 i denne rangering, det bedste match for dine svar.
Vores anbefaling til dig
Returner ærlige statuskoder er den rigtige løsning for dig
Nummer 4 i denne rangering, det bedste match for dine svar.
SEO for single page applications er samlingen af teknikker, der gør en JavaScript-app bygget med React, Vue, Angular eller Svelte lige så nem at crawle som et klassisk website. Problemet er veldokumenteret: Google forklarer i sine grundlæggende principper for JavaScript-SEO, at det behandler JavaScript-sider i tre faser (crawling, gengivelse, indeksering), og hver svaghed i en SPA sidder et sted i den kæde. Denne guide fokuserer på SPA'er; til JavaScript-websites generelt, læs vores guide til JavaScript-SEO.
Et traditionelt website returnerer et komplet HTML-dokument for hver URL. En SPA returnerer næsten det samme dokument for alle URL'er: en tom <div id="root">, nogle få metatags og en stor JavaScript-pakke. Browseren henter pakken, kalder et API og tegner derefter siden. Når den besøgende klikker på et link, udskifter JavaScript indholdet uden at genindlæse siden.
For et menneske med en hurtig telefon virker resultatet øjeblikkeligt. For en crawler er det første svar en tom skal: ingen overskrift, ingen tekst, ingen links. Alt afhænger af, om robotten kører JavaScriptet, og hvornår. Det enkelte faktum forklarer de fleste SEO-problemer i SPA'er:
/#/pricing), og det, der står efter #, sendes aldrig til serveren, så alle visninger samles i én URL.<title>, og hvis routeren ikke opdaterer den, deler alle sider den.href: knapper og onClick-håndterere navigerer for brugerne, men giver crawlerne intet at følge.Googlebot henter først den rå HTML og læser de links og direktiver, den finder der. Sider, der returnerer statuskode 200, sættes derefter i kø til Web Rendering Service, en headless Chromium. Google oplyser, at en side „kan blive i denne kø i nogle få sekunder, men det kan tage længere“. Når siden er gengivet, analyseres den resulterende HTML igen for indhold og links, og derefter indekseres den.
Fire detaljer fra Googles dokumentation betyder noget for SPA'er:
<a>-elementer med en href er pålidelige links. Links indsat med JavaScript er i orden, så længe de følger det format.pushState) i stedet for #-ruter. Det udfasede sin gamle AJAX-crawlingordning (#!-URL'erne) i oktober 2015.noindex i den oprindelige HTML vinder. Google kan springe gengivelsen over, når det ser noindex, så det virker ikke at fjerne den senere med JavaScript.Den praktiske konsekvens: Google kan indeksere en klientgengivet SPA, men du tilføjer et ekstra trin, en forsinkelse og et fejlpunkt til hver side. En timeout, et blokeret API-kald eller en JavaScript-fejl under gengivelsen efterlader den indekserede version tom. Tjek, hvad Google ser, med URL-inspektionsværktøjet i Search Console, og læs vores guide til hvordan Googles indeksering virker, hvis sider bliver stående uden for indekset.
For det meste ikke. I et studie offentliggjort i december 2024 om trafikken i sit netværk fandt Vercel og MERJ, at „ingen af de største AI-crawlere i øjeblikket gengiver JavaScript“: GPTBot, OAI-SearchBot og ChatGPT-User (OpenAI), ClaudeBot (Anthropic), PerplexityBot, Meta-ExternalAgent og Bytespider læser alle kun den rå HTML. De henter dog JavaScript-filer (cirka 11.5% af ChatGPTs anmodninger og 23.8% af Claudes), men kører dem ikke. Undtagelserne er Gemini, som bygger på Googles gengivelsesinfrastruktur, og AppleBot, som bruger en browserbaseret crawler.
For en klientgengivet SPA betyder det, at AI-crawlerne, der forsyner ChatGPT, Claude og Perplexity, ser en tom side. Dit produkt kan rangere på Google og stadig være usynligt i AI-svar, fordi assistenten aldrig læste et ord af det. Det samme gælder for de fleste linkeksempelrobotter på sociale netværk og beskedapps, som læser Open Graph-tagsene i den rå HTML. Når indholdet står i HTML'en, skal du også kontrollere, at din robots.txt tillader de AI-crawlere, du ønsker.
Løsningen er at sende rigtig HTML i det første svar. Google kalder dynamisk gengivelse (hvor kun robotter får en forudgengivet version) „en midlertidig løsning og ikke en anbefalet løsning“ i sin dokumentation om dynamisk gengivelse og henviser i stedet til server-side rendering, statisk gengivelse eller hydrering. Definitionerne nedenfor følger referencen Rendering on the Web på web.dev.
| Strategi | Sådan virker den | Indhold i den første HTML | Bedst til | Begrænsninger |
|---|---|---|---|---|
| Klientgengivelse (CSR) | Browseren bygger siden ud fra JavaScript og et API | Nej | Dashboards og sider bag et login | Forsinket indeksering hos Google, usynlig for de fleste AI-crawlere |
| Server-side rendering (SSR) | Serveren gengiver HTML ved hver anmodning, derefter hydrerer JavaScript den | Ja | Kataloger, lister, indhold der ofte ændrer sig eller er personligt | Serveromkostninger, langsommere svartid uden cache |
| Statisk generering (SSG) | HTML genereres ved byggeriet for hver URL og leveres fra et CDN | Ja | Markedsføringssider, blog, dokumentation, landingssider | Der skal genbygges, når indholdet ændres (der findes trinvise muligheder) |
| Prerendering ved byggeriet | En headless browser gemmer den første tilstand af hver rute som statisk HTML | Ja | Eksisterende SPA'er med et begrænset antal offentlige ruter | Data fastfryses ved byggeriet, ruterne skal listes |
| Dynamisk gengivelse | Robotter får et forudgengivet øjebliksbillede, brugerne får SPA'en | Ja, kun for de listede robotter | Midlertidig løsning for en ældre app | Officielt en midlertidig løsning, vedligeholdelsesomkostninger, risiko for at vise robotterne andet indhold |
De fleste moderne frameworks lader dig blande strategier pr. rute: statisk for markedsføringssider, server-gengivet for kataloget, klientgengivet for den indloggede app. Denne hybride opsætning giver crawlerne fuld HTML der, hvor søgetrafikken opstår, og bevarer SPA-oplevelsen der, hvor den tilfører værdi.
| Bibliotek | Framework eller funktion til HTML ved første indlæsning |
|---|---|
| React | Next.js (serverkomponenter, SSR og statisk generering), React Router i framework-tilstand, Gatsby |
| Vue | Nuxt (universel gengivelse som standard, statisk generering tilgængelig) |
| Angular | Angular SSR (server-gengivelse og prerendering ved byggeriet) |
| Svelte | SvelteKit (server-gengivelse som standard, prerendering pr. rute) |
| Alle disse | Astro (statisk HTML som standard, interaktive øer indlæses kun, hvor det er nødvendigt) |
Sider genereret af AI-website-værktøjer fortjener en særlig omtale: mange eksporterer en klientgengivet React-app. Hvis du har bygget dit site med et sådant værktøj, så se vores noter om SEO og GEO for Lovable, før du antager, at Google og ChatGPT kan læse det.
Brug History API (/pricing, aldrig /#/pricing), én URL pr. stykke indhold, og den samme URL, uanset om den besøgende kommer direkte eller via navigation i appen. Hver URL skal indlæse det rigtige indhold, når den åbnes i en ny fane, og det er den test, en crawler udfører.
Hvert navigationselement, der fører til en side, der kan indekseres, bør være et <a href="/path">. Frameworkets linkkomponenter (Link, NuxtLink, routerLink) udsender denne markup; brugerdefinerede klikhåndterere på div- eller button-elementer gør ikke. Gode links bærer også din webstedsarkitektur: hvis en side ikke er linket, finder crawlere den sjældent.
Hver rute har brug for sin egen titel, metabeskrivelse, canonical og Open Graph-tags, genereret på serveren når det er muligt. Vores side om metatags lister, hvad du skal sætte. Hold dig til ét canonical-tag: Google anbefaler at sætte det i HTML'en, og hvis JavaScript ændrer det, må resultatet ikke modsige det oprindelige.
Manglende produkter og slettede artikler må ikke svare 200 med en fejlbesked. Med SSR skal serveren returnere en rigtig 404 eller 410. I en ren SPA accepterer Google to reserveløsninger: omdirigér med JavaScript til en URL, der returnerer 404, eller tilføj et robots-metatag med noindex til fejlvisningen.
Overskrifter, brødtekst, priser, FAQ og JSON-LD-data bør være i serverens svar, ikke indlæst efter et klik eller et rul. Indhold bag faner, der gengives på forespørgsel, eller bag knapper med „indlæs flere“, bliver ofte overset.
Del pakken op pr. rute, udskyd det, der ikke er nødvendigt for den første visning, og undgå at gengive hele siden igen under hydreringen. Bemærk, at Chrome-feltdata (CrUX) tilskriver målingerne for navigation i appen til den URL, den besøgende først indlæste, så test dine vigtigste skabeloner enkeltvis.
Sammenlign tre versioner af hver vigtig skabelon: den rå HTML (vis kildekoden eller hent siden med et kommandolinjeværktøj), Googles gengivne HTML (URL-inspektion, derefter „Se gennemgået side“) og siden med JavaScript slået fra. Hvis hovedteksten kun dukker op i den anden version, ser AI-crawlerne den ikke. Vores gratis revision af crawlbarhed for AI og tjek af indekserbarhed kører disse kontroller på enhver URL.
| Symptom | Sandsynlig årsag | Løsning |
|---|---|---|
| Search Console viser mange sider „Gennemgået, men ikke indekseret“ | Tom eller næsten identisk HTML før gengivelse | SSR, SSG eller prerendering for offentlige ruter |
Alle resultater i en site:-søgning viser den samme titel | Titlen opdateres ikke pr. rute | Styring af head pr. rute på serveren |
| Kun forsiden er indekseret | Hash-routing eller links uden href | History API og rigtige <a>-links |
| Fejlsider optræder i indekset | Bløde 404-fejl (statuskode 200 overalt) | 404 fra serveren, eller JavaScript-omdirigering til en 404-URL, eller noindex |
| Rangerer på Google, men citeres aldrig af ChatGPT eller Perplexity | Indhold der kun er synligt efter kørsel af JavaScript | Indhold i det første HTML-svar |
| Gammelt indhold vises i Googles gengivne visning | Cachede JavaScript- eller CSS-filer | Filnavne med fingeraftryk |
I årevis var klientgengivelse en håndterbar risiko, fordi Google til sidst gengav JavaScript. Nu hvor en del af opdagelsen foregår i ChatGPT, Claude, Gemini og Perplexity, har omkostningen ændret sig: en side, der kun findes, efter at JavaScript er kørt, er fraværende fra de kilder, de fleste assistenter kan læse. Crawlbarhed i den rå HTML er blevet den første betingelse for generativ motoroptimering.
Når HTML'en er komplet, følger resten de sædvanlige regler: sider, der besvarer ét spørgsmål tydeligt, med kildebelagte fakta og strukturerede data, er dem, assistenterne citerer. Sorank's GEO-optimering hjælper dig med at skrive og udgive indholdet, og sporing af AI-omtaler viser, om ChatGPT, Claude og Gemini citerer dit brand efter gengivelsesrettelsen.
Hovedreglen i SEO for single page applications kan siges i én sætning: det, du vil have Google til at rangere og AI til at citere, skal stå i den HTML, serveren sender. Behold SPA'en til den indloggede oplevelse, gengiv offentlige sider på serveren eller ved byggeriet, og test derefter, hvad robotterne modtager, før og efter hver udgivelse.
En single page application bliver ikke straffet af Google, men dens standardopsætning, klientgengivelse med én HTML-skal, gør indekseringen langsommere og mindre pålidelig. De fleste AI-crawlere kører ikke JavaScript, så de ser en tom side. Med server-side rendering, statisk generering eller prerendering på offentlige ruter kan en SPA rangere lige så godt som et klassisk website.
React i sig selv er neutral: det afgørende er, hvor HTML'en produceres. En React-app, der kun gengives i browseren, har de sædvanlige SPA-problemer, mens de samme komponenter gengivet på serveren med Next.js eller React Router i framework-tilstand leverer komplet HTML til crawlere. Vælg et framework, der understøtter server- eller statisk gengivelse for de sider, du vil have indekseret.
Kun som en midlertidig foranstaltning. Google beskriver dynamisk gengivelse som en midlertidig løsning og ikke en anbefalet løsning, fordi vedligeholdelse af en separat version til robotter giver omkostninger og risiko. Server-side rendering, statisk generering eller prerendering ved byggeriet giver samme HTML til alle besøgende og er de langsigtede løsninger.
DE PRØVEDE SORANK, FØR DU GJORDE DET
