SPA SEO Rehberi

Tek sayfalı uygulamaları (React Router, Vue Router, Angular Router) taranabilir ve dizine eklenebilir kılmanın yollarını açıklar: app-shell ve soft-404 sorunları, History API ile hash yönlendirmesi arasındaki fark, SSR/prerendering ile rota başına HTML, rota başına canonical ve title değerleri ve istemci tarafı rotalar için sitemap üretimi.

İlk yayın tarihi: 3 Tem 2026 · Son güncelleme: 8 Ağu 2026 · Advanced
Diller

Tek sayfalı bir uygulama, sunucudan yeni bir sayfa istemek yerine tek bir belge yükleyen ve görünümleri JavaScript ile değiştiren uygulamadır. Birçok SPA bunu “app shell” ile uygular — sunucu her rota için gerçek HTML yerine neredeyse boş bir kabuk döndürür — ancak bu her SPA için geçerli bir kural değildir; varsaymadan önce her rotaya doğrudan yapılan isteğin ne döndürdüğünü kontrol edin. Çıplak app-shell kurulumunun sorun olduğu yerde çözümün iki bağımsız yarısı vardır: adreslenebilirlik (hash/#! parçaları yerine History API ile her görünüm için gerçek bir URL) ve içerik kullanılabilirliği (SSR, prerendering/SSG veya meta-framework ile bu URL’lerin istek üzerine benzersiz HTML döndürmesi). Ayrıca her rotanın title, canonical ve robots durumunu doğrudan girişte ve oluşturma sonrasında doğrulayın; soft-not-found durumlarını ele alın (yönlendiriciler “not found” görünümleri için 200 durumunu koruma eğilimindedir — kendisi not-found döndüren bir URL’ye yönlendirin veya oluşturulmuş noindex ekleyin) ve sitemap’teki her rotanın gerçek, dizine eklenebilir HTML’ye çözüldüğünü doğrulayın.

TL;DR — Bir SPA’nın temel SEO riski, soyut anlamda JavaScript değil, istemci tarafı yönlendirmenin kullanıcının gördüğünü sunucunun döndüreceği şeyi değiştirmeden değiştirmesidir. Çözümün sürekli birbirine karıştırılan iki bağımsız yarısı vardır: adreslenebilirlik (History API, rota başına benzersiz URL’ler ve #! parçalarının olmaması) ve içerik kullanılabilirliği (SSR, prerendering/SSG veya meta-framework). Yalnızca ilkini yaparsanız tümü aynı kabuğu oluşturan düzenli bir sitemap elde edersiniz. Her ikisinin üzerine her rotanın oluşturulmuş DOM’da kendi canonical/title/description değerleri olmalı, 200 döndüren soft-not-found durumları ele alınmalı ve sitemap’teki her rota bağımsız olarak gerçek HTML’ye çözümlenmelidir.

SPA SEO gerçekte nedir

SPA bir uygulama mimarisidir; garanti edilmiş bir SEO başarısızlık durumu değildir. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: MDN: Single-page application Sunucu tarafı oluşturma, prerendering veya dikkatle uygulanmış istemci tarafı oluşturma içeriği görünür kılabilir, ancak hiçbiri dizine eklenmeyi garanti etmez. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics

Bu, özellikle tek sayfalı uygulamaların — React Router, Vue Router veya Angular Router ile istemci tarafı yönlendirmenin — derinlemesine incelenmesidir; ilk yüklemeden sonra sunucu bir daha tam sayfa göndermez. Daha geniş JavaScript SEO rehberinin (parite, lazy-loading, infinite scroll ve JS oluşturmayı genel olarak ele alır) ve React, Next.js, Nuxt, Angular, Vue, Svelte ve Astro için framework rehberlerinin yanında yer alır. Burada yalnızca yönlendirme katmanına ve bunun tarama ile dizine eklemeyi nasıl etkilediğine odaklanıyorum.

Çıplak istemci tarafı yönlendirmeli SPA’lar SEO’da neden başarısız olur

Bir URL, bir HTML yanıtı — app-shell sorunu

Google bu arıza biçimini açıkça tanımlar: “Some JavaScript sites may use the app shell model where the initial HTML does not contain the actual content and Google needs to execute JavaScript before being able to see the actual page content.” (Türkçesi: “Bazı JavaScript siteleri, ilk HTML’in gerçek içeriği içermediği ve Google’ın gerçek sayfa içeriğini görebilmek için JavaScript çalıştırması gereken app shell modelini kullanabilir.”) Çıplak bir SPA’de “app shell”, sunucunun döndürdüğü tek şeydir. /products için yeni bir istek yaptığınızda /about için alacağınız aynı neredeyse boş belgeyi alırsınız. İçerik ancak tarayıcı JavaScript’inizi çalıştırıp yönlendiriciniz ne göstereceğine karar verdikten sonra ayrışır.

Sorun tek cümlede budur: istemci tarafı yönlendirme, kullanıcının gördüğünü sunucunun döndüreceği şeyi değiştirmeden değiştirir. Sonraki her şey — soft-not-found durumları, yinelenen içerik, eksik başlıklar — bunun belirtisidir.

Sunucu hangi “sayfanın” istendiğini hiç görmez (hash yönlendirmesi neden başarısız olur)

Eski SPA’lar görünümleri URL parçalarından yüklerdi — example.com/#/products. Google’ın tam ifadesi şöyledir: “A SPA may use URL fragments (for example https://example.com/#/products) for loading different views.” (Türkçesi: “Bir SPA, farklı görünümleri yüklemek için URL parçalarını kullanabilir.”) Bunun başarısız olmasının belirli ve mekanik bir nedeni vardır: tarayıcılar parçayı (# sonrasındaki her şeyi) HTTP isteğinde sunucuya asla göndermez. Sunucu hangi “sayfanın” istendiğini bilemez; bu nedenle farklı içerik veya farklı durum kodu döndüremez. Bir URL’yi bir kez getiren tarayıcı, parça ne olursa olsun aynı HTML’i alır.

Google’ın 2009 tarihli AJAX tarama şemasını Ekim 2015’te resmen kullanımdan kaldırmasının nedeni de budur: “In short: We are no longer recommending the AJAX crawling proposal we made back in 2009.” (Türkçesi: “Kısacası, 2009’da yaptığımız AJAX tarama teklifini artık önermiyoruz.”) Eski _escaped_fragment_ çözümü, parça rotalarını istek üzerine önceden oluşturmaya izin veriyordu; ancak yönlendirme sorununu çözmek yerine etrafından dolaşıyordu. Google’ın bunun yerine önerdiği yöntem aşağıda ele alınan History API’dir.

Soft-not-found durumları — istemci tarafı yönlendiriciler her şey için 200’ü korur

This one is close to inevitable in a bare SPA. Client-side routers, by design, keep the original page’s 200 status for every virtual navigation — including “not found” states. Google flags it explicitly: “In a single-page application (SPA), this can be especially difficult. To prevent error pages from being indexed, you can use one or both of the following strategies.” And the why: “When a SPA is using client-side JavaScript to handle errors they often report a 200 HTTP status code instead of the appropriate status code.”

Sonuç, ince 200 sayfalar olarak dizine eklenen boş veya hata görünümleridir. Google burada tam olarak iki strateji belgeler: sunucusu gerçek bir 404/hata durumu döndüren bir URL’ye yönlendirin (veya tam istek yapın) ya da hata görünümüne JavaScript ile noindex etiketi ekleyin. İkinci seçeneğe dikkat edin: noindex uygulama rotanın geçersiz olduğuna karar vermeden önceki ilk boyamada mevcutsa Google’ın sayfayı oluşturmayı atlamasına yol açabilir. Bu nedenle yalnızca sonradan oluşan DOM’da ne göründüğünü değil, herhangi bir JS çalışmadan önce doğrudan isteğin ne döndürdüğünü doğrulayın. Evidence for this claim For a client-rendered not-found view, Google documents two approaches: redirect to a URL whose server returns a 404 response, or add noindex with JavaScript; an initial noindex can cause rendering to be skipped, so raw and rendered directives require separate testing. Scope: SPAs Confidence: high · Verified: Fix Search-related JavaScript problems

Paylaşılan kabuk kopyaları — olası neden, otomatik teşhis değil

İkinci ve daha sinsi bir arıza biçimi vardır: farklı rotalar, aynı paylaşılan header/nav/footer şablonuna indirgendikleri için birbirinin kopyası olarak dizine eklenebilir. Gary Illyes bunun bir yolunu şöyle anlattı: “I have a bunch of emails in my inbox where the issue is that the centerpiece took forever to load, so rendering timed out (my most likely explanation) and we were left with a bunch of pages that only had the boilerplate. With only the boilerplate, those pages are dups.” (Türkçesi: “Gelen kutumda, sorunun merkez içeriğin yüklenmesinin çok uzun sürmesi ve oluşturmanın zaman aşımına uğraması (en olası açıklamam) olduğunu belirten birçok e-posta var; sonuçta yalnızca şablon içeriği olan bir sürü sayfa kaldı. Yalnızca şablon varken bu sayfalar kopyadır.”) Çözümü de şuydu: “Try to restructure the js calls such that the content (including marginal boilerplate) loads first.” (Türkçesi: “JS çağrılarını, içeriğin (ikincil şablon içeriği dahil) önce yükleneceği şekilde yeniden yapılandırmayı deneyin.”) (Otomatik doğrulamaya direnen bir LinkedIn gönderisi üzerinden aktarıldı; yüksek güvenli ikincil kaynak olarak ele alın.)

Illyes’in bunu doğrulanmış bir teşhis olarak değil, “en olası açıklamam” şeklinde çerçevelediğine dikkat edin — bunu kelimesi kelimesine ciddiye almak gerekir. “Render timeout” tek başına belirtilerden teşhis edilemez; bir rotanın yinelenen içerik sorununu özellikle zaman aşımına bağlamadan önce istek düzeyinde kanıta (doğrudan getirinin gerçekten ne döndürdüğüne), oluşturulmuş çıktı kanıtına (merkez içeriğin oluşturma sonrasında mevcut olup olmadığına) ve Search Console kanıtına (yinelenen/dizine ekleme sinyallerine) ihtiyacınız vardır. Ayrıca tasarım yapılacak sabit, yayımlanmış bir zaman aşımı yoktur — Google’ın temel belgesi bir sayfanın “may stay on this queue for a few seconds, but it can take longer than that,” (Türkçesi: “birkaç saniye bu kuyrukta kalabilir, ancak daha uzun sürebilir”) kuyrukta kalabileceğini söyler; bir sayı taahhüt etmez. Varsayılan bir oluşturma kuyruğu süresine göre plan yapmayın; oluşturmanın ne kadar sürdüğünden bağımsız olarak birincil içeriğin olabildiğince erken yüklenmesini sağlayın.

Çözüm: her rota için gerçek HTML elde edin

Tam çözüm, insanların sürekli birbirine karıştırdığı iki bağımsız parçaya sahiptir:

  1. URL adreslenebilirliği — History API, rota başına benzersiz URL’ler, parça yok.
  2. İçerik kullanılabilirliği — SSR, statik prerendering/SSG veya bir meta-framework.

Yalnızca #1’i yaparsanız, hâlâ aynı boş kabuğu döndüren temiz ve paylaşılabilir URL’ler elde edersiniz. Gerçekten dizine eklenmesini istediğiniz bir rota için ikisine de ihtiyacınız vardır.

Bu, her yere SSR eklemeye ilişkin evrensel bir zorunluluk da değildir. SSR ve prerendering, tarayıcının JavaScript’inizi başarıyla çalıştırmasına olan bağımlılığınızı azaltır — site teknik olarak SPA olduğu anda zorunlu hale gelmezler. Belirli bir rota için mimari seçmeden önce üç şeyi kontrol edin: bu rotanın gerçekten sıralanması gerekip gerekmediği (dahili yönetim panelinin gerekmez), JS’siz doğrudan isteğin zaten ne döndürdüğü (bazı kurulumlar anlamlı HTML’i zaten gönderir) ve hangi tarayıcılara hizmet etmeniz gerektiği (Google JS’i oldukça güvenilir biçimde oluşturur; Bing ve çoğu AI tarayıcısı daha az güvenilirdir — aşağıya bakın). Bu kontrolleri zaten geçen CSR, site SPA olduğu için SSR’ye dönüştürülmek zorunda değildir.

Sunucu tarafı oluşturma (SSR)

Sunucu, her istek için uygulamanızı çalıştırır ve bu rota için tamamen oluşturulmuş HTML’i döndürür; ardından istemci onu canlı bir SPA’ye “hydrate” eder. Bu, tarayıcının ilk getirişinde eksiksiz içerik aldığı ve JS çalıştırması gerekmediği için en sağlam seçenektir.

Statik prerendering / SSG

İstek başına oluşturmak yerine deploy sırasında her rotanın HTML’ini önceden derlersiniz. Kullanıcıya göre değişmeyen içerikler için idealdir. Kendi JavaScript SEO yazılarımda da söylediğim gibi, her tür SSR, statik oluşturma ve prerendering kurulumu arama motorları için uygundur — kaçınılması gereken şey içeriği yalnızca istemci tarafı oluşturmanın arkasında bırakmaktır.

Veya: kendiniz yazmayın — bir meta-framework kullanın

Yeni bir proje için dürüst önerim, React-Router-only veya Vue-Router-only istemci tarafı yönlendirmeyi baştan kendiniz yazmamanızdır. Next.js, Nuxt, SSR paketiyle Angular, SvelteKit ve Remix gibi bir meta-framework, SSR/SSG’yi ve rota tabanlı meta verileri kutudan çıktığı haliyle sunar; böylece bu sorun kategorisinin tamamını aşar. (Bu sitede bunların her biri için ayrı derinlemesine rehber vardır.) Diğer taraf konusunda dürüst olun: mevcut, elle yazılmış bir SPA’ye SSR sonradan eklemek gerçek mühendislik işidir — bir yapılandırma düğmesi değil, bir geçiş projesidir.

Hedef değil, geçici çözüm olarak dinamik oluşturma

Tarayıcılara ayrı oluşturulmuş bir HTML anlık görüntüsü sunabilirsiniz (dynamic rendering). Hem Google hem Bing bunu kabul eder — Bing, “recommend[s] dynamic rendering as a great alternative for websites relying heavily on JavaScript” (Türkçesi: “dynamic rendering’ı JavaScript’e yoğun biçimde dayanan web siteleri için harika bir alternatif olarak önerir”) (Bing’in 2018 blogundan aktarıldı; aşağıdaki iki kısa bingbot-yeteneği alıntısı doğrudan doğrulanmıştır, bu uzun ifade bağımsız olarak tekrar kontrol edilmemiştir) — ancak Google bunun bir geçici çözüm olduğunu açıkça söyler: “Dynamic rendering was a workaround and not a long-term solution… Instead, we recommend that you use server-side rendering, static rendering, or hydration as a solution.” (Türkçesi: “Dynamic rendering bir geçici çözümdü, uzun vadeli bir çözüm değildi… Bunun yerine sunucu tarafı oluşturma, statik oluşturma veya hydration kullanmanızı öneririz.”) (Google’ın dynamic-rendering belgesinden aktarıldı; ifade bu sitenin daha geniş JavaScript SEO rehberinde zaten alıntılanan metinle örtüşür.) Bu bir köprüdür, mimari değildir.

History API ile hash yönlendirmesi (#!)

İki değil, beş durum

Bir SPA rotasını test etmek kafa karıştırır; çünkü “çalışıyor mu” aslında ayrı ayrı doğrulanabilen beş farklı duruma uzanır:

DurumNedir?
Sunucu yanıtıJS’siz, yeni bir HTTP isteğinin URL’den gerçekten aldığı baytlar.
Oluşturulmuş DOMBir tarayıcının (veya Googlebot oluşturucusunun), sunucu yanıtı üzerinde JavaScript çalıştırdıktan sonra oluşturduğu şey.
Arama işlemesiGoogle’ın sunucu yanıtını ayrı ayrı taraması, daha sonra sayfayı oluşturması ve ikisine dayanarak dizine eklemesi.
Tarayıcıda tam belge gezinmesiBir URL’ye yapılan gerçek yeni HTTP isteği — sunucu yanıtını veya durum kodunu değiştirebilen tek durum.
Tarayıcıda soft navigationGörünen URL’yi, tarayıcı geçmişini ve ekrandaki arayüzü değiştiren bir History API geçişi (pushState/replaceState).

Herkesin birbirine karıştırdığı nokta şudur: soft navigation URL’yi ve arayüzü değiştirir, ancak tek başına yeni bir HTTP yanıtı veya durum kodu oluşturmaz — bu yalnızca tam gezinmede (veya curl gibi eşdeğer doğrudan istekte) gerçekleşir. Ana sayfadan uygulamaya tıklayarak bir rotayı test etmek soft navigation’ı; URL’yi doğrudan istemek sunucu yanıtını test eder. İkisi de önemlidir ve birbiriyle uyuşmayabilir.

History API size ne verir

Google’ın önerisi açıktır: “We recommend using the History API to load different content based on the URL in a SPA.” (Türkçesi: “Bir SPA’de URL’ye göre farklı içerik yüklemek için History API’yi kullanmanızı öneririz.”) (Canlı belgede “History API” bir bağlantı olduğundan bu deep link giriş cümlesini hedefler.) History API (pushState/replaceState), tam yükleme olmadan yönlendiricinizin görünen URL’yi gerçek ve yer imlerine eklenebilir bir yola — /products, /#/products değil — değiştirmesini sağlar. Bu, adreslenebilirlik yarısını düzeltir: artık her görünümün, sunucunun farklı yanıt verebileceği bir URL’si vardır.

Parça/hash URL’leri sunucuya — ve Google’a — neden görünmez

Parça sunucuya asla ulaşmadığı için (yukarıya bakın), History API her rotaya sunucunun gerçekten hizmet verebileceği bir URL vermenin tek yoludur. Google, temel belgesinde bunun alt sınırını şöyle çizer: “don’t use fragments to load different page content. The following example is a bad practice, because Googlebot can’t reliably resolve the URLs.” (Türkçesi: “Farklı sayfa içerikleri yüklemek için parçaları kullanmayın. Aşağıdaki örnek kötü bir uygulamadır; çünkü Googlebot URL’leri güvenilir biçimde çözemez.”) Bu, başka yerde yazdığım önerinin aynısıdır — /products gibi hash URL’leri değil, /#/products gibi normal görünen URL’leri kullanın; Google hash olanları güvenilir biçimde dizine ekleyemez.

2015’teki kullanımdan kaldırma, kısaca

Hash-bang (#!) dönemi Google’ın 2015 tarihli gönderisiyle sona erdi: “Times have changed. Today, as long as you’re not blocking Googlebot from crawling your JavaScript or CSS files, we are generally able to render and understand your web pages like modern browsers,” (Türkçesi: “Zaman değişti. Bugün, Googlebot’un JavaScript veya CSS dosyalarınızı taramasını engellemediğiniz sürece web sayfalarınızı genellikle modern tarayıcılar gibi oluşturup anlayabiliyoruz.”) ve “you can use the History API pushState() to ensure accessibility for a wider range of browsers (and our systems).” (Türkçesi: “Daha geniş bir tarayıcı yelpazesi (ve sistemlerimiz) için erişilebilirliği sağlamak üzere History API pushState() kullanabilirsiniz.”) Korunması gereken bir nüans şudur: Google eski hash-bang sitelerini anında dizinden çıkarmadı — “we’ll generally crawl, render, and index the \u0060#!\u0060 URLs” (Türkçesi: “\u0060#!\u0060 URL’lerini genellikle tarayacak, oluşturacak ve dizine ekleyeceğiz.”) — ancak “hâlâ deneyebiliriz”, “bunu hâlâ yapmalısınız” demek değildir.

Her rotayı bağımsız olarak dizine eklenebilir kılma

Temiz URL’ler ve gerçek HTML taranmanızı sağlar. Doğru biçimde dizine eklenmek için her rotanın kendi sinyallerine ihtiyacı vardır.

Rota başına canonical etiketleri — “en kısıtlayıcı yönerge” tuzağı

Her rotanın oluşturulmuş DOM’da kendi rel=canonical değerine sahip olması gerekir. Tuzak şudur: ham HTML kabuğunda bir placeholder canonical (veya noindex) gönderilir ve JavaScript’in daha sonra üzerine yazması beklenirse çakışma oluşabilir. Google ham ve oluşturulmuş sürümler arasındaki çakışmaları daha kısıtlayıcı sinyali alarak çözer — daha önce ifade ettiğim gibi Google, bir sayfanın HTML’i ile oluşturulmuş sürümü arasındaki en kısıtlayıcı ifadeleri seçer. Kabuğa gömülmüş başıboş bir noindex veya yanlış canonical, JS’iniz bunu “düzelttikten” sonra bile tüm rotayı sessizce bastırabilir.

JavaScript ile rota başına title ve meta description

Bunları JS ile ayarlamak uygundur — Google bunu doğrudan söyler: “You can use JavaScript to set or change the meta description as well as the <title> element.” (Türkçesi: “meta description’ın yanı sıra <title> öğesini ayarlamak veya değiştirmek için JavaScript kullanabilirsiniz.”) Gereklilik, bunların kısa süreliğine görünmesi değil, Google’ın değerlendirdiği oluşturulmuş DOM’a yerleşmesidir. Her sayfaya rota değiştiğinde güncellenen kendi başlığını ve açıklamasını verin.

Rotalar arasında gerçek <a href> bağlantıları

Rotalar arası bağlantılarınızı href üzerindeki tıklama işleyicileriyle değil, <div> öznitelikli gerçek anchor’larla kurun. Google URL’leri href değerlerini çıkararak keşfeder; router üzerinden yönlendiren bir <div onClick>, tarayıcının bağlantı çıkarma işlemine görünmez. Bu gezinmeler arasında içeriği taşımak için istemci tarafı durumuna da güvenmeyin — Google’ın oluşturucusu “does not retain state across page loads: Local Storage and Session Storage data are cleared across page loads. HTTP Cookies are cleared across page loads.” (Türkçesi: “Sayfa yüklemeleri arasında durumu korumaz: Local Storage ve Session Storage verileri sayfa yüklemeleri arasında temizlenir. HTTP çerezleri sayfa yüklemeleri arasında temizlenir.”)

SPA rotaları için sitemap üretimi

Özel bir “SPA sitemap” biçimi yok — mesele muhasebedir

SPA’lar için sitemap protokolü değişmez. Asıl iş, listelediğiniz her rotanın bağımsız olarak gerçek, benzersiz ve oluşturulmuş HTML’e çözülmesini sağlamaktır. İstemci tarafındaki 500 rota aynı kabuğu döndürüyorsa bu rotaların sitemap’i değersizdir. Dolayısıyla sitemap, oluşturma stratejinizin alt ürünüdür; onun yerine geçmez.

Dinamik/parametreli rotaları ele alma (/product/:id)

Parametreli rotaları olan uygulamalarda listeyi elle sürdüremezsiniz. Sitemap oluşturucusu, uygulamanın kullandığı veri kaynağına karşı çalışmalıdır — her id’yi sıralayan bir build script’i veya sunucu endpoint’i — böylece sitemap ile uygulama birbirinden kopmaz. Sıralanan URL’ler ancak SSR’den veya prerendering’den geçtiğinde listelenmeye değerdir.

Sitemap’i sunucunun çözebildiği şeyle senkron tutma

İçeriğinizin kaynağına bağlı olarak sitemap’i derleme sırasında veya içerik kaynağınıza bağlı bir takvimle yeniden oluşturun. Sitemap’te 200 döndüren (veya daha kötüsü soft-not-found olan) bir rota bulunması istemediğiniz bir tarama bütçesi ve kalite sinyalidir.

Google’ın gerçekte ne gördüğünü test etme

Tek bir URL’yi noktasal olarak kontrol etmeyin. SPA sorununun özü, rotaların tarayıcıda farklılaşıp ağ üzerinde farklılaşmayabilmesidir; bu nedenle birden çok rotayı ham HTML düzeyinde test edin:

  • Her rota için ham HTML’i getirin; uygun olduğunda bir Googlebot user-agent’ı ile curl kullanın ve içeriğin paylaşılan kabuk değil, URL başına benzersiz olduğunu doğrulayın.
  • Search Console’da URL Inspection — birkaç rotanın taranan/oluşturulan HTML’ini karşılaştırın ve rota başına title, description ve canonical değerlerinin bulunduğunu doğrulayın.
  • Hata rotalarının doğru sinyali döndürdüğünü doğrulayın — “bulunamadı” görünümü ya gerçek bir hata durumuna yönlenmeli ya da oluşturulmuş DOM’da noindex taşımalıdır.

SPA SEO hakkında yaygın mitler

  • “Google SPA’leri hiç dizine ekleyemez.” Güncelliğini yitirmiştir. Google evergreen Chromium çalıştırır ve genellikle SPA içeriğini oluşturur. Gerçek riskler belirgindir: soft-not-found durumları, hash routing, oluşturma zaman aşımları ve Google dışı tarayıcılar (Bing daha az güvenilir, çoğu AI tarayıcısı hiç oluşturmaz).
  • “History API eklemek SPA SEO’sunu düzeltir.” Yalnızca adreslenebilirliği düzeltir. Sunucu her rota için hâlâ aynı kabuğu döndürüyorsa Google bir şey görebilmek için yine JS çalıştırmak zorundadır.
  • “Hash routing hâlâ yedek olarak çalışır.” 2015’ten beri kullanım dışıdır ve o zamandan beri önerilmemektedir.
  • “İstemci tarafı oluşturma bir sıralama cezasıdır.” Doğrudan bir CSR cezası yoktur. Zarar dolaylıdır: başarısız/gecikmiş oluşturma, soft-not-found durumları ve oluşturma zaman aşımlarından kaynaklanan yinelenen kümeler dizine eklenen içeriği azaltır.
  • “Botlar için önceden oluşturma cloaking’dir.” İçerik kullanıcıların sonunda gördüğü içerikle eşleştiğinde cloaking değildir; farklı olan yalnızca içeriğin ne zaman ve nerede oluşturulduğudur.
  • “Özel bir SPA sitemap oluşturucusuna ihtiyacınız var.” Özel bir format yoktur; yapılması gereken, listelenen her rotanın gerçek HTML’ye çözümlenmesini sağlamaktır.

SSS

Google tek sayfalı bir uygulamayı dizine ekleyebilir mi? Evet; her rota gerçek bir URL’de gerçek ve benzersiz HTML’e (SSR/prerendering yoluyla) çözülüyorsa. Çıplak, yalnızca istemci tarafında çalışan SPA’lar çoğu zaman bunu yapamaz.

SSR’ye ihtiyacım var mı, yoksa istemci tarafı oluşturma hiç uygun olabilir mi? Sıralanması gerekmeyen içerik için CSR çalışabilir; ancak güvenilir biçimde dizine eklenmesini istediğiniz her şey için prerendering veya SSR kullanın — oluşturucunun JS’inizi zamanında çalıştırmasına bel bağlamayın.

Hash (#!) yönlendirmesi SEO için kötü mü? Evet — parça sunucuya hiç ulaşmaz; bu yüzden Google bu URL’leri güvenilir biçimde çözemez. History API’yi kullanın.

Her rotanın kendi canonical etiketine ihtiyacı var mı? Evet, oluşturulmuş DOM’da — ve ham kabukta daha kısıtlayıcı hiçbir şeyin (başıboş bir noindex veya yanlış canonical) gönderilmediğinden emin olun.

Bir prerendering servisi cloaking midir? Hayır; botlara sunulan içerik kullanıcıların gördüğü içerikle eşleştiği sürece.

Yönlendirmeyi kendim kurmak yerine bir meta-framework kullanmalı mıyım? Yeni bir build için genellikle evet — Next.js/Nuxt/Angular-SSR/SvelteKit size SSR/SSG’yi ve rota başına meta verileri ücretsiz sunar.

SPA’m var olmayan sayfalar için neden 200 döndürüyor? Çünkü istemci tarafı yönlendirici sanal gezinmelerde başlangıçtaki 200 durumunu korur. Gerçek hata durumuna bir JS yönlendirmesiyle veya oluşturulmuş bir noindex ile düzeltin.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.