İçeriğe geç
Approvalens

Okuma odası · 7 dk okuma

Next.js ve React Sitelerde AdSense: Kod, ads.txt ve Render

Next.js veya React sitesine AdSense nasıl eklenir? App Router'da kodun yeri, /public içindeki ads.txt, sunucuda render edilen içerik ve proxy tuzakları.

Approvalens ekibi

Şu rapor bulgularını düzeltir

  • İçerik JavaScript'e bağlı
  • Google ve ziyaretçi aynı içeriği görüyor
  • AdSense kodu ve meta etiketi
  • ads.txt dosyası
  • ads.txt içerik türü
  • Olmayan sayfalar 404 veriyor
  • robots.txt Googlebot'a izin veriyor
  • Çerez onay penceresi (CMP)

AdSense'in React'e ya da Next.js'e karşı bir kuralı yok. İncelemeci her sitede aynı şeylere bakıyor: gerçek içerik, menü, gizlilik politikası ve Google'ın açabildiği sayfalar. JavaScript framework'ünde değişen şey, bunları fark etmeden bozmanın ne kadar kolay olduğu. Sayfa tarayıcında kusursuz görünür, ama sunucunun gönderdiği HTML boş bir <div id="root"> olabilir, /ads.txt uygulamanın ana sayfasını döndürebilir ya da bir proxy Google'ın botunu giriş sayfasına yönlendirebilir.

Bu rehber yalnızca React ve Next.js'e özgü kısımları anlatıyor. Next.js 16 (App Router) dokümantasyonu ve Google'ın kendi sayfalarıyla kontrol edildi.

Önce sunucunun ne gönderdiğine bak

Google'ın JavaScript SEO rehberi, Googlebot'un sayfaları render kuyruğuna aldığını ve sayfanın bu kuyrukta birkaç saniye, bazen daha uzun kalabileceğini söylüyor. Yine de sunucu tarafında render'ı öneriyor: sunucuda ya da önceden render etmek "hâlâ iyi bir fikir", çünkü siteyi kullanıcılar ve botlar için hızlandırıyor ve "her bot JavaScript çalıştıramıyor" (JavaScript SEO temelleri).

AdSense botunun ayrı bir yardım sayfası var (AdSense tarayıcısı hakkında). Mediapartners-Google'ın sitene "içeriğini anlamak" için geldiğini anlatıyor ama JavaScript çalıştırıp çalıştırmadığı hakkında tek kelime yok. Onayını bu varsayıma bağlama. Yazının metni HTML'de olsun.

İki panel: solda HTML'inde yalnızca boş bir root div ve script etiketi olan istemci taraflı React sayfası, sağda başlığı ve paragrafları HTML'de hazır gelen sunucu render'lı Next.js sayfası
Botun, JavaScript çalışmadan önce aldığı yanıt. İçerik yalnızca sağdaki sayfada ilk yanıtta var.

Kendin kontrol et

Yazılarından birinin ortasından bir cümle seç ve ham HTML'de ara:

curl -s https://ornekblog.com/rehber/yazim | grep -c "yazının ortasından bir cümle"

Sonuç 0 ise metin yalnızca JavaScript ile ekleniyor demektir. Aynı testi Google'ın user agent'ıyla da yap, çünkü güvenlik duvarları ve bot korumaları botlara bazen başka bir sayfa gösteriyor:

curl -s -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://ornekblog.com/rehber/yazim | grep -c "yazının ortasından bir cümle"

Ücretsiz Googlebot erişim kontrolü aracı aynı karşılaştırmayı senin yerine yapıyor ve her botun aldığı durum kodunu gösteriyor.

Hangi kurulumlar riskli?

