Mert Özen Her Satırda Daha İleri
SEO ve GEO Teknik SEO — #03

noindex ve X-Robots-Tag: Bir Sayfayı veya PDF'i Index'ten Doğru Şekilde Çıkarmak

Mert Özen 8 Kas 2026 11 dk 1 görüntülenme
noindex ve X-Robots-Tag: Bir Sayfayı veya PDF'i Index'ten Doğru Şekilde Çıkarmak

Bir sayfayı veya PDF'i index'ten çıkarmanın yolu noindex'tir, robots.txt değil: engellenmiş URL'deki noindex hiç görülmez, Removals aracı ise yalnız altı ay kadar gizler. ASP.NET Core'da X-Robots-Tag middleware'i kuruyor, static file sıralama hatasını, Angular'da JavaScript ile eklenen noindex'in riskini ve server route header'ını gerçek çıktılarla görüyoruz.

Sürüm notu: Bu yazıdaki kodlar .NET 10 (ASP.NET Core 10) ve Angular 22.2 ile derlenip denenmiştir; kurallar Google'ın robots meta tag dokümanının Kasım 2026 hâli esas alınarak anlatılmıştır.

Önce Tahmin Et

Bookstore 2024 kataloğunu PDF olarak /uploads/catalog-2024.pdf adresinde yayımlamıştı. Fiyatlar eskidi ama PDF hâlâ Google'da çıkıyor ve müşteriler eski fiyatla sipariş vermeye çalışıyor. Ekip iki şey yapıyor: robots.txt'ye Disallow: /uploads/ ekliyor ve Search Console'un Removals aracından URL (Uniform Resource Locator) için kaldırma isteği gönderiyor. Ertesi gün PDF sonuçlardan kayboluyor; ekip işi kapatıyor.

Altı ay sonra PDF'in durumu ne olur? Ve aynı ekip Angular uygulamasındaki hesap sayfasını index dışında tutmak için noindex meta tag'ini component'in constructor'ında JavaScript ile ekliyorsa, Google bu tag'i görür mü?

Serinin önceki yazısında robots.txt'nin crawl'ı engellediğini ama index'i engellemediğini görmüştük. Bu yazı index tarafının aracı: robots meta tag'i ve onun HTTP (HyperText Transfer Protocol) header'ı karşılığı X-Robots-Tag.

İki Yol, Aynı Kurallar

Bir sayfanın index'te nasıl görüneceğini sayfa bazında iki yerden söyleyebilirsin. HTML (HyperText Markup Language) sayfalar için <head> içinde bir meta tag:

<meta name="robots" content="noindex, follow">
<meta name="googlebot" content="max-snippet:120">

Ya da yanıtın kendisinde bir HTTP header'ı:

X-Robots-Tag: noindex
X-Robots-Tag: googlebot: max-snippet:120

Meta tag'deki her kural header olarak da gönderilebilir. Header'ın iki avantajı var: HTML olmayan dosyalarda (PDF, görsel, video) tek yol odur ve sayfanın içeriğine dokunmadan sunucu tarafında, merkezi olarak uygulanabilir. Google header'da birden fazla X-Robots-Tag satırını da, virgülle ayrılmış listeyi de kabul ediyor; bir kuralın önüne crawler adı yazarak (googlebot: nofollow) yalnız o crawler'ı hedefleyebiliyorsun. Meta tag'de name değeri olarak Google yalnız robots, googlebot ve googlebot-news'ü tanıyor.

Meta tag'in yeri konusunda Mart 2026'da dokümana bir not eklendi; davranış değişmedi, yalnız yazılı hâle geldi: Google robots meta tag'ini <head> dışında, örneğin <body> içinde bulsa da dikkate alıyor. Bu iyi haber gibi görünse de aslında bir uyarı: bir CMS (Content Management System) editörünün yazı gövdesine yapıştırdığı bir <meta name="robots" content="noindex"> sayfayı index'ten çıkarabilir. Kullanıcı içeriğini HTML olarak basıyorsan, meta tag'leri sanitize etmeyi listene ekle.

Kurallar ve Ne Yaptıkları

Google'ın desteklediği kuralların özeti:

KuralEtkisi
noindexSayfa veya dosya sonuçlarda gösterilmez
nofollowSayfadaki link'ler takip edilmez
nonenoindex, nofollow ile aynı
nosnippetMetin snippet'i ve video önizlemesi yok; içerik Google'ın AI (Artificial Intelligence) özelliklerine (AI Overviews, AI Mode) doğrudan girdi olarak da kullanılmaz
max-snippet:[sayı]Snippet en fazla bu kadar karakter; 0 = nosnippet, -1 = sınır yok
max-image-preview:[none|standard|large]Görsel önizlemenin en büyük boyutu
noimageindexSayfadaki görseller index'lenmez
unavailable_after:[tarih]Bu tarihten sonra sayfa sonuçlarda gösterilmez
indexifembeddedYalnız noindex ile birlikte: içerik iframe ile gömüldüğünde index'lenebilir

Birkaç ayrıntı. all ve index, follow varsayılan davranıştır; yazmanın bir etkisi yok. noarchive ve nocache Google Search'te artık yok sayılıyor. Kurallar çeliştiğinde daha kısıtlayıcı olan kazanıyor: nosnippet ile max-snippet:50 birlikteyse snippet hiç çıkmaz. Farklı crawler'lara farklı kurallar verirsen Googlebot için negatif kuralların toplamı geçerli olur: genel bir nofollow ile Googlebot'a özel bir noindex, Googlebot için noindex, nofollow demektir. unavailable_after için tarih RFC (Request for Comments) 822, RFC 850 veya ISO (International Organization for Standardization) 8601 biçiminde verilebilir; o tarihten sonra Google sayfayı daha seyrek crawl ediyor.

nosnippet'in AI Overviews ve AI Mode'u da kapsaması, generative AI özelliklerinden çıkmanın sayfa düzeyindeki yolu. Bunun GEO (Generative Engine Optimization) açısından bedelini ve alternatiflerini GEO serisinde ele alıyoruz; burada yalnız mekanizmayı not et.

ASP.NET Core'da X-Robots-Tag Middleware'i

Bookstore'da üç kural var: /uploads altındaki PDF'ler index'lenmeyecek, site içi arama sonuçları index'lenmeyecek ama sonuçlardaki link'ler takip edilecek, Black Friday kampanya sayfası 1 Aralık'tan sonra sonuçlardan düşecek ve Googlebot için snippet'i 120 karakterle sınırlanacak. Kuralları tek bir middleware'de toplamak, her endpoint'e ayrı ayrı header eklemekten daha kolay denetlenir:

namespace Bookstore.Noindex;

public sealed class RobotsHeaderMiddleware(RequestDelegate next)
{
    public Task InvokeAsync(HttpContext context)
    {
        // header'lar body'nin ilk byte'ı yazılmadan önce eklenmeli
        context.Response.OnStarting(() =>
        {
            foreach (string rule in RulesFor(context.Request.Path))
                context.Response.Headers.Append("X-Robots-Tag", rule);
            return Task.CompletedTask;
        });
        return next(context);
    }

