← Blog'a Dön
INP Nedir? Interaction to Next Paint Optimizasyon Rehberi
Core Web Vitals 26 dk okuma Yayın: Güncelleme:

INP Nedir? Interaction to Next Paint Optimizasyon Rehberi

INP (Interaction to Next Paint) nedir? FID'in yerini alan yeni Core Web Vitals metriği, 200ms eşiği, uzun görevler, JavaScript optimizasyonu ve INP iyileştirme teknikleri.

2024 yılının Mart ayında Google, Core Web Vitals ailesinde sessiz ama son derece önemli bir değişiklik yaptı: FID (First Input Delay) metriği emekliye ayrıldı ve yerini INP (Interaction to Next Paint) aldı. Bu değişiklik yalnızca bir metriğin yerini başka bir metriğin almasından ibaret değil. INP, kullanıcı etkileşim kalitesini ölçmenin çok daha kapsamlı ve gerçekçi bir yolu olarak tasarlandı.

Peki INP tam olarak ne ölçüyor? FID’den neden daha iyi? Sitenizin INP puanı neden yüksek olabilir ve bunu düzeltmek için ne yapabilirsiniz?

Bu rehberde INP’yi temelden ele alacak, teknik mekanizmasını açıklayacak, performansı etkileyen nedenleri inceleyecek ve JavaScript optimizasyon tekniklerinden araç seçimine kadar geniş bir yelpazede pratik çözümler sunacağız. Core Web Vitals hakkında genel bir bakış için bu rehbere göz atabilirsiniz.


INP Nedir?

INP (Interaction to Next Paint), bir kullanıcı web sayfasıyla etkileşime girdiğinde — tıklama, dokunma veya klavye tuşuna basma — tarayıcının bu etkileşime yanıt olarak ekranı ne kadar sürede güncellediğini ölçen bir performans metriğidir.

Daha açık bir ifadeyle: Kullanıcı bir butona tıkladığında, tarayıcının o tıklamayı işlemesi ve görsel bir geri bildirim üretmesi arasında geçen süre INP’yi belirler. Bu süre ne kadar kısaysa, site o kadar “duyarlı” hissettiriri.

INP, bir sayfayı ziyaret süresince gerçekleşen tüm etkileşimlerin gecikmelerini toplar ve genel olarak en yüksek gecikmeyi (bazı aykırı değerler hariç) temsil eden bir puan üretir. Yani tek bir kötü etkileşim bile genel puanı olumsuz etkileyebilir.

INP’nin Temel Özellikleri

  • Yalnızca tıklama, dokunma ve klavye girdilerini ölçer (kaydırma ve yakınlaştırma dahil değildir)
  • Sayfa ömrü boyunca tüm etkileşimleri izler
  • Tek bir gecikme değeri değil, ziyaret süresindeki en yüksek gecikmeyi temsil eden bir skor üretir
  • Gerçek kullanıcı verileri (RUM — Real User Monitoring) üzerinden değerlendirilir
  • Chrome Kullanıcı Deneyimi Raporu (CrUX) aracılığıyla sahadan elde edilir

FID ile INP Arasındaki Temel Fark

FID (First Input Delay) yıllarca kullanıcı etkileşim duyarlılığını temsil eden metrik olarak kullanıldı. Ancak ciddi bir kısıtı vardı: yalnızca sayfadaki ilk etkileşimi ölçüyordu ve yalnızca input delay (giriş gecikmesi) kısmını kapsıyordu.

Bu yaklaşım, gerçek dünya kullanıcı deneyimini yeterince yansıtmıyordu. Bir kullanıcı sayfaya girip ilk tıklamasını yaptığında site hızlı görünebilir; ama sayfa boyunca onlarca etkileşim gerçekleştirdiğinde birkaç kötü an tüm deneyimi mahvedebilir. FID bu durumu hiç yakalamıyordu.

Karşılaştırma Tablosu

ÖzellikFIDINP
Ölçülen etkileşimYalnızca ilkTüm etkileşimler
Ölçülen bileşenYalnızca input delayInput delay + processing + presentation
Temsil edilen değerİlk gecikmeEn yüksek gecikme (p98)
DurumEmekli (Mart 2024)Aktif Core Web Vitals metriği
İyi eşiği<100ms<200ms
Kötü eşiği>300ms>500ms

FID’in yalnızca ilk etkileşimi ölçmesi, bazı sitelerin gerçekte yavaş bir etkileşim deneyimi sunmalarına karşın iyi FID puanları almasına yol açıyordu. INP bu açığı kapatarak kullanıcı deneyiminin çok daha doğru bir temsilini sunuyor.


INP Nasıl Hesaplanır?

INP’nin hesaplanması üç ayrı bileşenden oluşur. Bu üç bileşenin toplamı, tek bir etkileşim için INP değerini verir.

1. Input Delay (Giriş Gecikmesi)

Kullanıcı bir etkileşim başlattığında, tarayıcı bu girdiyi hemen işleyemeyebilir. Ana iş parçacığı (main thread) başka bir görevle meşgulse, giriş olayı kuyruğa girer ve bekler. Bu bekleme süresi input delay’dir.

Örneğin bir analytics scripti tam o an 300 ms’lik ağır bir hesaplama yapıyorsa ve siz bu süre içinde bir butona tıklarsanız, tarayıcı tıklamayı ancak bu görev bitince algılayabilir. Bu 300 ms doğrudan input delay olarak INP puanınıza yansır.

2. Processing Time (İşleme Süresi)

Tarayıcı girişi algıladıktan sonra, bu girişe bağlı olay dinleyicilerini (event listeners) çalıştırır. onclick, onkeydown, onpointerdown gibi handler’ların tamamı bu aşamada yürütülür. Handler’lar ne kadar yavaşsa, processing time o kadar artar.

