Tarayıcının sitenize ne kadar yer ayırdığını öğrenmek için navigator.storage.estimate() çağırırsınız; promise, bayt cinsinden tahmini kotayı (quota) ve kullanımı (usage) içeren bir nesneyle çözülür. Verinizin disk dolduğunda kendiliğinden silinmemesini istiyorsanız navigator.storage.persist() ile kalıcı depolama istersiniz; navigator.storage.persisted() ise bu iznin zaten verilip verilmediğini söyler. Üç yöntem de Storage API'nin StorageManager arayüzüne aittir.

Bu yazıda tarayıcıların site verisini nasıl "kova" (bucket) adı verilen alanlarda tuttuğunu, "best-effort" ve "persistent" modlarını, kotaların ve silme (eviction) kurallarının nasıl işlediğini, kota dolduğunda ne yapmanız gerektiğini ve Origin Private File System (OPFS) için kısa bir girişi anlatıyoruz. Tek tek depolama API'leri için localStorage, IndexedDB ve Cache API yazılarına, dizinin genel haritasına Web API öğrenme rehberi üzerinden ulaşabilirsiniz.

Tarayıcı site verisini nerede tutar?

Tarayıcı site verisini nerede tutar? Çerezler, Web Storage, IndexedDB, Cache API

WHATWG Storage Standard, sitelerin tarayıcıda veri saklamak için kullandığı tüm API'lerin paylaştığı ortak bir depolama sistemini tanımlar. Bu sistem genellikle her köken için tek bir kova barındırır; her sitenin verisi kendi kovasına konur. Köken şema, alan adı ve porttan oluşur: https://example.com ile https://example.com/app/index.html aynı kökendir. Kota ve silme kuralları da kökenin tamamına uygulanır; aynı kökende /site1/ ve /site2/ gibi iki ayrı uygulama çalıştırıyorsanız aynı kotayı paylaşırlar.

MDN'e göre bazı durumlarda tarayıcı tek bir kökenin verisini birden çok kovaya bölebilir; örneğin aynı köken farklı üçüncü taraf sitelere iframe ile gömüldüğünde. Bunun amacı kullanıcının siteler arası izlenmesini zorlaştırmaktır. Kovaya giren veriler şunlardır:

TeknolojiNe saklar
ÇerezlerSunucu ile tarayıcı arasında gidip gelen küçük durum bilgisi
Web StoragelocalStorage ve sessionStorage ile yalnızca string anahtar/değer çiftleri
IndexedDBDizinlenebilir büyük yapılandırılmış veri ve blob'lar
Cache APIRequest ve Response çiftleri
OPFSKökene özel, kullanıcıya görünmeyen dosya sistemi

MDN, tarayıcıların bunlara ek olarak WebAssembly kod önbelleği gibi başka verileri de köken adına saklayabildiğini not eder. Çerezlerin sınırları bu sayfada ele alınmaz, çünkü MDN çerezlerin veri saklamak için kullanılmamasını önerir; çerez ayrıntıları document.cookie ve Set-Cookie yazısındadır.

best-effort ve persistent modları

Her kovanın veri saklama politikasını belirleyen bir modu vardır. Varsayılan mod best-effort'tur: köken kotasının altında kaldığı, cihazda yeterli yer olduğu ve kullanıcı tarayıcı ayarlarından silmediği sürece veri kalır. Ancak depolama alanı daraldığında tarayıcı bu kovayı kullanıcıya haber vermeden temizleyebilir. IndexedDB veya Cache API ile yazdığınız veri kullanıcıdan izin istenmeden bu modda saklanır ve gerektiğinde yine sessizce silinir.

persistent modda tarayıcı veriyi olabildiğince uzun tutar ve kalıcı bir kovayı temizlemeyi düşünmeden önce tüm best-effort kovaları temizler. Kalıcı kovaların temizlenmesi gerekirse kullanıcıyı bilgilendirir ve seçim yapmasını sağlar. MDN'e göre kalıcı kovalar, kullanıcının "önbelleği temizle" veya "son geçmişi temizle" gibi seçenekleri de dahil olmak üzere, köken veya kullanıcı açıkça istemedikçe silinmez; kullanıcıdan bu kovalar için özel olarak izin istenir.

