Modern web uygulamalarının büyük çoğunluğu artık JavaScript üzerine inşa ediliyor. React, Vue, Angular, Next.js, Nuxt — bu framework’ler geliştiricilere muazzam bir esneklik sunuyor. Ancak bu esneklik, SEO açısından ciddi tuzaklar barındırıyor.
Sorun şu: Googlebot, bir insan kullanıcı gibi sayfayı anında görmüyor. JavaScript ile oluşturulan içerikler, belirli bir render sürecinden geçmeden indekslenemiyor. Bu süreç doğru yönetilmediğinde, sitenizin tamamı ya da önemli bir bölümü Google’ın gözünden kaçıyor.
Bu rehberde Googlebot’un JavaScript’i nasıl işlediğini, hangi render modellerinin SEO için ne anlama geldiğini ve 2026 itibarıyla uygulamanız gereken teknik optimizasyon stratejilerini ayrıntılı biçimde ele alacağız.
Googlebot JavaScript’i Neden Farklı İşler?
Klasik HTML siteler, Googlebot tarafından çok daha basit bir süreçle işlenir: HTML indirilir, metin parse edilir, linkler bulunur ve içerik indekse alınır. Birkaç saniye içinde tamamlanan bu süreç JavaScript ağırlıklı sitelerde köklü biçimde değişir.
JavaScript tabanlı sayfalar iki aşamalı bir süreç gerektirir:
- HTML indirme ve parse etme: Googlebot sayfa kodunu indirir. Ancak bu aşamada gördüğü şey genellikle içi boş bir iskelet —
<div id="root"></div>gibi. - Render: JavaScript dosyaları indirilir, yorumlanır ve DOM gerçek içeriğiyle oluşturulur.
Bu iki aşama arasındaki zaman farkı, JavaScript SEO’sunun temel sorun kaynağıdır.
Googlebot’un JavaScript İşleme Süreci: Crawl → WRS → Index
Googlebot bir JavaScript sayfasını işlerken dört temel aşamadan geçer. Bu süreci tam olarak anlamak, nerede hata yapıldığını tespit etmek için kritiktir.
Aşama 1: Crawl (Tarama)
Googlebot URL’yi keşfeder ve ham HTML’i indirir. Bu noktada sayfa henüz render edilmemiştir. Eğer içeriğiniz yalnızca JS ile oluşturuluyorsa, Googlebot bu aşamada neredeyse hiçbir şey görmez.
Aşama 2: WRS Kuyruğu (Web Rendering Service)
Google’ın WRS (Web Rendering Service) altyapısı, tarama sırasında render edilemeyen sayfaları bir kuyruğa alır. Bu kuyruk, Google’ın mevcut render kapasitesine göre işlenir.
Kritik nokta: Bu kuyruk bekleme süresi dakikalarla değil, günlerle ya da haftalarla ölçülebilir. Yani JS ile oluşturulan bir içerik, taranmasından günler sonra indekslenebilir. Bu “render gecikmesi” (render delay), dinamik içeriklerin taze tutulmasını zorlaştırır.
Aşama 3: Render
WRS, Chromium tabanlı bir headless browser kullanarak sayfayı render eder. JavaScript çalıştırılır, DOM oluşturulur. Ancak WRS’nin bazı kısıtlamaları vardır:
- Bazı modern JavaScript API’leri desteklenmeyebilir
- İşlem zaman aşımı (timeout) nedeniyle uzun süren scriptler çalışmayabilir
- Üçüncü taraf kaynaklara yapılan çağrılar engellenebilir
- Service Worker’lar güvenilir biçimde çalışmaz
Aşama 4: Index
Render sonucunda elde edilen içerik, linkler ve meta veriler Google’ın indeksine alınır. Burada önemli olan nokta: Googlebot render edilen DOM’u baz alır, kaynak HTML’i değil.
CSR vs SSR vs SSG vs ISR: SEO Açısından Karşılaştırma
Bir web uygulaması inşa ederken seçeceğiniz render stratejisi, SEO performansınızı doğrudan etkiler. Dört ana model bulunur ve her birinin SEO etkisi farklıdır.
CSR — Client-Side Rendering (İstemci Tarafı Render)
Tarayıcı önce boş bir HTML yükler, ardından JavaScript devreye girerek içeriği oluşturur. React uygulamalarının varsayılan mimarisi budur.
<!-- CSR ile gelen ham HTML -->
<!DOCTYPE html>
<html>
<head>
<title>Uygulama</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>
Googlebot bu sayfayı taradığında <div id="root"></div> dışında içerik görmez. WRS kuyruğuna alınır ve render sonrası içerik indekslenir — ancak gecikmeli olarak.
SEO açısından CSR’ın riskleri:
- Render gecikmesi nedeniyle içerik güncellemeleri yavaş indekslenir
- Render bütçesi (render budget) aşılırsa bazı sayfalar hiç render edilmez
- İlk Byte Süresi (TTFB) çoğu zaman kabul edilebilir olsa da Largest Contentful Paint (LCP) geç gelir
SSR — Server-Side Rendering (Sunucu Tarafı Render)
Her istek için sunucu, dinamik olarak tam HTML üretir ve tarayıcıya gönderir. Next.js’de getServerSideProps, Nuxt’ta asyncData ile sağlanır.
// Next.js SSR örneği
export async function getServerSideProps(context) {
const { params } = context;
const res = await fetch(`https://api.example.com/posts/${params.slug}`);
const post = await res.json();
return {
props: { post },
};
}
export default function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
Googlebot bu sayfayı taradığında tam ve doldurulmuş HTML’i görür. WRS kuyruğuna gerek olmadan içerik anında indekslenebilir.
SSR’ın SEO avantajları:
- Googlebot içeriği ilk taramada görür
- Render gecikmesi yok
- Dinamik içerikler (kullanıcıya özel değilse) indekslenebilir
Dezavantajı: Her istek için sunucu işlemi gerektirir; yüksek trafikte sunucu maliyeti artar.
SSG — Static Site Generation (Statik Site Üretimi)
Derleme zamanında tüm sayfalar önceden HTML olarak üretilir. Astro, Next.js ve Nuxt bu modeli destekler. Üretilen dosyalar CDN üzerinden dağıtılır.
// Next.js SSG örneği
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: { posts },
};
}
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
const paths = posts.map((post) => ({
params: { slug: post.slug },
}));
return { paths, fallback: false };
}
SSG’nin SEO avantajları:
- Tam HTML, Googlebot için anında hazır
- Render gecikmesi sıfır
- CDN üzerinden hızlı teslimat → Core Web Vitals iyileşir
- Render bütçesi sorunu yok
Dezavantajı: İçerik değiştiğinde yeniden derleme gerekir. Sık güncellenen içerikler için tek başına yeterli olmaz.
ISR — Incremental Static Regeneration
Next.js’e özgü bu model, SSG ile SSR’ın melezi sayılabilir. Sayfalar statik olarak üretilir, ancak belirli aralıklarla arka planda yeniden üretilir.
// Next.js ISR örneği
export async function getStaticProps() {
const res = await fetch('https://api.example.com/blog');
const data = await res.json();
return {
props: { data },
revalidate: 3600, // Her saat yeniden üret
};
}
SEO açısından ISR: Googlebot statik HTML’i görür, dolayısıyla render gecikmesi yaşanmaz. Ancak içerik güncellemeleri revalidate süresi dolana kadar yansımaz; bu, haber siteleri gibi sık güncelleme gerektiren durumlar için sorun oluşturabilir.
Karşılaştırma Tablosu
| Özellik | CSR | SSR | SSG | ISR |
|---|---|---|---|---|
| Googlebot ilk taramada içeriği görür mi? | Hayır | Evet | Evet | Evet |
| Render gecikmesi riski | Yüksek | Yok | Yok | Yok |
| Dinamik içerik desteği | Evet | Evet | Sınırlı | Kısmi |
| Sunucu maliyeti | Düşük | Yüksek | Çok düşük | Düşük |
| Core Web Vitals etkisi | Olumsuz | Nötr | Olumlu | Olumlu |
Render Bütçesi ve Gecikme Sorunu
Google’ın sonsuz render kapasitesi yoktur. Her site için belirli bir “render bütçesi” tahsis edilir; bu bütçe dolduğunda geri kalan sayfalar render edilmeden bekler.
Render Bütçesini Etkileyen Faktörler
- Site otoritesi: Yüksek otoriteli siteler daha fazla render bütçesi alır
- Sayfa sayısı: Milyonlarca sayfası olan büyük siteler daha fazla baskı altındadır
- JavaScript dosya büyüklüğü: Bundle boyutu büyüdükçe render süresi uzar
- Üçüncü taraf scriptler: Analytics, chat widget, A/B test araçları render süresini uzatır
Render Gecikmesini Azaltma Stratejileri
1. Critical rendering path’i optimize edin:
<!-- Kritik CSS'i inline ekleyin -->
<style>
/* Sadece above-the-fold içerik için gerekli CSS */
body { margin: 0; font-family: sans-serif; }
.hero { height: 100vh; background: #000; }
</style>
<!-- Kritik olmayan CSS'i defer edin -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
2. JavaScript bundle’ını küçültün:
// next.config.js — bundle analyzer ile ağır paketleri tespit edin
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
// diğer ayarlar
});
3. Code splitting uygulayın:
// Dinamik import ile lazy loading
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <p>Yükleniyor...</p>,
ssr: false, // SEO için gerekli olmayan bileşenler
});
JavaScript İç Linkleri ve SEO
İç linkleme, SEO’nun temel taşlarından biridir. Ancak JavaScript ile oluşturulan linklerin Googlebot tarafından farklı işlendiğini bilmek gerekir.
Doğru Link Yapısı
Googlebot yalnızca <a href="..."> etiketlerini güvenilir biçimde takip eder. JavaScript event listener’larıyla tetiklenen navigasyonlar link olarak algılanmaz.
<!-- Googlebot bu linki takip eder ✓ -->
<a href="/hakkimizda">Hakkımızda</a>
<!-- Googlebot bu linki takip ETMEZ ✗ -->
<span onclick="window.location.href='/hakkimizda'">Hakkımızda</span>
<button onclick="navigate('/hakkimizda')">Hakkımızda</button>
Next.js ve Nuxt’ta Doğru Link Kullanımı
// Next.js — doğru kullanım ✓
import Link from 'next/link';
export default function Navigation() {
return (
<nav>
<Link href="/hizmetler/teknik-seo">Teknik SEO</Link>
<Link href="/hizmetler/web-tasarim">Web Tasarım</Link>
<Link href="/blog">Blog</Link>
</nav>
);
}
<!-- Nuxt.js — doğru kullanım ✓ -->
<template>
<nav>
<NuxtLink to="/hizmetler/teknik-seo">Teknik SEO</NuxtLink>
<NuxtLink to="/hizmetler/web-tasarim">Web Tasarım</NuxtLink>
</nav>
</template>
Next.js’in <Link> bileşeni ve Nuxt’un <NuxtLink> bileşeni, render sonucunda standart <a> etiketi üretir. Bu nedenle Googlebot bu linkleri sorunsuz takip edebilir.
SPA’larda Sayfalama Linkleri
Tek sayfa uygulamalarında sayfalama genellikle JavaScript ile yönetilir. Bu durum linklerin görünmez olmasına neden olabilir.
// Yanlış: JavaScript ile sayfalama ✗
function Pagination({ currentPage, onPageChange }) {
return (
<div>
<button onClick={() => onPageChange(currentPage - 1)}>Önceki</button>
<button onClick={() => onPageChange(currentPage + 1)}>Sonraki</button>
</div>
);
}
// Doğru: Gerçek URL'lerle sayfalama ✓
function Pagination({ currentPage, totalPages }) {
return (
<div>
{currentPage > 1 && (
<a href={`/blog?page=${currentPage - 1}`}>Önceki</a>
)}
{currentPage < totalPages && (
<a href={`/blog?page=${currentPage + 1}`}>Sonraki</a>
)}
</div>
);
}
Lazy-Loaded Content ve SEO
Görünüm alanına girdikçe yüklenen (lazy-loaded) içerikler kullanıcı deneyimini iyileştirir; ancak yanlış uygulandığında önemli içeriklerin Googlebot tarafından görülmesini engeller.
Intersection Observer ile Lazy Loading
// Görsel lazy loading — SEO açısından güvenli
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imageObserver.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
<!-- HTML tarafında -->
<img
src="/placeholder.jpg"
data-src="/gercek-gorsel.jpg"
alt="Ürün görseli"
loading="lazy"
/>
Önemli: loading="lazy" native HTML özelliği Googlebot tarafından desteklenir. Görseller için bu yöntemi tercih edin; JavaScript tabanlı lazy loading yerine.
İçerik Lazy Loading’in SEO Riskleri
Kritik içeriklerinizi (ana başlık, ilk paragraf, önemli linkler) asla lazy load etmeyin. Bu içerikler her koşulda ilk HTML yanıtında veya render sonrasında görünür olmalıdır.
// Risk: Ana içerik lazy load edilmiş ✗
const MainContent = dynamic(() => import('./MainContent'), {
ssr: false,
});
// Güvenli: Sadece görsel ağır bileşenler ssr: false ✓
const VideoPlayer = dynamic(() => import('./VideoPlayer'), {
ssr: false,
});
const ChatWidget = dynamic(() => import('./ChatWidget'), {
ssr: false,
});
Dynamic Meta Tags ve SEO
JavaScript ile dinamik olarak değiştirilen <title>, <meta description> ve Open Graph etiketleri, Googlebot’un render sürecine bağlıdır.
Next.js’de Metadata
Next.js App Router ile meta veriler sunucu tarafında üretilir — bu SEO için idealdir:
// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [{ url: post.coverImage }],
},
alternates: {
canonical: `https://example.com/blog/${params.slug}`,
},
};
}
Nuxt’ta useHead
// Nuxt 3 — pages/blog/[slug].vue
const { data: post } = await useAsyncData('post', () =>
$fetch(`/api/posts/${route.params.slug}`)
);
useHead({
title: post.value?.title,
meta: [
{ name: 'description', content: post.value?.excerpt },
{ property: 'og:title', content: post.value?.title },
{ property: 'og:description', content: post.value?.excerpt },
],
link: [
{ rel: 'canonical', href: `https://example.com/blog/${route.params.slug}` },
],
});
Angular’da Title ve Meta Service
// Angular — blog-post.component.ts
import { Component, OnInit } from '@angular/core';
import { Title, Meta } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-blog-post',
templateUrl: './blog-post.component.html',
})
export class BlogPostComponent implements OnInit {
constructor(
private title: Title,
private meta: Meta,
private route: ActivatedRoute,
private postService: PostService
) {}
ngOnInit() {
const slug = this.route.snapshot.params['slug'];
this.postService.getPost(slug).subscribe(post => {
this.title.setTitle(post.title);
this.meta.updateTag({ name: 'description', content: post.excerpt });
this.meta.updateTag({ property: 'og:title', content: post.title });
});
}
}
Kritik hatırlatma: Angular uygulamalarında meta etiketler yalnızca client-side set ediliyorsa, Angular Universal (SSR) kullanmadan Googlebot bu etiketleri render gecikmesiyle görecektir.
Hreflang JavaScript ile Kullanımda
Çok dilli siteler için hreflang etiketleri kritik öneme sahiptir. Bu etiketlerin JavaScript ile inject edilmesi, Googlebot’un bunları doğru okumasını zorlaştırabilir.
Doğru Yöntem: SSR/SSG ile Hreflang
// Next.js App Router — layout veya page.js içinde
export async function generateMetadata({ params }) {
return {
alternates: {
languages: {
'tr-TR': 'https://example.com/tr/blog/javascript-seo',
'en-US': 'https://example.com/en/blog/javascript-seo',
'de-DE': 'https://example.com/de/blog/javascript-seo',
'x-default': 'https://example.com/en/blog/javascript-seo',
},
},
};
}
Bu yöntem, hreflang etiketlerini HTML’in <head> bölümüne sunucu tarafında yerleştirir. Googlebot render gecikmesine gerek kalmadan bu etiketleri okuyabilir.
XML Sitemap ile Hreflang (Alternatif)
Hreflang etiketlerini <head>’e eklemek yerine sitemap içinde de belirtebilirsiniz. Bu yöntem JavaScript’e hiç bağlı değildir:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://example.com/tr/blog/javascript-seo</loc>
<xhtml:link rel="alternate" hreflang="tr-TR"
href="https://example.com/tr/blog/javascript-seo"/>
<xhtml:link rel="alternate" hreflang="en-US"
href="https://example.com/en/blog/javascript-seo"/>
<xhtml:link rel="alternate" hreflang="x-default"
href="https://example.com/en/blog/javascript-seo"/>
</url>
</urlset>
JavaScript ile Structured Data (Schema Markup)
Yapısal veri, Googlebot’un içeriğinizi daha iyi anlamasını ve zengin sonuçlar (rich results) göstermesini sağlar. JSON-LD formatında sunulan yapısal veri, script etiketi içinde olduğu için JavaScript uyumluluğu açısından en güvenli yöntemdir.
Doğru JSON-LD Ekleme
// Next.js — App Router ile JSON-LD
export default function BlogPost({ post }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
description: post.excerpt,
image: post.coverImage,
author: {
'@type': 'Person',
name: post.author.name,
},
publisher: {
'@type': 'Organization',
name: 'Site Adı',
logo: {
'@type': 'ImageObject',
url: 'https://example.com/logo.png',
},
},
datePublished: post.publishedAt,
dateModified: post.updatedAt,
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://example.com/blog/${post.slug}`,
},
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
</>
);
}
Dinamik Schema Verileri için Dikkat Edilecekler
JSON-LD içindeki veriler her zaman sayfa içeriğiyle tutarlı olmalıdır. Google, schema verisi ile görünür içerik arasındaki tutarsızlıkları ceza sebebi saymaktadır.
// Hatalı: Schema'daki fiyat ile sayfadaki fiyat farklı ✗
const jsonLd = {
'@type': 'Product',
offers: {
'@type': 'Offer',
price: '99.00', // Hardcoded
},
};
// Doğru: Her iki değer de aynı kaynaktan gelsin ✓
const jsonLd = {
'@type': 'Product',
offers: {
'@type': 'Offer',
price: product.price.toString(),
priceCurrency: product.currency,
},
};
Next.js ile SEO Best Practices
Next.js, App Router mimarisiyle JavaScript SEO sorunlarının büyük çoğunluğunu çözüme kavuşturmuştur. Ancak bazı yapılandırmalar hâlâ dikkat gerektirir.
Robots.txt ve Sitemap
// app/robots.js
export default function robots() {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/private/'],
},
sitemap: 'https://example.com/sitemap.xml',
};
}
// app/sitemap.js
export default async function sitemap() {
const posts = await getAllPosts();
return [
{
url: 'https://example.com',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 1,
},
...posts.map(post => ({
url: `https://example.com/blog/${post.slug}`,
lastModified: new Date(post.updatedAt),
changeFrequency: 'monthly',
priority: 0.8,
})),
];
}
Canonical URL Yönetimi
// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
return {
alternates: {
canonical: `https://example.com/blog/${params.slug}`,
},
};
}
Core Web Vitals için Next.js Optimizasyonları
// Image optimizasyonu
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Ana görsel"
width={1200}
height={630}
priority // LCP görseli için kritik
sizes="(max-width: 768px) 100vw, 1200px"
/>
);
}
// Font optimizasyonu — CLS'yi önler
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap',
});
Nuxt.js ile SEO Best Practices
Nuxt 3, SSR ve SSG modlarında güçlü SEO desteği sunar.
Nuxt’ta Global SEO Ayarları
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1',
meta: [
{ name: 'robots', content: 'index, follow' },
],
},
},
nitro: {
prerender: {
routes: ['/sitemap.xml', '/robots.txt'],
},
},
});
Nuxt Content ile SEO
<!-- pages/blog/[slug].vue -->
<script setup>
const route = useRoute();
const { data: post } = await useAsyncData(route.params.slug, () =>
queryContent('/blog').where({ slug: route.params.slug }).findOne()
);
useSeoMeta({
title: post.value?.title,
description: post.value?.description,
ogTitle: post.value?.title,
ogDescription: post.value?.description,
ogImage: post.value?.image,
twitterCard: 'summary_large_image',
});
useHead({
link: [
{ rel: 'canonical', href: `https://example.com/blog/${route.params.slug}` },
],
});
</script>
Angular SEO Best Practices
Angular uygulamaları varsayılan olarak CSR ile çalışır. SEO için Angular Universal (SSR) veya Angular ile Prerendering zorunludur.
Angular Universal Kurulumu
# Angular Universal ekleme
ng add @nguniversal/express-engine
# Build ve serve
npm run build:ssr
npm run serve:ssr
Angular’da SEO Service
// seo.service.ts
import { Injectable } from '@angular/core';
import { Title, Meta } from '@angular/platform-browser';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class SeoService {
constructor(
private title: Title,
private meta: Meta,
private router: Router
) {}
updateMetadata(config: {
title: string;
description: string;
canonical?: string;
image?: string;
}) {
this.title.setTitle(config.title);
this.meta.updateTag({ name: 'description', content: config.description });
this.meta.updateTag({ property: 'og:title', content: config.title });
this.meta.updateTag({ property: 'og:description', content: config.description });
if (config.canonical) {
// Canonical link tag için DOM manipülasyonu
let link: HTMLLinkElement = document.querySelector('link[rel=canonical]')!;
if (!link) {
link = document.createElement('link');
link.setAttribute('rel', 'canonical');
document.head.appendChild(link);
}
link.setAttribute('href', config.canonical);
}
if (config.image) {
this.meta.updateTag({ property: 'og:image', content: config.image });
}
}
}
Test Araçları: JavaScript SEO’yu Doğrulama
Uyguladığınız stratejilerin çalıştığını doğrulamak için Google’ın resmi araçlarını ve bazı üçüncü taraf araçları kullanmalısınız.
URL Inspection (Google Search Console)
Google Search Console’daki URL Inspection aracı, Googlebot’un sayfanızı render sonrası nasıl gördüğünü gösterir.
Kullanım adımları:
- Search Console’a giriş yapın
- Üst arama çubuğuna incelemek istediğiniz URL’yi girin
- ”Test Live URL” butonuna tıklayın
- ”View Tested Page” → “Screenshot” ile render edilmiş sayfayı görün
- ”HTML” sekmesinde render sonrası DOM’u inceleyin
- ”More Info” → “Page Resources” ile hangi kaynakların yüklenip yüklenmediğini kontrol edin
Ne aramalısınız:
- Önemli içerikler render edilmiş ekran görüntüsünde görünüyor mu?
- Meta title ve description doğru set edilmiş mi?
- Canonical URL beklendiği gibi mi?
- JavaScript hataları var mı?
Mobile-Friendly Test
Google’ın Mobile-Friendly Test aracı, sayfanızın mobil uyumluluğunu ve render durumunu kontrol eder.
- Adres:
search.google.com/test/mobile-friendly - JavaScript ile oluşturulan içeriğin mobilde render edilip edilmediğini görürsünüz
- Sayfa kaynaklarını bloklayan öğeleri tespit eder
Rich Results Test
Structured data’nızın doğru çalıştığını doğrulamak için Rich Results Test kullanılır.
- Adres:
search.google.com/test/rich-results - JSON-LD’yi JavaScript ile inject ediyorsanız, aracın sayfayı render ettikten sonra schema’yı bulup bulmadığını kontrol edin
- Algılanan tüm schema türlerini ve hataları listeler
Lighthouse SEO Denetimi
# Chrome DevTools veya CLI ile
npx lighthouse https://example.com --only-categories=seo --output=json
# Temel SEO metrikleri:
# - meta description varlığı
# - hreflang geçerliliği
# - canonical tag kontrolü
# - robots.txt erişilebilirliği
# - crawlable links kontrolü
Screaming Frog ile JavaScript Render Karşılaştırması
Screaming Frog Spider’ın “Rendering” modunu kullanarak JavaScript öncesi ve sonrası içerikleri karşılaştırabilirsiniz:
- Configuration → Spider → Rendering → JavaScript seçin
- Taramayı başlatın
- Sonuçları “Rendered Page Source” ile “Raw HTML” arasında karşılaştırın
- JS öncesi boş olan ancak JS sonrası dolan içerikleri tespit edin
JavaScript SEO’da Kaçınılması Gereken 10 Kritik Hata
Hata 1: Tüm İçeriği CSR ile Yönetmek
E-ticaret ürün sayfaları, blog yazıları, hizmet sayfaları gibi SEO için kritik sayfaları yalnızca CSR ile yönetmek ciddi render gecikmesi riski oluşturur. Bu sayfalar için SSR veya SSG tercih edilmelidir.
Hata 2: <a> Etiketi Kullanmamak
Navigasyon için button veya span elementleri kullanmak, Googlebot’un linkleri keşfedememesine neden olur. Her dahili ve harici link için standart <a href=""> etiketi kullanın.
Hata 3: History API’yi <a> Etiketleri Olmadan Kullanmak
SPA router’ları history.pushState ile URL değiştirirken arka planda <a> etiketleri üretmiyorsa, Googlebot bu “sayfaları” ayrı URL olarak keşfedemez.
Hata 4: Kritik İçeriği Lazy Load Etmek
Sayfa başlığı, giriş paragrafı ve ana CTA gibi kritik içeriklerin lazy load edilmesi, Googlebot’un bu içerikleri görmemesiyle sonuçlanabilir.
Hata 5: JavaScript ile Canonical Eklemek
// YANLIŞ: Canonical'ı JavaScript ile DOM'a ekleme ✗
document.head.insertAdjacentHTML('beforeend',
'<link rel="canonical" href="https://example.com/sayfa">'
);
// DOĞRU: Canonical'ı SSR/SSG ile <head>'e ekle ✓
// next.config.js veya sunucu tarafı rendering ile
Hata 6: noindex Etiketini JS ile Yönetmek
Render gecikmesi nedeniyle Googlebot sayfayı önce noindex olmadan tarayabilir. Bu durumda indeksleme başlamış olabilir.
Hata 7: Üçüncü Taraf Script’leri Kontrol Etmemek
Chat widget’ları, A/B test araçları ve pazarlama pixel’leri render bütçesini tüketerek Googlebot’un sayfayı zamanında render edememesine yol açabilir.
Hata 8: Core Web Vitals’ı İhmal Etmek
JavaScript ağır sayfalar genellikle kötü LCP (Largest Contentful Paint) ve FID (First Input Delay) değerleri üretir. Bu metrikler Google’ın sıralama sinyallerinden biridir.
Hata 9: Soft 404 Üretmek
API çağrısı başarısız olduğunda JavaScript, boş sayfa veya “İçerik bulunamadı” mesajı gösterirken HTTP 200 döndürebilir. Bu “soft 404” olarak adlandırılır ve Googlebot tarafından sorun olarak değerlendirilir.
// SSR'da doğru HTTP status code döndürme
export async function getServerSideProps({ params, res }) {
const post = await getPost(params.slug);
if (!post) {
res.statusCode = 404;
return { props: { notFound: true } };
}
return { props: { post } };
}
Hata 10: Sitemap’i Güncel Tutmamak
Dinamik olarak oluşturulan sayfalar sitemap’e otomatik eklenmelidir. Mevcut bir <a> linki olmayan sayfaların sitemap’te bulunması Googlebot’un bu sayfaları keşfetmesi için kritiktir.
JavaScript SEO ve Teknik SEO’nun Kesişim Noktaları
JavaScript SEO, daha geniş bir teknik SEO stratejisinin ayrılmaz bir parçasıdır. Crawl bütçesi yönetimi, redirect zincirlerinin optimizasyonu, HTTP status code’larının doğruluğu ve site hızı — tüm bu faktörler JavaScript render süreciyle doğrudan ilişkilidir.
Özellikle Next.js, Nuxt veya Angular üzerine kurulu bir web tasarım projesinde teknik SEO gereksinimlerinin baştan mimariye entegre edilmesi, sonradan yapılacak pahalı düzeltmelerin önüne geçer. Bir web uygulaması inşa edilirken render stratejisi seçimi, URL yapısı, meta tag yönetimi ve structured data planlaması eş zamanlı yürütülmelidir.
Crawl Bütçesi ile Render Bütçesi Arasındaki Fark
JavaScript SEO tartışmalarında iki kavram sıklıkla karıştırılır: crawl bütçesi ve render bütçesi. Bunlar birbirine bağlı ama farklı kavramlardır.
Crawl bütçesi, Googlebot’un belirli bir zaman diliminde sitenize kaç istek gönderebileceğini ifade eder. Büyük, otoriter siteler daha yüksek crawl bütçesine sahiptir. Crawl bütçenizi verimli kullanmak için tekrar eden parametreli URL’leri, kalın içerikleri ve kırık sayfaları minimize etmeniz gerekir.
Render bütçesi ise farklı bir kaynaktır: Googlebot kaç sayfa için WRS render işlemi başlatacağını ve bu işlemi ne kadar süre sürdüreceğini belirler. Bir sayfa crawl ediliyor olsa bile render bütçesi dolmuşsa o sayfa render kuyrukta bekler.
Render Bütçesini Nasıl Korursunuz?
Render bütçenizi korumak için şu adımları uygulayın:
Gereksiz JavaScript dosyalarını kaldırın. Kullanılmayan npm paketleri, artık aktif olmayan A/B test kodları ve atıl analytics scriptleri bundle boyutunu şişirir. Her kilobayt, WRS’nin harcadığı kaynak anlamına gelir.
Üçüncü taraf scriptleri async veya defer yükleyin:
<!-- Render'ı bloke eden script ✗ -->
<script src="https://analytics.example.com/script.js"></script>
<!-- Render'ı bloke etmeyen script ✓ -->
<script src="https://analytics.example.com/script.js" async></script>
<!-- DOM hazır olduktan sonra çalışan script ✓ -->
<script src="https://analytics.example.com/script.js" defer></script>
Preconnect ile bağlantıları önceden açın:
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
JavaScript hatalarını minimize edin. WRS, JavaScript hataları nedeniyle render süreci yarıda kesilen sayfaları eksik içerikle indeksler. Production build’inizde window.onerror ve unhandledrejection event’lerini izleyin.
JavaScript ile Oluşturulan URL’lerin Yönetimi
SPA mimarisinde URL yönetimi, SEO açısından kritik bir konudur. History API’nin doğru kullanımı ile her “sayfa” Googlebot tarafından ayrı bir URL olarak keşfedilebilir olmalıdır.
Hash Tabanlı Routing’den Kaçının
// Hash routing — SEO için kötü ✗
// https://example.com/#/hakkimizda
// https://example.com/#/blog/javascript-seo
// History API tabanlı routing — SEO için doğru ✓
// https://example.com/hakkimizda
// https://example.com/blog/javascript-seo
Hash (#) ile oluşturulan URL’ler, Googlebot tarafından tek bir URL olarak değerlendirilir. # sonrası değişen kısım arama motorlarına görünmez.
React Router ile SEO Uyumlu Routing
// React Router v6 — history API tabanlı ✓
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/hakkimizda" element={<About />} />
<Route path="/blog/:slug" element={<BlogPost />} />
<Route path="/hizmetler/:service" element={<Service />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
Bu yapı, her route için ayrı bir <a> linki üretebilir durumda olmalıdır. Eğer uygulamanız yalnızca programatik navigasyon kullanıyorsa, Googlebot bu sayfaları hiç keşfedemez.
Prerendering: CSR Siteler için Geçici Çözüm
CSR ağırlıklı bir migrasyona gidemeyeceğiniz durumlarda prerendering (ön render) geçici bir çözüm sunabilir. Prerendering, sayfaları derleme zamanında headless browser ile render edip statik HTML olarak saklar; Googlebot bu statik versiyonu görür.
Prerendering Araçları
- Prerender.io: Cloud tabanlı prerendering servisi. Bot tespiti yaparak botlara HTML, insanlara JS versiyonu sunar
- react-snap: Build sırasında Puppeteer ile sayfaları statik HTML’e dönüştürür
- Rendertron: Google’ın kendi geliştirdiği açık kaynaklı prerendering çözümü
// react-snap kurulumu — package.json
{
"scripts": {
"postbuild": "react-snap"
},
"reactSnap": {
"inlineCss": true,
"minifyHtml": {
"collapseWhitespace": false,
"removeComments": false
}
}
}
Önemli uyarı: Google, kullanıcılara farklı sunucu botlara farklı içerik sunmayı (cloaking) ceza sebebi sayar. Prerendering yalnızca aynı içeriğin farklı formatlarda sunulması durumunda güvenlidir. Botlara özel farklı içerik asla göstermeyin.
JavaScript SEO Denetim Kontrol Listesi
Bir JavaScript ağırlıklı siteyi SEO açısından denetlerken şu maddeleri sistematik biçimde kontrol etmeniz gerekir:
Crawl Denetimi
- Robots.txt dosyası JavaScript ve CSS kaynaklarını blokluyor mu? (Bloklanmamalıdır)
- XML sitemap tüm önemli URL’leri içeriyor mu?
- İç linklerin tamamı standart
<a href>etiketiyle mi yapılmış? - Hash routing kullanılıyor mu? (Kullanılmamalıdır)
- Sayfalama linkleri gerçek URL’lerle mi çalışıyor?
Render Denetimi
- URL Inspection ile render edilmiş HTML kontrol edildi mi?
- Kritik içerikler ilk HTML yanıtında mı yoksa render sonrasında mı geliyor?
- JavaScript hataları console’da görünüyor mu?
- Üçüncü taraf scriptler async/defer ile yükleniyor mu?
- Bundle boyutu makul seviyelerde mi? (300KB altı tercih edilir)
Meta Veri Denetimi
- Title ve meta description her sayfada unique ve SSR/SSG ile mi üretiliyor?
- Canonical URL doğru set edilmiş mi?
- Hreflang etiketleri doğru formatta ve tüm dil versiyonları için mevcut mu?
- Open Graph ve Twitter Card etiketleri render sonrasında doğru mu?
Structured Data Denetimi
- JSON-LD sayfa içeriğiyle tutarlı mı?
- Rich Results Test hata döndürüyor mu?
- Schema tipi sayfa içeriğiyle uyumlu mu (Article, Product, FAQPage vb.)?
2026’da JavaScript SEO’nun Geleceği
Google’ın Evergreen Googlebot politikası, WRS’nin sürekli güncel Chromium sürümlerini kullandığı anlamına gelir. Bu, 2026 itibarıyla modern JavaScript API’lerinin büyük çoğunluğunun Googlebot tarafından desteklendiğini gösterir.
Ancak render gecikmesi sorunu hâlâ geçerlidir. Google, bu sorunu çözmek için çaba gösterse de büyük siteler için render kuyruğu bekleme süreleri anlamlı kalabilir.
2026’da odaklanılması gereken alanlar:
- INP (Interaction to Next Paint): Core Web Vitals’ta FID’in yerini alan bu metrik, JavaScript ağır sayfalar için kritik öneme sahip
- Speculation Rules API: Tarayıcının sayfaları önceden yüklemesini sağlayan bu yeni API, JavaScript SPA’larında deneyimi iyileştirir
- Server Components: React Server Components ve Next.js App Router mimarisinin yaygınlaşmasıyla client-side JavaScript azalmakta, bu durum render sorunlarını kökten çözme potansiyeli taşımakta
- Edge Rendering: Cloudflare Workers ve Vercel Edge Functions ile SSR, kullanıcıya en yakın edge node’da gerçekleştirilerek hem hız hem SEO iyileştirilmektedir
Sonuç
JavaScript SEO, yalnızca bir optimizasyon taktiği değil; modern web geliştirmenin temel bir boyutudur. Googlebot’un WRS kuyruğu aracılığıyla sayfaları nasıl render ettiğini anlamak, render bütçesini akıllıca yönetmek, doğru render stratejisini (SSR, SSG veya ISR) seçmek ve her linkten meta etikete kadar teknik detayları doğru uygulamak — bunların tamamı organik görünürlüğünüzü doğrudan etkiler.
Özellikle React, Next.js, Nuxt veya Angular ile geliştirilen sitelerde JavaScript SEO sorunları çoğu zaman sıralama kayıplarının görünmez nedenidir. URL Inspection ve Rich Results Test gibi araçlarla düzenli denetim yaparak sorunları erken tespit edin.
JavaScript ile oluşturulmuş sitenizin SEO potansiyelini tam olarak değerlendirmek için teknik SEO hizmetlerimizden yararlanabilir veya JavaScript ağırlıklı projenizi SEO uyumlu biçimde inşa etmek için web tasarım çözümlerimizi inceleyebilirsiniz.