Ağır DOM manipülasyonları, senkron AJAX çağrıları veya karmaşık hesaplamalar içeren event handler’lar bu aşamada gecikmelere yol açar.

3. Presentation Delay (Sunum Gecikmesi)

Olay handler’ları tamamlandıktan sonra tarayıcı, değişen CSS stillerini hesaplar (style recalculation), düzeni yeniden oluşturur (layout), boyama yapar (paint) ve bu pikselleri ekrana kompozitleler. Tüm bu aşamalar presentation delay’i oluşturur.

Çok sayıda DOM düğümünü etkileyen değişiklikler, karmaşık CSS kuralları veya CSS animasyonları bu aşamanın uzamasına neden olabilir.

Formül

INP = max(input delay + processing time + presentation delay)

Daha teknik bir ifadeyle: Sayfa boyunca gerçekleşen tüm etkileşimler için bu üç değerin toplamı hesaplanır. Kullanıcı çok sayıda etkileşim gerçekleştirmişse, 98. yüzdelik dilim (p98) değeri rapor edilir; yani neredeyse en kötü etkileşim puanı INP’yi belirler.


INP Eşik Değerleri

Google, INP için üç kategori belirlemiştir:

KategoriDeğer
İyi<200ms
Geliştir200ms – 500ms
Kötü>500ms

200 ms neden sınır? İnsan algısı açısından 100–200 ms aralığındaki gecikmeler “anlık” hissettirirken, 200 ms üzeri gecikmeler kullanıcı tarafından fark edilmeye başlar. 500 ms geçildiğinde çoğu kullanıcı “sayfa yavaş” ya da “dondu” izlenimi edinir.

Hedef, sayfanızdaki tüm etkileşimlerin — özellikle 75. yüzdelik dilim (p75) kullanıcı verisi baz alındığında — 200 ms altında kalmasını sağlamaktır.


INP’yi Kötüleştiren Nedenler

INP puanınız yüksekse, bunun birkaç temel nedeni olabilir. Her biri main thread (ana iş parçacığı) üzerinde baskı oluşturarak etkileşim gecikmelerini artırır.

Uzun Görevler (Long Tasks)

Tarayıcı, JavaScript’i tek bir iş parçacığında çalıştırır. Bu iş parçacığında 50 ms veya daha uzun süren herhangi bir görev “uzun görev” (long task) olarak sınıflandırılır ve kullanıcı etkileşimlerini bloke edebilir.

Uzun görevler nerede ortaya çıkar?

  • Büyük JavaScript paketlerinin ayrıştırılması ve derlenmesi
  • Karmaşık hesaplamalar yapan fonksiyonlar
  • Sayfalara yüklenen üçüncü taraf scriptlerin başlatılması
  • Büyük veri listelerinin senkron olarak işlenmesi
  • React, Angular veya Vue gibi framework’lerin ilk render aşamaları

Chrome DevTools Performance panelinde uzun görevler kırmızıyla işaretlenir ve kolayca tespit edilebilir.

Main Thread Engelleme

Ana iş parçacığı hem JavaScript çalıştırmaktan hem de render işlemlerinden sorumludur. Bir JavaScript görevi çalışırken kullanıcı etkileşimleri sıraya alınır; yani kullanıcı ne kadar tıklarsa tıklasın, görev bitene kadar yanıt alınamaz.

Sık karşılaşılan engelleme senaryoları:

  • Senkron XHR çağrıları: Artık nadiren kullanılsa da bazı eski kodlarda main thread’i tamamen dondurur
  • Masif JavaScript dosyaları: Tek bir büyük bundle’ın ayrıştırılması yüzlerce ms sürebilir
  • İç içe döngüler: Büyük veri kümelerinde O(n²) karmaşıklığındaki algoritmalar
  • Zorla senkronize layout işlemleri: offsetWidth gibi değerlerin okunup hemen ardından stil değişikliklerinin uygulanması (layout thrashing)

Ağır Event Handler’lar

Bir butona tıklandığında tetiklenen olay dinleyicisi içinde çok fazla iş yapılması, processing time bileşenini şişirir. Yaygın örnekler:

  • Tıklama sonrası büyük bir API yanıtını senkron olarak DOM’a yazma
  • Filtreleme veya arama işlemleri için tüm listeyi senkron döngüyle tarama
  • Modal açılışında karmaşık animasyon hesaplamaları yapma
  • Her tuş basımında tam metin araması tetikleme

Üçüncü Taraf Scriptler

Reklam scriptleri, canlı destek widget’ları, sosyal medya eklentileri ve analytics araçları main thread üzerinde ciddi yük oluşturabilir. Bu scriptler üzerinde kontrol sahibi olmak zordur ama etkilerini azaltmak mümkündür.

Aşırı DOM Boyutu

DOM’da çok sayıda düğüm bulunması hem style recalculation hem de layout süresini uzatır. Özellikle küçük bir değişikliğin bile binlerce düğümü etkilediği durumlarda presentation delay önemli ölçüde artar.


INP Optimizasyon Teknikleri

INP’yi iyileştirmenin özü, main thread üzerindeki yükü azaltmak ve uzun görevleri kısa, kesintiye izin veren parçalara bölmektir.

1. Uzun Görevleri Parçalama: yield ve scheduler.yield

JavaScript’te bir görev başladığında, tarayıcı o görevi tamamlamadan başka bir şey yapamaz. Uzun bir görevi parçalara bölerek arasına “nefes alma noktaları” eklemek, tarayıcıya bekleyen etkileşimleri işleme fırsatı tanır.

setTimeout ile klasik yield:

