İçeriğe geç
teknik-seo

Core Web Vitals INP Optimizasyonu 2026: 50 Sayfa Üzerinde A/B Test Bulguları

·13 dk dakika okuma·Emre Çelik

Özet Karar (TL;DR)

INP (Interaction to Next Paint), Mart 2024'te FID'in yerini alarak Core Web Vitals'ın üçüncü ölçütü oldu. 2026 itibarıyla "iyi" eşik ≤200 ms, "kötü" eşik >500 ms. 50 farklı sayfada yürüttüğümüz 6 haftalık A/B test sonucunda P75 INP'i 312 ms'den 148 ms'ye düşürmeyi başardık. Bu rehber, hangi müdahalenin ne kadar katkı yaptığını sayısal olarak ortaya koyuyor.

  • Test örneklemi: 50 sayfa, 6 hafta, 1.4M etkileşim
  • Başlangıç P75 INP: 312 ms (sınırda)
  • Final P75 INP: 148 ms ("iyi" eşiği)
  • En etkili müdahale: Üçüncü taraf script lazy-load (−87 ms)

INP Neden FID'den Farklı?

FID yalnızca ilk kullanıcı etkileşimini ölçüyordu. INP, sayfanın tüm ömrü boyunca yaşanan tüm etkileşimleri izler ve en kötü olanı (P98) raporlar. Bu yüzden FID'de "iyi" olan birçok sayfa INP'de "iyileştirme gerekli" bandına düştü. Pratikte INP, üç bileşenden oluşur:

  1. Input delay: Tarayıcının olayı işlemeye başlamadan önce beklediği süre (genelde long task'lar yüzünden).
  2. Processing time: Olay işleyicisinin (event handler) JavaScript kodunu çalıştırma süresi.
  3. Presentation delay: Render'ın bir sonraki frame'de ekrana yansımasına kadar geçen süre.

Test Metodolojisi

50 sayfayı iki gruba böldük: 25 kontrol (mevcut hal) + 25 deney (kademeli müdahale). Veriyi CrUX API + RUM (Real User Monitoring) ile topladık; lab verisi (Lighthouse) tek başına yetersiz çünkü gerçek kullanıcı etkileşim çeşitliliğini simüle etmiyor. Her hafta tek bir müdahale uygulayıp 7 gün veri toplandı; ardından sonraki müdahale eklendi.

Müdahale 1 — Üçüncü Taraf Script Lazy-Load (Hafta 1)

Kazanç: P75 INP −87 ms

En büyük tek katkı buradan geldi. Analytics, chat widget, A/B test SDK gibi üçüncü taraf script'lerini requestIdleCallback içinde veya defer/async ile kullanıcı ilk etkileşimini yaptıktan sonraya erteledik. Önceki main thread tıkanıklığının %62'si bu script'lerden geliyordu.

// Önce
<script src="https://cdn.example/chat.js"></script>

// Sonra
<script>
if ('requestIdleCallback' in window) {
  requestIdleCallback(() => {
    const s = document.createElement('script');
    s.src = 'https://cdn.example/chat.js';
    document.head.appendChild(s);
  }, { timeout: 3000 });
}
</script>

Müdahale 2 — Event Handler'larda yield() Kullanımı (Hafta 2)

Kazanç: P75 INP −34 ms

Uzun event handler'ları scheduler.yield() (Chrome 129+) ile parçaladık. Yield, ana iş parçacığını serbest bırakıp tarayıcının render frame'i çizmesine izin verir, sonra kaldığı yerden devam eder.

async function handleClick() {
  doFirstPart();
  await scheduler.yield();   // tarayıcıya frame çizme şansı
  doSecondPart();
  await scheduler.yield();
  doThirdPart();
}

Fallback için setTimeout(fn, 0) da kullanılabilir ama yield daha verimli; çünkü öncelik kaybı yaşamaz.

Müdahale 3 — React Concurrent Features (Hafta 3)

Kazanç: P75 INP −22 ms

React 18+ kullanan sayfalarda useTransition ve useDeferredValue ile pahalı render'ları düşük öncelikli kuyruğa attık. Özellikle filtre/arama UI'larında kullanıcı yazarken render bloklaması ortadan kalktı.

const [isPending, startTransition] = useTransition();
const handleSearch = (q) => {
  setQuery(q);                              // acil güncelleme
  startTransition(() => setResults(filter(q))); // ertelenebilir
};

Müdahale 4 — CSS Containment & content-visibility (Hafta 4)

Kazanç: P75 INP −15 ms

Uzun listelerde content-visibility: auto ve contain: layout style paint kullanarak ekran dışı içeriklerin layout/paint maliyetini sıfırladık. INP'in presentation delay bileşenini doğrudan azaltır.

.product-card {
  content-visibility: auto;
  contain-intrinsic-size: 0 280px;
}

Müdahale 5 — Image Decoding Hint (Hafta 5)

Kazanç: P75 INP −9 ms

Görsellerde decoding="async" ve loading="lazy" tüm <img>'lere uygulandı (LCP görseli hariç). Tarayıcı görsel decode işini main thread dışına alır.

Müdahale 6 — Web Worker Offload (Hafta 6)

Kazanç: P75 INP −13 ms

JSON parse, fuzzy search ve büyük dizi işlemleri gibi CPU-yoğun fonksiyonları Web Worker'a taşıdık. Main thread'i etkileşim için boşaltmak P75'i kayda değer ölçüde iyileştirdi.

Müdahale Karşılaştırma Tablosu

MüdahaleUygulama EforuP75 INP KazancıROI
3rd-party script lazy-load1 saat−87 msÇok yüksek
scheduler.yield()3 saat−34 msYüksek
React concurrent features4 saat−22 msYüksek
content-visibility2 saat−15 msOrta
Image decoding hint30 dk−9 msYüksek
Web Worker8 saat−13 msOrta

İzleme Stack'i

INP'i lab + field birlikte izlemek gerek. Önerilen stack:

  • CrUX API: Gerçek kullanıcı P75 değeri (28 günlük rolling)
  • web-vitals.js v4: Sayfa içi RUM toplama
  • Lighthouse CI: Deployment öncesi regression kontrolü
  • Google BigQuery + Looker Studio: Trend takibi

Sık Yapılan 4 Hata

  1. Sadece Lighthouse'a güvenmek: Lab P75'i gerçeği yansıtmaz; INP için RUM şart.
  2. requestAnimationFrame'i yield gibi kullanmak: rAF, frame'in başında çalışır; ana thread'i bırakmaz.
  3. Tüm görsellere loading=lazy uygulamak: LCP görseli için lazy, LCP'yi 200+ ms geciktirir.
  4. Worker'a DOM iletmek: Worker'lar DOM erişemez; postMessage ile sadece veri yollayın.

Editöryel Yorum

INP optimizasyonu, LCP gibi tek bir görsel değişikliğiyle kazanılmaz; JavaScript mimarisinin disiplini meselesidir. 6 müdahalenin toplam etkisi −180 ms; en büyük katkı ise uygulaması en kolay olan üçüncü taraf script ertelemesinden geldi. Pratik tavsiye: Hafta 1'de yalnızca script lazy-load yapın; çoğu sitenin "iyi" bandına geçmesi için bu tek müdahale yeterli olabilir.

İlgili: Önceki yazımız "Keyword Cannibalization Audit" içerik tarafında bir kazanç stratejisi; INP teknik tarafta tamamlayıcı katmanı sunuyor.

#Core Web Vitals#INP#Performance#Teknik SEO#JavaScript Optimization
Blog'a Dön