    private static IEnumerable<string> RulesFor(PathString path)
    {
        if (path.StartsWithSegments("/uploads") && path.Value!.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
            yield return "noindex";
        if (path.StartsWithSegments("/search"))
            yield return "noindex, follow";
        if (path.StartsWithSegments("/campaigns/black-friday"))
        {
            yield return "unavailable_after: 2026-12-01T00:00:00+03:00";
            yield return "googlebot: max-snippet:120";
        }
    }
}
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
WebApplication app = builder.Build();

app.UseMiddleware<RobotsHeaderMiddleware>(); // static file'lardan önce: PDF'leri de kapsar
app.UseStaticFiles();

app.MapGet("/search", (string? q) => Results.Content($"<h1>Results for {q}</h1>", "text/html"));
app.MapGet("/campaigns/black-friday", () => Results.Content("<h1>Black Friday</h1>", "text/html"));
app.MapGet("/books/{slug}", (string slug) => Results.Content($"<h1>{slug}</h1>", "text/html"));
app.Run();

OnStarting kullanmamın nedeni, header'ı endpoint'in yanıtı yazmaya başlamasından hemen önce eklemek: bu sayede hem static file middleware'inin servis ettiği PDF'ler hem de endpoint'lerin ürettiği HTML aynı kuraldan geçiyor. Gerçek yanıtlar:

$ curl -s -D - -o /dev/null http://localhost:20104/uploads/catalog-2024.pdf
HTTP/1.1 200 OK
Content-Type: application/pdf
X-Robots-Tag: noindex
$ curl -s -D - -o /dev/null http://localhost:20104/search?q=dune
HTTP/1.1 200 OK
Content-Type: text/html
X-Robots-Tag: noindex, follow
$ curl -s -D - -o /dev/null http://localhost:20104/campaigns/black-friday
HTTP/1.1 200 OK
Content-Type: text/html
X-Robots-Tag: unavailable_after: 2026-12-01T00:00:00+03:00
X-Robots-Tag: googlebot: max-snippet:120
$ curl -s -D - -o /dev/null http://localhost:20104/books/dune
HTTP/1.1 200 OK
Content-Type: text/html

Kitap sayfasında header yok, çünkü index'lenmesini istiyoruz; varsayılan davranış için kural yazmaya gerek yok. Kampanya sayfasındaki iki ayrı header satırı, iki farklı hedefe iki ayrı kural vermenin okunur yolu.

Sıralama Hatası: Static File Middleware'i Header'ı Yutuyor

Aynı middleware'i UseStaticFiles()'tan sonraya taşıdığımda yanıtlar şöyle değişti:

$ curl -s -D - -o /dev/null http://localhost:20104/uploads/catalog-2024.pdf
HTTP/1.1 200 OK
Content-Type: application/pdf
$ curl -s -D - -o /dev/null http://localhost:20104/search?q=dune
HTTP/1.1 200 OK
Content-Type: text/html
X-Robots-Tag: noindex, follow

Arama sayfası hâlâ doğru, ama PDF'in header'ı kayboldu. Static file middleware'i dosyayı bulduğunda yanıtı kendisi yazıp pipeline'ı orada kısa devre ediyor; arkasındaki middleware hiç çalışmıyor. Bu tür bir hatayı test olmadan fark etmek zor: sayfalar çalışıyor, yalnız bir header eksik. Middleware sıralamasının mantığı ASP.NET Core Web API (Application Programming Interface) serisinin "ASP.NET Core Middleware Pipeline: Sıralama, Use, Run, Map ve Kendi Middleware'in" yazısında. Alternatif olarak yalnız static dosyalar için StaticFileOptions.OnPrepareResponse callback'inde de header eklenebilir; ama kuralların iki yere bölünmesi, birini güncelleyip diğerini unutmaya davetiye.

robots.txt ve noindex Birlikte Çalışmaz

Açılıştaki ekibin ilk hatası buydu. robots.txt'ye Disallow: /uploads/ eklendiği anda Googlebot PDF'i istemeyi bırakıyor; istemediği yanıtın header'ını da göremiyor. Google dokümanı bunu açıkça söylüyor: robots meta tag'leri ve X-Robots-Tag yalnız URL crawl edildiğinde bulunur; crawl'ı engellenmiş bir URL'deki kurallar yok sayılır. Yani engellenmiş bir URL için noindex hiç işlemez ve URL, başka sitelerden link aldıkça içeriksiz bir kayıt olarak index'te kalabilir.

Doğru sıra şu: önce noindex ver ve URL'yi crawl'a açık bırak. Google URL'yi tekrar crawl edip noindex'i görsün ve sonuçlardan düşürsün. Ancak bundan sonra, istersen, crawl'ı robots.txt ile engelle. Bunun bir de crawl budget yüzü var: Google, noindex'li sayfaların da istenmesi gerektiğini, dolayısıyla noindex'in crawl'ı azaltmadığını belirtiyor. Crawl budget'ı serinin on birinci yazısında ele alıyoruz.

Ekibin ikinci hatası Removals aracı. Search Console yardım sayfasına göre başarılı bir geçici kaldırma isteği yalnızca altı ay kadar sürüyor ve URL'yi index'ten silmiyor, sonuçlarda gizliyor. Kalıcı çözüm sayfanın kendisinde: içeriği kaldırıp 404 veya 410 dönmek, erişimi parolayla kısıtlamak ya da noindex vermek. Açılıştaki sorunun cevabı bu yüzden "altı ay sonra PDF büyük ihtimalle geri döner": hem kaldırma süresi dolmuş, hem de robots.txt yüzünden noindex verilse bile görülemiyor olur. Removals aracı acil durumlar için (yanlışlıkla yayımlanmış kişisel veri gibi) zaman kazandırır; çözümün kendisi değildir.

Bookstore için doğru akış: eski kataloğun artık hiç gerekmediği netse dosyayı silip 404 veya 410 dön (Google ikisini aynı şekilde işliyor; ayrıntısı serinin altıncı yazısında). Dosya müşteri arşivi için yerinde kalacaksa X-Robots-Tag ile noindex ver ve robots.txt'den /uploads/ engelini kaldır.

JavaScript ile noindex: Angular'da Doğru Yer

Google Aralık 2025'te JavaScript SEO (Search Engine Optimization) dokümanına iki not ekledi. Birincisi, JavaScript ile robots meta tag'i eklemek veya değiştirmek mümkün, ama Google noindex gördüğünde render'ı ve JavaScript çalıştırmayı atlayabilir; bu yüzden sayfanın index'lenmesini istiyorsan orijinal HTML'de noindex olmamalı. İkincisi, Google JavaScript ile eklenen noindex'in nasıl işleneceğini tanımlamıyor. Yani JavaScript'le noindex kaldırmak güvenilmez, eklemek de garanti değil.

Bookstore'un Angular uygulamasında hesap sayfası RenderMode.Client ile çalışıyor; sunucu yalnız boş bir kabuk HTML gönderiyor. Component noindex'i constructor'da ekliyor:

@Component({
  selector: 'app-account',
  template: `<h1>My account</h1><p>Orders and wishlist.</p>`,
})
export class Account {
  constructor() {
    // yalnız tarayıcıda çalışır: bu route RenderMode.Client
    inject(SeoService).update({ title: 'My account', description: '', path: '/account', noindex: true });
  }
}

Sunucunun gönderdiği HTML'de bu tag yok; yalnız tarayıcı JavaScript'i çalıştırınca ortaya çıkıyor. Google'ın davranışını tanımlamadığı bölge tam burası. Çözüm, kuralı sunucunun gönderdiği yanıta taşımak. Angular'ın server route'ları render modundan bağımsız olarak header verebiliyor:

{ path: 'account', renderMode: RenderMode.Client, headers: { 'X-Robots-Tag': 'noindex' } },
$ curl -s -D - -o acc.html http://localhost:20110/account | grep -iE "^HTTP|^x-robots|^content-type"
HTTP/1.1 200 OK
content-type: text/html;charset=UTF-8
x-robots-tag: noindex
$ grep -o '<meta name="robots"[^>]*>\|<title>[^<]*</title>' acc.html
<title>BookstoreNg</title>

HTML'de robots meta tag'i yok ve başlık hâlâ uygulamanın varsayılanı; ama header ilk yanıtta orada. SSR (Server-Side Rendering) ile çalışan arama sayfasında ise SeoService'in eklediği tag, sunucuda render edildiği için ilk HTML'in içinde geliyor:

$ curl -s "http://localhost:20110/search?q=dun" | grep -o '<meta name="robots"[^>]*>'
<meta name="robots" content="noindex">

Kural: index kararını etkileyen her şey (noindex, canonical, status code) ilk HTML'de veya HTTP yanıtında olmalı. Render modlarını ve server route'ları serinin dokuzuncu yazısında ayrıntılı kuracağız.

mertozen.com'da robots Meta Tag'i

Bu sitenin kaynak kodunda robots meta tag'i tek bir partial view'dan basılıyor. Varsayılan değer index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1. İlk iki kural varsayılan davranışı tekrar ediyor, yani etkisiz; kalan üçü ise snippet uzunluğunu ve görsel/video önizlemesini sınırsız bırakmayı açıkça söylüyor. Sitenin AI özelliklerinde alıntılanma tercihiyle tutarlı bir seçim.

404 sayfası ve beklenmeyen hata sayfası bu değeri noindex, follow ile eziyor: sayfa index'lenmesin ama üzerindeki ana sayfa ve blog link'leri takip edilsin. 404 sayfası zaten gerçek 404 status code'uyla döndüğü için (sitede UseStatusCodePagesWithReExecute("/404") kullanılıyor) Google içeriğini işlemiyor; noindex burada ikinci bir emniyet. CMS geçici olarak yanıt veremediğinde dönen 503 sayfası da kendi içinde noindex taşıyor. Blog listesindeki site içi arama (?q=) ise noindex almıyor, onun yerine canonical'ı arama terimi atılmış liste adresine işaret ediyor; bu da geçerli bir tercih, canonical ile noindex'in farkını serinin beşinci yazısında tartışıyoruz.

Üretimde Dikkat

X-Robots-Tag kurallarını test et. Header'lar görünmez; bir sayfa yanlışlıkla noindex alırsa site çalışmaya devam eder, yalnız trafik yavaş yavaş düşer. Integration test'te kritik URL'lerin (ana sayfa, kitap sayfaları) X-Robots-Tag taşımadığını, PDF'lerin ve arama sayfalarının taşıdığını assert et.

Staging'deki noindex'in production'a sızmasına dikkat. Environment'a göre her sayfaya noindex veren bir kural, environment adı yanlış ayarlanmış bir deploy'da production'ı index'ten çıkarır. Bu senaryo, staging'i noindex yerine authentication ile korumanın bir başka nedeni.

Search Console'un URL Inspection aracı, Google'ın bir URL için gördüğü robots kurallarını ve index durumunu gösteriyor; "Sayfalar" raporundaki "Excluded by 'noindex' tag" satırı ise noindex'li URL'lerin listesi. Bu listede görmemen gereken bir URL varsa sorun genelde bir şablondadır. Search Console'a giriş SEO Temelleri serisinde.

CDN (Content Delivery Network) ve reverse proxy katmanlarının header'ları korumasını kontrol et. Bazı katmanlar bilinmeyen header'ları atabilir veya cache'lenmiş eski bir yanıtı header'sız servis edebilir. Testi uygulamanın önündeki gerçek adrese karşı yap, Kestrel'e değil.

Sık Düşülen Tuzaklar

robots.txt ile engellenmiş bir sayfaya noindex koymak. İkisi birbirini iptal eder; noindex hiç görülmez.

Removals aracını kalıcı çözüm sanmak. Kaldırma yaklaşık altı ay sürer; sayfanın kendisinde 404, 410, parola veya noindex yoksa URL geri gelir.

Index'lenmesi istenen sayfanın ilk HTML'ine noindex koyup JavaScript ile kaldırmak. Google noindex'i görünce render'ı atlayabilir; JavaScript hiç çalışmayabilir.

PDF için meta tag aramak. PDF'in <head>'i yok; tek yol X-Robots-Tag.

Middleware'i UseStaticFiles()'tan sonra kaydetmek. Static dosyalar kuralları hiç görmez.

Sayfayı noindex yapıp canonical'ını başka bir sayfaya vermek. İki sinyal çelişir: biri "bu sayfayı index'leme", diğeri "bu sayfa şunun kopyası" der. Hangisini istediğine karar ver; ayrıntısı canonical yazısında.

Küçük Bir Deneme

★☆☆ Kendi sitende üç URL'nin (bir sayfa, bir PDF, bir arama sonucu) robots meta tag'ini ve X-Robots-Tag header'ını curl -s -D - -o /dev/null ile kontrol et. Index'lenmesini istemediğin bir şey header'sız mı çıkıyor?

★★☆ RobotsHeaderMiddleware'e response status code'una bakan bir kural ekle: 4xx ve 5xx yanıtlara noindex header'ı versin. Bunun 404 sayfası için ne kadar gerekli olduğunu, Google'ın 4xx içeriğini zaten işlemediği bilgisiyle birlikte tartış.

★★★ WebApplicationFactory ile bir test sınıfı yaz: bir URL listesi ve her biri için beklenen X-Robots-Tag değerlerini (veya yokluğunu) tablo olarak tut, test her URL'yi isteyip header'ları karşılaştırsın. Ardından middleware'i UseStaticFiles()'tan sonraya taşı ve testin PDF satırında kırıldığını gör.

Index'ten çıkarmak bir taraf; index'e sokmak istediğin URL'leri Google'a bildirmek diğer taraf. Bir sonraki yazıda XML (Extensible Markup Language) sitemap'in protokol sınırlarını, Google'ın lastmod'u ne zaman ciddiye aldığını, ASP.NET Core'da EF (Entity Framework) Core'dan streaming sitemap üretmeyi ve Bing ile Yandex'e değişikliği anında bildiren IndexNow'u kodla göreceğiz.