function yieldToMain() {
  return new Promise(resolve => setTimeout(resolve, 0));
}

async function processLargeList(items) {
  for (let i = 0; i < items.length; i++) {
    processItem(items[i]);

    // Her 50 öğede bir main thread'e nefes ver
    if (i % 50 === 0) {
      await yieldToMain();
    }
  }
}

scheduler.yield() ile modern yaklaşım:

scheduler.yield() API’si, setTimeout(0) yerine daha akıllı bir yield mekanizması sunar. Görevleri öncelik sırasına göre zamanlayabilirsiniz:

async function processWithScheduler(items) {
  for (let i = 0; i < items.length; i++) {
    processItem(items[i]);

    // scheduler.yield destekleniyorsa kullan
    if ('scheduler' in window && 'yield' in scheduler) {
      await scheduler.yield();
    } else {
      // Fallback: setTimeout
      await new Promise(resolve => setTimeout(resolve, 0));
    }
  }
}

scheduler.yield() özellikle Chrome 129+ sürümlerinde mevcut olup, görevin önceliğini koruyarak daha iyi bir zamanlama kalitesi sağlar.

isInputPending ile akıllı yield:

async function smartProcess(items) {
  for (let i = 0; i < items.length; i++) {
    processItem(items[i]);

    // Yalnızca bekleyen giriş varsa ger
    if (navigator.scheduling?.isInputPending()) {
      await yieldToMain();
    }
  }
}

Bu yaklaşım, bekleyen bir kullanıcı etkileşimi yokken sürekli yield yapmaktan kaçınır; böylece görev hem hızlı tamamlanır hem de gerçekten gerekli olduğunda yol verir.

2. Web Workers ile Ağır Hesaplamaları Taşımak

Kullanıcı arayüzüyle doğrudan ilişkisi olmayan ağır hesaplamalar Web Worker’lara taşınabilir. Worker’lar ayrı bir iş parçacığında çalıştığından main thread’i hiç meşgul etmezler.

Ana thread:

// worker.js dosyasını başlat
const worker = new Worker('/js/heavy-worker.js');

// Veriyi gönder
worker.postMessage({ items: largeDataArray });

// Sonucu bekle
worker.onmessage = function(event) {
  const result = event.data;
  updateUI(result);
};

worker.js:

self.onmessage = function(event) {
  const { items } = event.data;

  // Ağır hesaplama burada yapılır, main thread etkilenmez
  const result = items.map(item => heavyTransform(item));

  self.postMessage(result);
};

Web Worker’ların kısıtlarına dikkat edin: DOM’a erişemezler, window nesnesine sahip değillerdir ve ana thread ile yalnızca postMessage üzerinden iletişim kurabilirler. Bu nedenle yalnızca saf hesaplama görevleri için uygundurlar.

3. React 18 Concurrent Features

React 18 ile gelen Concurrent Mode, INP optimizasyonu için güçlü araçlar sunar. Concurrent Mode, React’in render işlemlerini kesintiye uğratılabilir parçalara bölmesini sağlar.

useTransition ile düşük öncelikli güncellemeler:

import { useState, useTransition } from 'react';

function SearchComponent() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  function handleChange(e) {
    // Acil güncelleme: input değerini hemen güncelle
    setQuery(e.target.value);

    // Düşük öncelikli: arama sonuçları bekleyebilir
    startTransition(() => {
      const filtered = searchItems(e.target.value);
      setResults(filtered);
    });
  }

  return (
    <div>
      <input value={query} onChange={handleChange} />
      {isPending ? <Spinner /> : <ResultList items={results} />}
    </div>
  );
}

startTransition içindeki güncellemeler “interruptible” (kesilebilir) olarak işaretlenir. Kullanıcı yeni bir tuşa basarsa React, devam eden render’ı bırakıp yeni girişi önce işler. Bu, her tuş basımında tüm listenin yeniden render edilmesinin getirdiği INP maliyetini dramatik biçimde azaltır.

useDeferredValue ile değer erteleme:

import { useState, useDeferredValue } from 'react';

function FilteredList({ items }) {
  const [filter, setFilter] = useState('');
  const deferredFilter = useDeferredValue(filter);

  const filteredItems = items.filter(item =>
    item.name.toLowerCase().includes(deferredFilter.toLowerCase())
  );

  return (
    <>
      <input
        value={filter}
        onChange={e => setFilter(e.target.value)}
        placeholder="Ara..."
      />
      <ul>
        {filteredItems.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </>
  );
}

useDeferredValue, input’un hemen güncellenip render pahalı bileşenin ertelenmesini sağlar. Kullanıcı hızlı yazarken liste bir adım geride kalır ama klavye hiçbir zaman kasılmaz.

4. Debounce ve Throttle ile Event Sıklığını Azaltma

Her tuş basımında veya her fare hareketinde ağır bir işlem tetiklemeniz gerekmiyorsa, bu olayları debounce veya throttle etmek önemli bir INP kazanımı sağlar.

Debounce: Kullanıcı durana kadar bekler, sonra işlemi yapar.

function debounce(fn, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), delay);
  };
}

const handleSearch = debounce(function(value) {
  // API çağrısı veya ağır filtreleme
  fetchSearchResults(value);
}, 300);

document.getElementById('search').addEventListener('input', function(e) {
  handleSearch(e.target.value);
});

Throttle: Belirli zaman aralıklarında en fazla bir kez çalışır.

function throttle(fn, limit) {
  let lastRun = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastRun >= limit) {
      lastRun = now;
      fn.apply(this, args);
    }
  };
}

const handleScroll = throttle(function() {
  updateStickyHeader();
}, 100);

window.addEventListener('scroll', handleScroll);