Kurulum İlk HTML'de ne var? AdSense incelemesi için risk
Next.js App Router, Server Components (varsayılan) Sayfanın tüm içeriği Düşük
Next.js, 'use client' bileşenleri İçerik yine var, çünkü Client Component'ler de sunucuda önceden render ediliyor (Next.js dokümanı) Düşük; veri yalnızca useEffect içinde çekilmiyorsa
Next.js statik dışa aktarım (output: 'export') Her sayfa için hazır .html dosyası Düşük; hosting 404.html'i 404 koduyla veriyorsa
Vite veya Create React App ile tek sayfalık uygulama (SPA) Boş bir root öğesi ve JS paketi Yüksek: metin ancak JavaScript'ten sonra geliyor
Herhangi bir framework, içerik useEffect ile çekiliyor Başlıklar ve iskelet var, yazı metni yok En önemli sayfalarda yüksek

Düz bir React SPA kullanıyorsan çözüm yapısal: sunucuda ya da build sırasında render eden bir yapıya geç (Next.js, React Router'ın framework modu, Astro) ya da yazı sayfalarını önceden render et. Meta etiketi eklemek botun aldığı yanıtı değiştirmez.

Soft 404: SPA'ların klasik sorunu

Tek sayfalık uygulamalar genellikle her adrese index.html ve 200 kodu döndürür, sonra JavaScript ile "Bulunamadı" yazar. Google buna soft 404 diyor ve iki yol öneriyor: gerçekten 404 dönen bir adrese yönlendirmek ya da hata görünümüne noindex eklemek (JavaScript SEO temelleri).

Next.js varsayılan olarak daha iyi davranıyor, ama dokümanda yazan bir istisna var: not-found sayfalarında Next.js "stream edilen yanıtlarda 200, stream edilmeyenlerde 404" döndürüyor (not-found.js). Bir route'ta loading.tsx varsa ve notFound() stream başladıktan sonra çağrılıyorsa, ziyaretçi "bulunamadı" ekranını 200 koduyla görür. Her route türünde uydurma bir adresi dene:

curl -s -o /dev/null -w "%{http_code}\n" https://ornekblog.com/rehber/boyle-bir-sayfa-yok

Görmek istediğin sonuç 404. Gerçek bir 404, AdSense'e de bunların reklam gösterilecek sayfalar olmadığını söyler. Google hata sayfalarında reklama izin vermiyor.

App Router'da AdSense kodu nereye konur?

AdSense, kodu sitenin " ve etiketleri arasına" yapıştırmanı ve "her sayfaya" koymanı öneriyor (kodun yeri). App Router'da her sayfayı kapsayan yer kök layout: app/layout.tsx, çok dilli sitelerde app/[locale]/layout.tsx. Üç seçeneğin var. Doğrulama için birini seç, hepsini üst üste koyma.

1. Metadata API ile doğrulama meta etiketi. Sahipliği kanıtlamanın en temiz yolu. Kök layout'taki statik metadata, <head> içine yazılıyor. Next.js'in other alanı her türlü özel meta etiketini basıyor (generateMetadata → other):

// app/layout.tsx
export const metadata = {
  other: { "google-adsense-account": "ca-pub-1234567890123456" },
};

Bunun için async generateMetadata değil, statik metadata nesnesini kullan. Next.js, generateMetadata sonucunu stream ediyor ve JavaScript çalıştıran botlar için <body> sonuna ekliyor (streaming metadata). Googlebot için sorun değil, ama doğrulama etiketinin yeri statik head.

2. AdSense script'i düz bir <script> etiketi olarak. App Router'ın kullandığı React 19, src ve async verilmiş bir <script>'i <head>'e taşıyabiliyor ve tekrarları ayıklıyor (react.dev: <script>):

// kök layout'un JSX'i içinde
<script
  async
  src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1234567890123456"
  crossOrigin="anonymous"
/>

3. next/script. Varsayılan strateji afterInteractive, script'i "sayfa kısmen hydrate olduktan sonra" yüklüyor. Etiketin <head>'e mi <body>'ye mi düştüğü dokümanda yazmıyor. beforeInteractive "her zaman head içine" ekleniyor, ama kök layout'ta durması gerekiyor ve sayfanın onsuz çalışamayacağı script'ler için düşünülmüş (next/script). worker stratejisini kullanma: dokümana göre "henüz App Router'da çalışmıyor". @next/third-parties paketinde AdSense bileşeni yok. Yalnızca Google Tag Manager, Analytics, Maps ve YouTube için yardımcılar var (üçüncü parti kütüphaneler).

Hangisini seçersen seç, sayfa kaynağına bak (DevTools'a değil): adsbygoogle.js adresi kendi ca-pub- numaranla bir kez görünmeli.

Bir Next.js App Router projesinin haritası: meta etiketi ve script ile app/layout.tsx, public/ads.txt, app/robots.ts, dosyaları atlayan matcher'lı proxy.ts ve 404 döndüren app/not-found.tsx
AdSense ile ilgili her parçanın App Router projesindeki yeri.

Reklam birimleri ve istemci tarafı gezinme

Otomatik reklamlar için site geneli script yeterli. Elle eklenen reklam birimleri için ayrıca <ins class="adsbygoogle"> öğesi ve push({}) çağrısı gerekiyor. Bunlar " ve etiketleri arasına" konuyor (reklam birimi kodu). React'te bu push genellikle bir Client Component'teki useEffect içine yazılıyor.

İki şeyi bil. React, geliştirme ortamında Strict Mode'da efektleri iki kez çalıştırır. next dev'de gördüğün çift push, canlıdaki sorunla aynı şey değil. Ayrıca Google, sayfa geçişlerinde belgenin yeniden yüklenmediği tek sayfalık uygulamalar için resmî bir AdSense rehberi yayımlamıyor. Onaydan önce işi basit tut: site geneli script (ya da otomatik reklamlar) yeterli. Elle birimleri sonra ekle ve her sayfa görüntülemesinde yeni bir <ins> öğesi oluştuğunu test et.

ads.txt /public klasöründe durur

Next.js'te robots.txt ve sitemap.xml için olduğu gibi bir ads.txt dosya kuralı yok. public/ads.txt adında düz bir dosya koyarsan /ads.txt adresinden sunulur. public içindeki dosyalara "kök adresten (/) başlayarak" ulaşılıyor (public klasörü). Next.js 16.3 ile yaptığımız denemede public içindeki bir .txt dosyası Content-Type: text/plain; charset=UTF-8 ile geldi.

Ortam değişkenlerinden dosyayı üreten Route Handler dahil adım adım anlatım Next.js'te ads.txt ekleme rehberinde.

robots.ts ve önizleme ortamları

App Router, robots.txt'yi app/robots.ts'den üretiyor (robots.txt). Sık görülen bir kalıp, bir ortam değişkenine bakıp staging'de her şeyi engellemek, canlıda her şeye izin vermek. Bu değişken canlıda tanımlı değilse site Disallow: / ile yayına çıkar. robots dosyasına dokunan her deploy'dan sonra gerçek alan adında https://ornekblog.com/robots.txt adresini aç ya da dosyayı robots.txt test aracına yapıştır.

// app/robots.ts
import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [{ userAgent: "*", allow: "/", disallow: ["/api/", "/hesap/"] }],
    sitemap: "https://ornekblog.com/sitemap.xml",
  };
}