Modu değiştirmek için navigator.storage.persist() kullanılır. Bu çağrı "persistent-storage" kullanıcı iznini gerektirir ve izin verilip kova kalıcı hale gelirse true, aksi halde false ile çözülür. Tarayıcı isteği kendi kurallarına göre kabul edebilir veya etmeyebilir. MDN'in aktardığına göre Firefox kullanıcıya bir açılır pencereyle sorar; Safari ve Chrome ile Edge gibi Chromium tabanlı tarayıcıların çoğu ise kullanıcının siteyle etkileşim geçmişine bakarak, kullanıcıya hiçbir şey göstermeden otomatik karar verir. İzin kavramları ve hata durumları için DOMException ve güvenli bağlam hataları yazısına bakabilirsiniz.

javascript
if (navigator.storage && navigator.storage.persist) {
  navigator.storage.persist().then((persistent) => {
    if (persistent) {
      console.log("Depolama yalnızca kullanıcının açık isteğiyle silinir.");
    } else {
      console.log("Depolama alanı daralırsa tarayıcı veriyi silebilir.");
    }
  });
}

Önce iznin zaten verilip verilmediğini persisted() ile kontrol etmek, gereksiz istekleri önler. MDN ayrıca persist() yönteminin Web Worker içinde bulunmadığını, ama StorageManager arayüzünün worker'da da erişilebilir olduğunu (WorkerNavigator.storage) belirtir. Üç yöntem de köken opak bir köken ise veya kullanıcı depolamayı kapattıysa TypeError ile reddedilir.

javascript
async function kaliciligiSagla() {
  if (!navigator.storage?.persist) return false;
  if (await navigator.storage.persisted()) return true;
  return navigator.storage.persist();
}

Kalıcı depolamayı her siteye istemek doğru değildir. MDN, bunun başka hiçbir yerde saklanmayan kritik veriye dayanan uygulamalar için gerektiğini söyler; örneğin yalnızca tarayıcıda tutulan bir not uygulaması. MDN'in aktardığı Chrome ekibi araştırmasına göre tarayıcılar veriyi çok nadiren siler ve düzenli ziyaret edilen bir sitenin best-effort verisinin bile silinme olasılığı çok düşüktür.

Kota ve kullanım tahmini: estimate()

Tarayıcının bir kökene izin verdiği en büyük alan o kökenin kotası, bunun kullanılan kısmı ise kullanımıdır. estimate() ikisini de bayt cinsinden verir ve isteğe bağlı olarak kullanımı depolama sistemlerine göre bölen bir usageDetails nesnesi döndürebilir; bu nesnede yalnızca kullanımı sıfırdan büyük olan sistemler yer alır. MDN'e göre değerler kasıtlı olarak kesin değildir: tarayıcılar parmak izi (fingerprinting) çıkarılmasını önlemek için gerçek boyutu gizler, sıkıştırma ve tekilleştirme fiziksel boyutu değiştirir, kota da cihazdaki boş alandan daha az olacak şekilde temkinli hesaplanır. Ayrıca başka kökenlerden gelen kaynakların boyutu toplam kullanıma eklenirken tarayıcılar bilerek şişirilmiş değerler raporlayabilir.

MDN, kotanın kökenden kökene değişebileceğini ve bunda kullanıcının siteyi ne sıklıkla ziyaret ettiği, genel site popülerliği verileri ve yer imi ekleme, ana ekrana ekleme veya push bildirimlerini kabul etme gibi etkileşim sinyallerinin rol oynadığını belirtir.