Genel kural: Debounce için arama kutuları, form doğrulama; throttle için scroll olayları, resize olayları ve mousemove tercih edilir.

5. Code Splitting ile Gereksiz JavaScript’i Erteleme

Sayfa ilk yüklendiğinde kullanıcıya hemen gerekmeyen JavaScript kod bloklarını ayırmak hem ilk yükleme süresini hem de INP’yi iyileştirir. İlk yükte daha az kod = daha az ayrıştırma ve derleme = daha serbest main thread.

Dinamik import ile route-based code splitting:

// Modal bileşenini yalnızca gerektiğinde yükle
async function openModal() {
  const { initModal } = await import('./modal.js');
  initModal();
}

document.getElementById('open-btn').addEventListener('click', openModal);

Intersection Observer ile lazy loading:

const observer = new IntersectionObserver((entries) => {
  entries.forEach(async entry => {
    if (entry.isIntersecting) {
      // Bileşen görünür alana girince yükle
      const { initChart } = await import('./chart.js');
      initChart(entry.target);
      observer.unobserve(entry.target);
    }
  });
});

document.querySelectorAll('.chart-container').forEach(el => {
  observer.observe(el);
});

React.lazy ile bileşen seviyesinde split:

import { lazy, Suspense } from 'react';

const HeavyDashboard = lazy(() => import('./HeavyDashboard'));

function App() {
  return (
    <Suspense fallback={<div>Yükleniyor...</div>}>
      <HeavyDashboard />
    </Suspense>
  );
}

6. Event Handler’ları Optimize Etme

Olay dinleyicilerinin kendisini hafifletmek, processing time bileşenini doğrudan etkiler.

Gereksiz DOM okumalarından kaçının (layout thrashing):

// Kötü: Her iterasyonda layout tetikler
function badLoop(elements) {
  elements.forEach(el => {
    const height = el.offsetHeight; // DOM okuma
    el.style.marginTop = height + 'px'; // DOM yazma — layout invalidate!
  });
}

// İyi: Önce oku, sonra yaz
function goodLoop(elements) {
  const heights = elements.map(el => el.offsetHeight); // Önce hepsini oku
  elements.forEach((el, i) => {
    el.style.marginTop = heights[i] + 'px'; // Sonra hepsini yaz
  });
}

Event delegation ile handler sayısını azaltın:

// Kötü: Her öğeye ayrı listener
document.querySelectorAll('.list-item').forEach(item => {
  item.addEventListener('click', handleItemClick);
});

// İyi: Tek bir parent listener
document.getElementById('item-list').addEventListener('click', function(e) {
  const item = e.target.closest('.list-item');
  if (item) handleItemClick(item);
});

7. Üçüncü Taraf Scriptleri Yönetme

Üçüncü taraf scriptler üzerinde tam kontrol sahibi olmasanız da etkilerini azaltabilirsiniz:

<!-- defer ile main thread'i bloke etmeden yükle -->
<script src="analytics.js" defer></script>

<!-- Kritik olmayan scriptler için async -->
<script src="chatbot.js" async></script>

<!-- Web Worker üzerinden çalıştırmak için Partytown gibi araçları değerlendirin -->

Scriptlerin hangi kaynaktan geldiğini ve ne kadar uzun görev ürettiğini Chrome DevTools’ta Third-party summary filtresiyle görebilirsiniz.


INP’yi Ölçme Araçları

Chrome DevTools Performance Paneli

DevTools’un Performance sekmesi, INP sorunlarını tespit etmek için birincil araçtır.

Nasıl kullanılır:

  1. Chrome DevTools’u açın (F12)
  2. Performance sekmesine geçin
  3. Kayıt düğmesine basın
  4. Yavaş hissettiren etkileşimleri gerçekleştirin
  5. Kaydı durdurun

Kayıt tamamlandığında:

  • Long tasks kırmızı köşeli bloklar olarak görünür
  • INP candidate interactions zaman çizelgesinde işaretlenir
  • Her etkileşim için input delay, processing ve presentation bileşenleri ayrı ayrı görülebilir

INP bozulma noktasını bulmak için: Flame Chart görünümünde en uzun bölümleri inceleyin. Call stack’te hangi fonksiyonun ne kadar süre harcadığını görebilirsiniz. “Bottom-up” ve “Call Tree” sekmeleri darboğazı bulmayı kolaylaştırır.

PerformanceObserver API

Gerçek kullanıcıların etkileşim sürelerini kodunuz aracılığıyla takip etmek istiyorsanız PerformanceObserver kullanabilirsiniz.

Event Timing API ile etkileşim ölçümü:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Yalnızca pointer ve klavye olaylarını ölç
    if (entry.interactionId) {
      const inp = entry.processingEnd - entry.startTime;
      console.log(`Etkileşim süresi: ${inp.toFixed(2)}ms`);
      console.log(`Input delay: ${(entry.processingStart - entry.startTime).toFixed(2)}ms`);
      console.log(`Processing: ${(entry.processingEnd - entry.processingStart).toFixed(2)}ms`);

      // Analytics'e gönder
      sendToAnalytics({
        metric: 'INP',
        value: inp,
        element: entry.target?.tagName
      });
    }
  }
});

observer.observe({ type: 'event', buffered: true, durationThreshold: 16 });

web-vitals kütüphanesi ile basit entegrasyon:

import { onINP } from 'web-vitals';

onINP(({ value, rating, entries }) => {
  console.log(`INP: ${value}ms — ${rating}`);

  // En kötü etkileşimi bul
  const worstEntry = entries.reduce((worst, entry) =>
    entry.duration > worst.duration ? entry : worst
  , entries[0]);

  console.log('En yavaş etkileşim:', worstEntry.name, worstEntry.target);
});