Mediapartners-Google * grubunu yok sayıyor (Google'ın bot listesi). Yani oradaki bir Disallow AdSense botunu durdurmaz, ama Googlebot'u durdurur. Bunun neden yine de önemli olduğunu robots.txt rehberinde anlattık.

proxy.ts (eski adıyla middleware) siteni gizleyebilir

Next.js 16'da middleware'in adı proxy oldu. Dokümanı açıkça uyarıyor: matcher tanımlanmazsa Proxy, public/ klasöründeki dosyalar dahil "her istekte" çalışıyor (proxy.js). Onay sorunları tam da burada saklanıyor:

  • Çok dilli yönlendirme /ads.txt isteğini var olmayan /tr/ads.txt adresine gönderebilir.
  • Oturum kontrolü çerezi olmayan herkesi, botlar dahil, /giris sayfasına atabilir. AdSense, sitenin girişle korunuyorsa "botun ulaşabilmesi için girişi geçici olarak kaldırmayı" öneriyor (site hazır değil).
  • User agent'a göre bot engelleme Mediapartners-Google ya da Googlebot'u da yakalayabilir.

Resmî örnek robots.txt ve sitemap.xml'i matcher dışında bırakıyor. Uzantısı olan bütün dosyaları dışarıda bırakmak da yaygın bir yöntem:

// proxy.ts
export const config = {
  matcher: ["/((?!api|_next|.*\\..*).*)"],
};

AB, Birleşik Krallık ve İsviçre ziyaretçileri için onay

AEA, Birleşik Krallık ya da İsviçre'deki ziyaretçilere reklam gösteriyorsan Google, kendisinin sertifikaladığı ve IAB TCF ile entegre bir CMP kullanmanı istiyor (onay gereksinimleri). AdSense'teki Gizlilik ve mesajlaşma sekmesi bunlardan birini sunuyor. Next.js uygulamasında CMP'yi de AdSense script'i gibi kök layout'tan yükle ki ziyaretçinin açtığı ilk sayfada hazır olsun. Seçenekleri CMP rehberinde bulabilirsin.

Başvurudan önce Next.js kontrol listesi

  • Yazı metni ham HTML'de var (curl + grep buluyor)
  • Googlebot user agent'ı tarayıcıyla aynı sayfayı alıyor
  • Uydurma adresler, loading.tsx olan route'larda bile 404 dönüyor
  • Kök layout'ta tek doğrulama yöntemi var: meta etiketi ya da bir kez adsbygoogle.js
  • public/ads.txt kök alan adında 200 ve düz metin dönüyor
  • Canlı alan adındaki robots.txt'de * ya da Googlebot için Disallow: / yok
  • proxy.ts matcher'ı ads.txt, robots.txt ve diğer dosyaları atlıyor
  • İçeriğin önünde giriş duvarı yok
  • Gizlilik politikası, hakkımızda ve iletişim sayfaları layout'tan linkli
  • AEA, Birleşik Krallık veya İsviçre trafiği varsa sertifikalı CMP

Yayındaki siteyi tara

Yerel build, hosting'in, CDN'in ve proxy'nin gerçek isteklere ne yaptığını söyleyemez. Ücretsiz Approvalens taramasını canlı alan adında çalıştır. Ham ve render edilmiş metni karşılaştırıyor, ads.txt ile robots.txt'yi Google'ın aldığı gibi çekiyor, giriş duvarlarını ve soft 404'leri işaretliyor.

SSS

İstemci tarafında çalışan bir React uygulaması AdSense onayı alabilir mi?

AdSense kurallarında bunu yasaklayan bir madde yok, ama incelemecinin ve botların içeriğini görmesi gerekiyor. Tamamen istemci tarafında çalışan bir uygulamada bu, JavaScript render'ına bağlı kalıyor ve Google AdSense botunun JavaScript çalıştırdığını söylemiyor. Sunucu tarafı render ya da ön render bu belirsizliği ortadan kaldırır.

AdSense için @next/third-parties gerekli mi?

Hayır. Pakette AdSense bileşeni yok. Kök layout'ta düz bir <script> de next/script de iş görür.

ads.txt Route Handler mı olsun, statik dosya mı?

En basiti public içindeki statik dosya. İçeriğin deploy'a göre değişmesi gerekiyorsa, örneğin ortam değişkenlerinden geliyorsa Route Handler kullan.

Sitem Vercel'de. Hangi alan adını başvuruya yazmalıyım?

Kendi alan adını, yani canonical etiketlerinde yazan adresi. Ziyaretçinin gerçekten açtığı sürümü (www'li ya da www'siz) gönder, diğerini ona yönlendir.

Eskimiş ya da yanlış bir şey mi gördün? Bize yaz, düzeltelim.

Bu rehberi İngilizce oku →

Kendi sitende kontrol et. Ücretsiz, kayıt yok.

Bunun için ücretsiz araçlar

Ücretsiz tarama

Kendi siteni kontrol et

Ücretsiz tarama: uygunluk puanı ve tüm sorunlar, genelde birkaç dakikada.

Ücretsiz tarama · puan ve bulunan tüm sorunlar · üyelik yok

Tüm rehberler →