javascript
navigator.storage.estimate().then((estimate) => {
  const yuzde = ((estimate.usage / estimate.quota) * 100).toFixed(2);
  const mb = (estimate.quota / 1024 / 1024).toFixed(2);
  document.getElementById("percent").textContent = yuzde;
  document.getElementById("quota").textContent = `${mb}MB`;
});
html
<p>Tahmini kotanızın yaklaşık %<span id="percent"></span> kadarını kullanıyorsunuz (<span id="quota"></span>).</p>

Tahmini değerleri kullanıcıya göstermek için okunur bir biçime çevirmek isteyebilirsiniz. Aşağıdaki yardımcı yalnızca sayılarla çalışır; örnek değerlerle Node.js'te çalıştırıldı. Tarayıcıda estimate() sonucunu doğrudan verirsiniz.

javascript
function bicimle(bayt) {
  const birimler = ["B", "KiB", "MiB", "GiB", "TiB"];
  let i = 0;
  let deger = bayt;
  while (deger >= 1024 && i < birimler.length - 1) {
    deger /= 1024;
    i++;
  }
  return `${deger.toFixed(2)} ${birimler[i]}`;
}

const tahmin = { usage: 52428800, quota: 2147483648 }; // örnek değerler
console.log(bicimle(tahmin.usage)); // 50.00 MiB
console.log(bicimle(tahmin.quota)); // 2.00 GiB
console.log(((tahmin.usage / tahmin.quota) * 100).toFixed(2)); // 2.44
console.log(bicimle(tahmin.quota - tahmin.usage)); // 1.95 GiB

Ne kadar veri saklanabilir?

Ne kadar veri saklanabilir? Firefox, Chrome ve Chromium tabanlılar, Safari (WebKit tarayıcı uygulamaları)

Web Storage için kural sabittir: MDN'e göre köken başına 5 MiB localStorage ve 5 MiB sessionStorage, toplamda en fazla 10 MiB. IndexedDB, Cache API ve OPFS ise her tarayıcının kendi depolama yönetim sistemine tabidir ve sınırlar tarayıcıya göre değişir. MDN'in bugünkü kopyasında anlatılan değerler aşağıdadır; bu sayılar tarayıcılar tarafından değiştirilebilir, bu yüzden uygulamanızı belirli bir sayıya göre değil estimate() sonucuna göre tasarlayın.

Tarayıcıbest-effortpersistent
FirefoxDisk boyutunun %10'u veya aynı sitenin kökenleri için 10 GiB grup sınırı; hangisi küçükseDisk boyutunun %50'si, en fazla 8 TiB; grup sınırı uygulanmaz
Chrome ve Chromium tabanlılarToplam disk boyutunun %60'ına kadarToplam disk boyutunun %60'ına kadar
Safari (WebKit tarayıcı uygulamaları)Köken başına toplam diskin yaklaşık %60'ıMDN mod ayrımı yapmaz; aynı yaklaşık %60

MDN bu tabloya birkaç ayrıntı ekler. Kotalar parmak izini önlemek için o anki boş alana göre değil toplam disk boyutuna göre hesaplanır; bu nedenle bir köken teorik kotasına hiç ulaşamayabilir. WebKit'te web içeriği gösteren ama tarayıcı olmayan uygulamalarda köken başına sınır yaklaşık %15'tir, siteler arası çerçevelerin (cross-origin frame) kotası ise ebeveynlerinin yaklaşık onda biridir. Firefox örneğinde 500 GiB bir diskte best-effort sınırı grup sınırı olan 10 GiB, persistent sınırı ise 250 GiB olur. Gizli tarama modunda tarayıcılar farklı kotalar uygulayabilir ve veriler genellikle oturum bitince silinir.

Kota dolduğunda ne olur?

IndexedDB, Cache API veya OPFS ile kotanın üzerinde veri yazmaya çalışmak QuotaExceededError ile başarısız olur; Web Storage da sınırda aynı hatayı fırlatır. MDN'in önerisi açıktır: tarayıcı depolamasına yazan kodu try...catch ile sarın ve yeni veri yazmadan önce gereksiz veriyi silerek yer açın. Aşağıdaki kalıp, yazma öncesinde kabaca bir yer kontrolü yapar ve hata durumunda eski önbellekleri temizler:

javascript
async function yerVarMi(gerekenBayt) {
  if (!navigator.storage?.estimate) return true;
  const { usage, quota } = await navigator.storage.estimate();
  return quota - usage > gerekenBayt;
}

async function buyukVeriyiSakla(url, yanit, boyut) {
  if (!(await yerVarMi(boyut))) {
    await caches.delete("eski-medya-v1");
  }
  try {
    const cache = await caches.open("medya-v2");
    await cache.put(url, yanit);
  } catch (e) {
    if (e.name === "QuotaExceededError") {
      // kullanıcıya yer açması gerektiğini bildirin
    }
    throw e;
  }
}

estimate() değerleri yaklaşık olduğu için bu kontrol yalnızca kaba bir ön denetimdir; asıl güvence catch bloğudur. Saklayacağınız bir metnin bayt boyutunu kabaca ölçmek için TextEncoder veya Blob kullanabilirsiniz. Aşağıdaki kod Node.js ile çalıştırıldı ve bir metnin karakter sayısıyla UTF-8 bayt sayısının Türkçe karakterlerde nasıl ayrıştığını gösterir; bu sayı tarayıcının diskte kullandığı gerçek alanla aynı olmak zorunda değildir.

javascript
const taslak = { baslik: "Toplantı notu", govde: "ç".repeat(1000) };
const metin = JSON.stringify(taslak);
console.log(metin.length); // 1037
console.log(new TextEncoder().encode(metin).length); // 2038
console.log(new Blob([metin]).size); // 2038

Veri ne zaman ve nasıl silinir?