web-vitals kütüphanesi, Google’ın resmi olarak desteklediği ve CrUX ile tutarlı ölçüm yapan en güvenilir yöntemdir.

Chrome User Experience Report (CrUX)

CrUX, Chrome kullanıcılarının gerçek oturum verilerinden derlenen bir alan adı performans veri tabanıdır. Sitenizin sahadan gelen INP verilerini görmek için birkaç yol vardır:

PageSpeed Insights:

https://pagespeed.web.dev/ adresine sitenizin URL’sini girin. “Saha Verisi” bölümünde son 28 gün boyunca gerçek Chrome kullanıcılarından elde edilen INP değerini ve p75 dağılımını görebilirsiniz.

Google Search Console:

Search Console > Core Web Vitals raporu, sitenizin tüm URL’leri için toplu INP durumunu gösterir ve “zayıf” olarak işaretlenen sayfaları listeleri.

BigQuery üzerinden CrUX:

Daha derin analizler için CrUX verisi Google BigQuery’de herkese açık olarak sunulmaktadır. Ülke, cihaz türü ve URL bazında filtreleme yapabilirsiniz.

CrUX API:

const endpoint = 'https://chromeuxreport.googleapis.com/v1/records:queryRecord';
const apiKey = 'YOUR_API_KEY';

fetch(`${endpoint}?key=${apiKey}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    url: 'https://example.com/',
    metrics: ['interaction_to_next_paint']
  })
})
.then(res => res.json())
.then(data => {
  const inp = data.record.metrics.interaction_to_next_paint;
  console.log('P75 INP:', inp.percentiles.p75, 'ms');
  console.log('Histogram:', inp.histogram);
});

Gerçek Dünya Senaryoları ve Çözümleri

Senaryo 1: E-ticaret Filtre Butonu Gecikmesi

Sorun: Kullanıcı ürün listesinde bir filtre butonuna tıkladığında 600 ms gecikme oluşuyor.

Teşhis: DevTools’ta kayıt alındığında, tıklama sonrasında 400 ms’lik bir uzun görev görünüyor. Bu görev, filtreleme işleminin tüm ürün listesini senkron olarak DOM’a yeniden yazmasından kaynaklanıyor.

Çözüm: Listenin yeniden oluşturulmasını startTransition ile erteleme ve sayfalama (pagination) veya sanal kaydırma (virtual scrolling) ekleme.

startTransition(() => {
  setFilteredProducts(applyFilters(products, activeFilters));
});

Sonuç: INP 600 ms → 140 ms’e düşer.

Senaryo 2: Arama Kutusu Donması

Sorun: Her tuş basımında canlı arama yapılıyor; kullanıcı hızlı yazınca klavye girdileri gecikmeyle işleniyor.

Teşhis: Her input olayı, 1000 öğelik bir listeyi senkron filtreleyen bir fonksiyon tetikliyor.

Çözüm: 250 ms debounce + useDeferredValue kombinasyonu.

const deferredQuery = useDeferredValue(query);
const results = useMemo(
  () => items.filter(item => item.name.includes(deferredQuery)),
  [items, deferredQuery]
);

Sonuç: INP 480 ms → 90 ms’e düşer.

Senaryo 3: Üçüncü Taraf Chat Widget’ı

Sorun: Canlı destek widget’ı sayfa yüklenirken büyük bir JS dosyası çalıştırıyor ve bu, kullanıcının ilk etkileşim anında main thread’i bloke ediyor.

Çözüm: Widget’ı requestIdleCallback veya Intersection Observer ile yalnızca kullanıcı sayfada belirli bir süre kaldıktan sonra yükleyin.

// 5 saniye sonra veya kullanıcı belirli bir alana gelince yükle
setTimeout(() => {
  const script = document.createElement('script');
  script.src = 'https://chat-widget.com/widget.js';
  document.body.appendChild(script);
}, 5000);

INP Optimizasyonu İçin Karar Çerçevesi

Bir sitenin INP puanı kötü çıktığında ekiplerin en çok kaybettiği yer “nereden başlamalı” sorusudur. Aşağıdaki karar çerçevesi, tespit ettiğiniz sorunun türüne göre hangi tekniği önce denemeniz gerektiğini gösterir.

BelirtiOlası Kök NedenÖnerilen İlk AdımBeklenen Etki
İlk tıklamada bile gecikme varAna bundle çok büyük, main thread meşgulCode splitting + kritik olmayan scriptleri ertelemeYüksek
Yalnızca arama/filtre kutusunda gecikmeSenkron liste işlemeDebounce + useDeferredValue/useTransitionYüksek
Sayfa boyunca tüm tıklamalar yavaşAğır üçüncü taraf scriptlerdefer/async + geç yükleme (idle veya scroll tetikli)Orta-Yüksek
Yalnızca mobilde kötü, masaüstünde iyiCPU kısıtı, büyük DOMDOM boyutunu küçültme + sanal listeOrta
p75 iyi ama p98 kötüBelirli nadir etkileşimlerde uzun görevPerformanceObserver ile “en kötü etkileşim” analiziOrta
Modal/dropdown açılışında donmaSenkron animasyon hesaplamaCSS transition’a geçiş, requestAnimationFrame kullanımıOrta

Bu tabloyu bir teşhis kontrol listesi gibi kullanabilirsiniz: önce belirtiyi Chrome DevTools veya web-vitals kütüphanesiyle doğrulayın, sonra ilgili satırdaki ilk adımı uygulayın, ardından tekrar ölçün. Sorunun kaynağını netleştirmeden rastgele optimizasyon denemek, hem geliştirme zamanını hem de kod kalitesini olumsuz etkiler.

Hızlı Teşhis Kontrol Listesi

  • PageSpeed Insights’ta “Saha Verisi” bölümünde gerçek INP değerini kaydettim
  • Search Console Core Web Vitals raporunda “zayıf” URL’leri listeledim
  • DevTools Performance panelinde en az 3 farklı etkileşimi (tıklama, form doldurma, menü açma) kaydettim
  • Long Task’ların hangi script/dosyadan geldiğini belirledim
  • Üçüncü taraf scriptlerin toplam main thread süresini Third-party summary ile ölçtüm
  • Mobil ve masaüstü INP değerlerini ayrı ayrı karşılaştırdım
  • web-vitals kütüphanesiyle gerçek kullanıcı verisini analytics’e göndermeye başladım
  • Değişiklik sonrası öncesi/sonrası INP değerlerini kayıt altına aldım

Sık Yapılan Hatalar

INP optimizasyonu yaparken ekiplerin tekrar tekrar düştüğü tuzaklar var. Bunları önceden bilmek, hem zaman kaybını hem de yanlış önceliklendirmeyi önler.

  1. Yalnızca lab verisine (Lighthouse) bakıp saha verisini (CrUX) hiç kontrol etmemek. Lighthouse, tek bir simüle oturumda ölçüm yapar; gerçek kullanıcıların cihaz çeşitliliğini, ağ koşullarını ve etkileşim davranışını yansıtmaz. Bir sayfa Lighthouse’ta “iyi” INP alabilirken CrUX’te “geliştirilmesi gerekiyor” kategorisinde çıkabilir. Karar verirken her zaman saha verisini esas alın.
  2. Tüm etkileşimleri aynı öncelikte görmek. Bir “beğen” butonuyla bir “ödeme tamamla” butonunun kullanıcı için taşıdığı bekleme toleransı farklıdır. Kritik dönüşüm noktalarındaki etkileşimleri önceliklendirin.
  3. setTimeout(fn, 0) ile scheduler.yield()‘i birbirinin yerine kullanmak. İkisi de main thread’e nefes verir ama scheduler.yield() tarayıcıya önceliklendirme bilgisi taşır ve daha tutarlı sonuç verir. Yalnızca eski tarayıcı desteği gerekiyorsa setTimeout fallback’i kullanın.
  4. Debounce süresini rastgele seçmek. 300 ms’lik bir debounce arama kutusu için makul olabilir ama form doğrulama için kullanıcıya “tepkisiz” hissi verebilir. Debounce/throttle sürelerini kullanıcı testleriyle kalibre edin.
  5. Üçüncü taraf scriptleri “dokunulamaz” kabul edip hiç optimize etmemek. Çoğu analytics ve chat widget sağlayıcısı gecikmeli yükleme (lazy loading) seçenekleri sunar; bu ayarları aktif etmemek sık rastlanan bir kayıptır.
  6. Yalnızca masaüstünde test edip mobil INP’yi hiç ölçmemek. Trafiğin büyük kısmı mobilden geliyorsa ve mobil INP kötüyse, masaüstü iyi bile olsa genel puan düşük kalır.
  7. Optimizasyon sonrası tekrar ölçüm yapmamak. Bir düzeltmenin işe yaradığını varsaymak yerine, değişikliği yayına aldıktan sonra 28 günlük CrUX penceresinde gerçek etkisini doğrulayın.
  8. React’te useTransition’ı her güncellemeye uygulamak. Acil güncellemeleri (örneğin input değerinin kendisi) de startTransition içine almak, kullanıcının yazdığı harflerin ekranda gecikmeli görünmesine yol açabilir. Yalnızca gerçekten “ertelenebilir” güncellemeleri transition içine alın.

Vaka Kurgusu: Bir Emlak Portalının INP Sorunu

Orta ölçekli bir emlak portalı, ilan listeleme sayfasında kullanıcı şikayetleri almaya başlıyor: “Filtreleri değiştirince sayfa donuyor.” Ekip önce Search Console’a bakıyor ve mobil INP değerinin 640 ms ile “kötü” kategorisinde olduğunu görüyor; masaüstünde ise 280 ms ile “geliştirilmesi gerekiyor” sınırında.

Uygulama: Geliştirme ekibi DevTools Performance panelinde filtre değişimini kaydediyor ve 450 ms’lik tek bir uzun görev tespit ediyor. Bu görev, filtre değişince 2.000 ilanlık listenin tamamının senkron olarak yeniden render edilmesinden kaynaklanıyor. Ekip üç değişiklik yapıyor: (1) liste render’ını startTransition ile düşük öncelikli hale getiriyor, (2) görünür alanda yalnızca ilk 24 ilanı render edip geri kalanını sanal kaydırma (virtual scrolling) ile yüklüyor, (3) filtre panelindeki üçüncü taraf harita widget’ını yalnızca kullanıcı harita sekmesine tıkladığında yüklüyor.

Sonuç penceresi: Değişiklikler yayına alındıktan sonraki 28 günlük CrUX penceresinde mobil INP 640 ms’den 210 ms’ye, masaüstü INP 280 ms’den 130 ms’ye geriliyor. Ekip aynı dönemde filtre kullanım oranında ve ilan detay sayfasına geçiş oranında da gözle görülür bir iyileşme kaydediyor; bu, INP iyileştirmesinin yalnızca teknik bir metrik değil, kullanıcı davranışını doğrudan etkileyen bir faktör olduğunu gösteriyor. (Vaka temsilidir.)

INP ve Yapay Zeka Destekli Arayüzler

2026 itibarıyla pek çok site, arama kutusuna yapay zeka destekli öneri sistemleri, sohbet tabanlı müşteri desteği veya kişiselleştirilmiş içerik önerileri ekliyor. Bu bileşenler kullanıcı deneyimini zenginleştirse de INP açısından ciddi risk taşır: bir AI öneri motoru her tuş vuruşunda sunucuya istek atıp gelen yanıtı senkron olarak DOM’a yazıyorsa, bu işlem kolayca uzun görev sınırını aşabilir.

Bu tür bileşenleri INP dostu tasarlamanın birkaç temel kuralı var: istekleri debounce etmek, yanıtları geldiğinde startTransition veya benzeri düşük öncelikli güncelleme mekanizmalarıyla render etmek, ve AI yanıtı beklenirken kullanıcının diğer etkileşimlerini (yazmaya devam etme, başka bir alana tıklama) hiçbir şekilde bloke etmemek. Yapay zeka destekli özellikler pazarlama açısından cazip olsa da, kötü uygulanmış bir AI widget’ı sitenin genel Core Web Vitals performansını tek başına düşürebilir; bu nedenle bu tür entegrasyonları performans bütçesi belirlemeden devreye almamak önerilir.

INP İyileştirmesinde Öncelik Sıralaması

Tüm bu teknikler arasında nereden başlayacağınızı belirlemek için aşağıdaki sırayı öneriyoruz:

  1. Ölçün: PageSpeed Insights ve Search Console’da gerçek INP değerinizi öğrenin
  2. Tespit edin: DevTools Performance panelinde en uzun görevleri bulun
  3. Event handler’ları hafifletin: Processing time’ı artıran ağır handler’ları optimize edin
  4. Görevleri parçalayın: yield veya scheduler.yield ile uzun görevleri böllün
  5. Üçüncü tarafları erteleyin: Chat widget, reklam scriptleri gibi kaynakları ilk yükten çıkarın
  6. Framework özelliklerini kullanın: React 18 concurrent features veya benzeri araçları devreye alın
  7. Tekrar ölçün: Değişikliklerin etkisini gerçek kullanıcı verileriyle doğrulayın

INP ve SEO İlişkisi

INP, Core Web Vitals’in aktif bir bileşeni olarak Google’ın sıralama algoritmasına dahildir. Ancak INP’nin SEO etkisini doğru anlamak önemlidir:

  • Core Web Vitals, “sayfa deneyimi” sinyalinin bir parçasıdır
  • Kötü bir INP puanı, aynı anahtar kelimeyi hedefleyen kaliteli içeriklere sahip rakipler karşısında sizi dezavantajlı konuma düşürebilir
  • INP’nin doğrudan sıralama etkisi nüanslıdır; ancak dolaylı etkileri (daha yüksek dönüşüm, düşük hemen çıkma oranı, daha uzun oturum süresi) SEO sinyallerini olumlu etkiler

INP’yi iyileştirmek, aynı zamanda kullanıcı deneyimini iyileştirir. Bu da organik trafiği artırmak için altyapıyı sağlamlaştırır. Teknik SEO hizmetlerimiz hakkında daha fazla bilgi almak için bu sayfayı inceleyebilirsiniz.


Sık Sorulan Sorular

INP ve TBT arasındaki fark nedir?
TBT (Total Blocking Time) ve INP ilişkili ama farklı metriklerdir. TBT, sayfa yükleme süresindeki uzun görevlerin toplamını ölçer ve Lighthouse gibi lab tabanlı araçlarda kullanılır; bu nedenle geliştirme sürecinde erken uyarı sinyali olarak değerlidir. INP ise gerçek kullanıcı etkileşimlerini ölçer ve yalnızca alan verileriyle (CrUX) değerlendirilir, dolayısıyla gerçek dünya deneyimini yansıtır. İkisi birbirini tamamlar: TBT geliştirme aşamasında iyi bir proxy metriktir ama yayına alındıktan sonra sitenin gerçek performansını değerlendirmek için INP’ye bakmak gerekir. Bir sayfa düşük TBT’ye sahip olsa bile gerçek kullanıcı cihazlarında yüksek INP verebilir.
INP değerim iyi ama kullanıcılar yavaş hissettiriyor; bu nasıl olabilir?
INP, tıklama ve klavye olaylarını ölçer; kaydırma veya animasyon akıcılığını kapsamaz. Kullanıcılarınız yavaş hissediyorsa CLS (layout shift), yavaş kaydırma (scroll jank) veya ağır animasyonlar sorun yaratıyor olabilir. Ayrıca INP p75 değeri iyi olsa bile p98 değeriniz yüksekse belirli etkileşimler ciddi gecikme yaşatıyor olabilir; bu durumda PerformanceObserver ile hangi etkileşimlerin en kötü olduğunu tespit etmek gerekir. Genel algıyı etkileyen başka faktörler de olabilir: sunucu yanıt süresi, görsel yükleme hızı veya font değişimi kaynaklı görsel kararsızlık.
Mobil INP puanı neden masaüstünden çok daha kötü?
Mobil cihazların işlemcisi masaüstü cihazlara göre genellikle çok daha kısıtlıdır. Aynı JavaScript kodu, masaüstünde 100 ms’de tamamlanan bir görevi mobilde 400 ms’de tamamlayabilir. Bu nedenle mobil öncelikli optimizasyon hayati önemdedir. CrUX ve PageSpeed Insights, cihaz türüne göre ayrı ayrı raporlama sunar; her iki skorunuzu ayrı değerlendirin ve mobil trafiğin toplam trafik içindeki payını da göz önünde bulundurun. Türkiye’de mobil trafik payı pek çok sektörde yarının üzerinde seyrettiğinden, mobil INP’yi ihmal etmek genel kullanıcı deneyimini ciddi biçimde zedeler.
INP optimizasyonu React dışındaki framework’lerde nasıl yapılır?
Vue, Angular, Svelte gibi framework’lerin de kendi deferral ve chunking mekanizmaları bulunur. Vue’da nextTick ve async components, Angular’da NgZone.runOutsideAngular ve Signals, Svelte’de built-in reactivity benzer amaçlara hizmet eder. Ancak temel ilke sabittir: ağır işleri main thread’den çıkar veya parçalara böl, kritik olmayan güncellemeleri erteleyerek kullanıcı girdisine öncelik ver. Framework’ten bağımsız olarak scheduler.yield() ve Web Worker gibi platform seviyesindeki API’ler her yerde aynı şekilde çalışır.
WordPress veya Shopify gibi hazır platformlarda INP nasıl iyileştirilir?
Hazır platformlarda kaynak kodu doğrudan değiştiremediğiniz için optimizasyon genellikle eklenti ve tema seçimiyle sınırlıdır. Öncelikle gereksiz eklentileri kaldırın, özellikle sayfa yüklenirken çok sayıda script enjekte edenleri. Temanızın ağır JavaScript kullanıp kullanmadığını DevTools ile kontrol edin. Sayfa oluşturucu (page builder) eklentileri genellikle en büyük main thread yükünü oluşturur; mümkünse daha hafif alternatiflere geçin. Analytics ve pazarlama scriptlerini defer veya gecikmeli yükleme seçenekleriyle ayarlayın; çoğu modern eklenti bu seçeneği sunar.
INP kötüyse Google Ads veya sosyal medya reklamlarımın performansı da etkilenir mi?
Doğrudan reklam sıralamasını etkilemez ama dolaylı etkisi büyüktür. Reklamdan gelen bir kullanıcı, açılış sayfasında bir butona tıkladığında sayfa donuk hissettiriyorsa, dönüşüm oranı düşer ve reklam harcamanızın verimliliği azalır. Google Ads’te Kalite Puanı hesaplamasında açılış sayfası deneyimi bir faktördür ve kötü Core Web Vitals bu puanı olumsuz etkileyebilir. Bu nedenle özellikle reklam trafiği alan açılış sayfalarında INP optimizasyonuna öncelik vermek, hem SEO hem de performans pazarlaması açısından anlamlıdır.
INP’yi izlemek için hangi ücretsiz araçları kullanmalıyım?
Başlangıç için üç araç yeterlidir: PageSpeed Insights (tekil URL’ler için hızlı saha verisi), Google Search Console’un Core Web Vitals raporu (site genelinde toplu izleme) ve Chrome DevTools Performance paneli (kök neden analizi için). Daha ileri seviyede, web-vitals npm paketini sitenize entegre edip kendi analytics altyapınıza gerçek kullanıcı verisi göndermeniz, sorunları üretimde gerçek zamanlı yakalamanızı sağlar. Bu dört araç birlikte kullanıldığında hem “ne kadar kötü” hem de “neden kötü” sorularına yanıt verir.
Tek sayfa uygulamalarda (SPA) INP neden genellikle daha zorlayıcıdır?
SPA mimarisinde sayfa geçişleri de birer “etkileşim” olarak INP ölçümüne dahil olabilir; bir menü linkine tıklandığında tüm sayfa içeriğinin istemci tarafında yeniden render edilmesi büyük bir main thread yükü oluşturur. Bu nedenle SPA’larda route bazlı code splitting, iskelet ekranlar (skeleton screens) ile algılanan hızı artırma ve kritik olmayan bileşenleri lazy-load etme özellikle önemlidir. Sunucu tarafında render (SSR) veya kısmi hydration stratejileri de SPA’larda INP’yi iyileştirmenin etkili yollarındandır.

Özet

INP, kullanıcıların bir web sitesiyle nasıl hissettiklerini ölçmenin bugüne kadar geliştirilen en kapsamlı ve gerçekçi yöntemidir. FID’den farklı olarak yalnızca ilk değil tüm etkileşimleri değerlendirir; yalnızca input delay değil, işleme ve sunum aşamalarını da kapsar.

200 ms altında tutulması gereken bu metrik, main thread üzerindeki yükün azaltılmasıyla iyileştirilebilir. Görevleri scheduler.yield ile parçalamak, ağır hesaplamaları Web Worker’lara taşımak, React 18 concurrent features’ı kullanmak, debounce/throttle uygulamak ve gereksiz kodu yalnızca gerektiğinde yüklemek en etkili teknikler arasındadır.

Optimizasyon sürecine PageSpeed Insights ve Chrome DevTools’la başlayın, gerçek kullanıcı verilerini web-vitals kütüphanesiyle ölçün ve değişikliklerinizin etkisini CrUX verileriyle doğrulayın. INP puanınızı iyileştirmek yalnızca sıralamayı değil, kullanıcılarınızın sitenizde geçirdiği her anı doğrudan etkiler.

Onur Öztürk, SEO uzmanı
// yazar

Onur ÖZTÜRK

SEO Uzmanı & Dijital Pazarlama Danışmanı

15 yılı aşkın deneyimle sağlık turizmi, e-ticaret ve kurumsal markalar için SEO stratejisi geliştiriyorum. Google Partner ve Meta Business Partner olarak 150'den fazla işletmenin organik büyümesine katkı sağladım. SEO'nun yanında web tasarım, reklam yönetimi ve logo tasarımı hizmetlerini de ekibimle birlikte yürütüyorum.

// google arama

Bu içerikleri Google'da daha sık görün

onuroztr.com'u tercih edilen kaynak olarak ekleyin; yazılarımız arama sonuçlarında ve yapay zeka özetlerinde size daha sık gösterilsin.

WhatsApp'tan yazın Genellikle 1 saat içinde dönüyorum
WhatsApp Toplantı Planlayın