MDN üç silme durumu tanımlar. Birincisi depolama baskısıdır: cihazda yer azaldığında tarayıcı en uzun süredir kullanılmayan (LRU) kökenin verisini siler, baskı sürerse bir sonrakine geçer. Bu mekanizma kalıcı depolama izni almış kökenleri atlar. İkincisi tarayıcının toplam sınırının aşılmasıdır: bazı tarayıcılar diskin belli bir oranından fazlasını kullanmaz (MDN, Chrome için şu anda toplam diskin en fazla %80'ini örnek verir). Hiçbir köken kendi kotasını aşmasa bile toplam bu sınırı geçerse best-effort kökenler aynı LRU sırasıyla silinir. Üçüncüsü proaktif silmedir ve yalnızca Safari'de görülür: siteler arası izleme koruması açıkken, son yedi günlük tarayıcı kullanımında kullanıcıyla hiç etkileşimi (tıklama, dokunma) olmayan bir kökenin betikle oluşturulmuş verisi silinir; sunucunun kurduğu çerezler bundan muaftır.

Silme her zaman kökenin tamamına uygulanır. Bir köken hem IndexedDB hem Cache API kullanıyorsa ikisi birlikte silinir; MDN bunun nedenini, verinin yalnızca bir kısmını silmenin tutarsızlıklara yol açabilmesi olarak açıklar. Bu yüzden uygulamanız, tüm yerel verinin bir gün yok olabileceği varsayımıyla tasarlanmalı ve önemli veriyi sunucuyla senkronize etmelidir.

OPFS'e kısa giriş

Origin Private File System (OPFS), File System API'nin bir parçası olan, sayfanın kökenine özel ve kullanıcının normal dosya sisteminde görünmeyen bir depolama alanıdır. Diğer köken bölümlenmiş depolar gibi tarayıcı kotasına tabidir, kullanımı estimate() ile görülebilir ve site verileri temizlendiğinde silinir. Kullanıcıya görünen dosyalara erişimin aksine izin istemi ve güvenlik denetimi gerektirmez; MDN bunun sayesinde daha hızlı olduğunu ve bayt düzeyinde, yerinde yazma imkânı verdiğini anlatır. Tarayıcı desteği için MDN uyumluluk tablosuna bakın.

Kök dizine navigator.storage.getDirectory() ile ulaşırsınız; bu bir FileSystemDirectoryHandle verir. Dosya ve klasörleri getFileHandle() ve getDirectoryHandle() ile alır, { create: true } ile yoksa oluşturursunuz. Ana iş parçacığında API promise tabanlıdır; okumak için getFile() ile bir File alır, yazmak için createWritable() ile bir akış açarsınız.

javascript
async function taslakKaydet(metin) {
  const kok = await navigator.storage.getDirectory();
  const dosya = await kok.getFileHandle("taslak.txt", { create: true });

  const yazici = await dosya.createWritable();
  await yazici.write(metin);
  await yazici.close();

  const okunan = await dosya.getFile(); // File, yani bir Blob
  return okunan.text();
}

Yüksek performans gereken durumlarda, yalnızca Web Worker içinde kullanılabilen eş zamanlı erişim tanıtıcısı (createSyncAccessHandle()) vardır. MDN'in uyarısıyla: adında "Sync" geçse de bu yöntemin kendisi eş zamansızdır; döndürdüğü tanıtıcının read(), write(), getSize(), truncate(), flush() ve close() yöntemleri ise eş zamanlıdır. getDirectory() bazı tarayıcılarda gizli modda SecurityError veya UnknownError fırlatabilir. Worker kullanımı için Web Workers, dosya nesneleri için File API ve Blob yazısına bakabilirsiniz.

Sık yapılan hatalar

Sık yapılan hatalar: estimate() değerini kesin sanmak, Sabit bir kota varsaymak, persist() çağrısını kesin izin sanmak, persist() çağrısını worker içinde yapmak
  • estimate() değerini kesin sanmak: Değerler kasıtlı olarak yaklaşıktır; yazma işlemlerini yine de try...catch ile koruyun.
  • Sabit bir kota varsaymak: Kota tarayıcıya, cihaza ve kullanıcının siteyle etkileşimine göre değişir.
  • persist() çağrısını kesin izin sanmak: Tarayıcı reddedebilir; dönen false değerini ele alın.
  • persist() çağrısını worker içinde yapmak: Bu yöntem worker bağlamında bulunmaz; çağrıyı sayfadan yapın.
  • Yerel veriyi tek kopya saymak: Silme işlemi kökenin tamamını kapsar; önemli veriyi sunucuya da yazın.
  • Gizli modda kalıcılık beklemek: Gizli pencere kapandığında veriler genellikle silinir.

Sık Sorulan Sorular

Sitem ne kadar alan kullanıyor, nasıl görürüm?

Kodda navigator.storage.estimate() ile tahmini kullanım ve kotayı alırsınız. Geliştirme sırasında MDN'in de andığı gibi Firefox'un Storage Inspector aracı veya Chrome'un Application paneli depolanan verileri gösterir.

Kalıcı depolama izni nasıl istenir?

navigator.storage.persist() çağrılır. Firefox kullanıcıya sorar; Chromium tabanlı tarayıcılar ve Safari, MDN'e göre kullanıcının siteyle etkileşim geçmişine bakarak kendiliğinden karar verir.

Tarayıcı verimi neden sildi?

Olası nedenler: cihazda yer daraldı ve siteniz en az kullanılanlar arasındaydı, tarayıcının toplam sınırı aşıldı, Safari'de yedi gün boyunca etkileşim olmadı, kullanıcı site verilerini temizledi veya oturum gizli moddaydı.

localStorage da bu kotaya dahil mi?

MDN'in Storage API sayfasına göre ortak depolama sistemi genellikle IndexedDB ve Cache API verisini kapsar, Web Storage verisini de içerebilir. Web Storage'ın ayrıca köken başına 5 MiB'lık kendi sınırı vardır.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Web API öğrenme rehberi · IndexedDB kullanımı · Cache API · localStorage ve sessionStorage · PWA ve web app manifest · DOMException hataları