Notifications API, web sayfasının işletim sisteminin kendi bildirim sistemiyle kullanıcıya bildirim göstermesini sağlar. Önce bir kullanıcı hareketi (örneğin düğme tıklaması) içinde Notification.requestPermission() ile izin istenir; izin "granted" ise sayfadan new Notification("Başlık", { body: "..." }) ile ya da service worker kaydı üzerinden registration.showNotification() ile bildirim gösterilir. Mobil cihazları hedefliyorsanız ikinci yol zorunludur.

Bu yazıda kalıcı ve kalıcı olmayan bildirim farkını, izin durumlarını, bildirim seçeneklerini, tag ile bildirimleri değiştirmeyi, olayları ve service worker tarafında notificationclick işlemeyi MDN belgelerine göre anlatıyoruz. Sunucudan gelen push mesajlarıyla bildirim göndermek ayrı bir konudur ve push bildirim yazısında ele alınıyor. Tüm Web API konuları için Web API öğrenme rehberine bakabilirsiniz.

Web bildirimi nedir?

Web bildirimi, bir web uygulamasında olan bir olayı kullanıcıya haber veren mesaj kutusudur. İşletim sisteminin yerel bildirim sistemi tarafından çizildiği için platformdaki diğer uygulamaların bildirimleriyle aynı görünür. Sayfanın görüntü alanının dışında gösterildiğinden kullanıcı başka bir sekmeye ya da uygulamaya geçmiş olsa bile görünebilir. MDN'in tipik örneği, kullanıcı başka bir işle meşgulken yeni mesaj geldiğini bildirmesi gereken web tabanlı bir e-posta ya da sohbet uygulamasıdır.

Görünüm ve tam işlevsellik platformdan platforma değişir; API, çoğu sistem bildirim mekanizmasıyla uyumlu olacak kadar genel tasarlanmıştır. Bu yüzden bir seçeneğin her platformda aynı etkiyi yaratacağını varsaymamak gerekir; MDN örneğin dir seçeneğinin çoğu tarayıcıda yok sayıldığını not eder.

Kalıcı ve kalıcı olmayan bildirimler

Kalıcı ve kalıcı olmayan bildirimler: Oluşturma, Nerede çalışır, Ömür, Tıklama olayı

API iki tür bildirim tanır. Kalıcı olmayan (non-persistent) bildirimler bir sayfada ya da sekmede Notification() kurucusuyla oluşturulur; ömürleri sayfanın ömrüne bağlıdır, sayfa kapanınca artık etkileşime girilemez ve click gibi olaylar doğrudan Notification nesnesinde tetiklenir. Kalıcı (persistent) bildirimler ise service worker kaydı üzerinden showNotification() ile oluşturulur, tek bir sayfanın ömrünü aşarak etkileşimli kalabilir ve olaylarını (notificationclick, notificationclose) service worker'ın global kapsamında alır.

ÖzellikKalıcı olmayanKalıcı
Oluşturmanew Notification(title, options)registration.showNotification(title, options)
Nerede çalışırSayfa veya sekmeService worker kaydı
ÖmürSayfa kapanınca etkileşim biterSayfanın ömrünü aşabilir
Tıklama olayıNotification nesnesinde clickService worker kapsamında notificationclick
MobilKurucu çoğu mobil tarayıcıda TypeError fırlatırMobilde kullanılması gereken yol

İzin istemek: Notification.requestPermission()

Bildirim göstermek için kullanıcının geçerli origin'e izin vermiş olması gerekir. Mevcut durum salt okunur Notification.permission özelliğinden okunur ve üç değerden biridir: "default" (kullanıcıya henüz sorulmadı, bildirim gösterilmez), "granted" (kullanıcı izin verdi) ve "denied" (kullanıcı açıkça reddetti). "default" durumunda tarayıcı izin reddedilmiş gibi davranır.

Notification.requestPermission() bir promise döndürür ve bu promise kullanıcının seçtiği değerle çözülür. Eski geri çağırma (callback) biçimi de vardır ama MDN onu kullanımdan kaldırılmış (deprecated) olarak işaretler. İzin istemi her zaman bir kullanıcı hareketine yanıt olarak açılmalıdır; MDN bunun yalnızca iyi uygulama olmadığını, tarayıcıların kullanıcı hareketi olmadan yapılan bildirim izni isteklerini açıkça engellemeye yöneldiğini anlatır. Kullanıcı etkinliği ve izinle ilgili hataların genel anlatımı için Web API hata yazısına bakın.

html
<button id="enable">Bildirimleri aç</button>
javascript
const notificationBtn = document.querySelector("#enable");

function askNotificationPermission() {
  if (!("Notification" in window)) {
    console.log("This browser does not support notifications.");
    return;
  }
  Notification.requestPermission().then((permission) => {
    // İzin verildiyse düğmeyi gizle, reddedildiyse fikrini değiştirebilsin diye göster
    notificationBtn.style.display = permission === "granted" ? "none" : "block";
  });
}

notificationBtn.addEventListener("click", askNotificationPermission);

MDN'in rehberine göre Chrome ve Firefox güvenli bağlam (HTTPS) olmayan sitelerde bildirim izni istenmesine hiç izin vermez ve çapraz origin iframe içinden izin istenemez. Kullanıcının verdiği karar genellikle oturum boyunca korunur. Bu nedenle sayfa açılır açılmaz izin istemek yerine kullanıcının bildirimin değerini anlayacağı bir anda, kendi düğmenizle istemek hem kullanıcı deneyimi hem de tarayıcı kuralları açısından doğru yoldur. HTTPS kurulumu için HTTPS rehberine bakabilirsiniz.

Bildirim oluşturmak

Kalıcı olmayan bildirim için Notification kurucusu bir başlık ve isteğe bağlı bir seçenek nesnesi alır. MDN'in yapılacaklar listesi örneği, süresi geçen bir görev için gövde metni ve simge içeren bir bildirim oluşturur:

javascript
if (Notification.permission === "granted") {
  const img = "/img/icon-128.png";
  const text = `"${title}" görevinin süresi doldu.`;
  const notification = new Notification("Yapılacaklar", { body: text, icon: img });
}

Kalıcı bildirimde ise önce etkin bir service worker gerekir. navigator.serviceWorker.ready etkin worker'a sahip kaydı verir; showNotification() bu kayıt üzerinden çağrılır ve undefined ile çözülen bir promise döndürür. Service worker'ın durumu activating ya da activated değilse ya da kullanıcı izni açıkça reddetmişse TypeError fırlatılır.

javascript
navigator.serviceWorker.register("sw.js");

async function showNotification() {
  const result = await Notification.requestPermission();
  if (result === "granted") {
    const registration = await navigator.serviceWorker.ready;
    registration.showNotification("Yeni sipariş", {
      body: "1042 numaralı sipariş alındı.",
      icon: "/icons/192.png",
      tag: "siparis",
      data: { url: "/siparis/1042" },
    });
  }
}

Bildirim seçenekleri

Bildirim seçenekleri: body, icon, image, badge

showNotification() ve Notification() kurucusu benzer bir seçenek nesnesi alır. MDN'in showNotification() sayfasındaki listeden en sık kullanılanlar şunlardır; bazıları (örneğin actions ve navigate) yalnızca belirli bağlamlarda ya da tarayıcılarda geçerlidir, desteği MDN uyumluluk tablosundan kontrol edin.

SeçenekAnlamıVarsayılan
bodyBaşlığın altında görünen gövde metniBoş dize
iconBaşlık ve gövdenin yanında görünen küçük resim (logo, gönderen fotoğrafı)Yok
imageİçerikte gösterilen büyük resim; üç resim seçeneği arasında en yüksek görsel önceliğe sahipYok
badgeYer dar olduğunda (durum çubuğu gibi) uygulamayı temsil eden küçük simgeYok
tagBildirimi tanımlayan etiket; aynı etiketli bildirimler birbirinin yerine geçerBoş dize
renotifyYeni bildirim eskisinin yerine geçtiğinde kullanıcı yeniden uyarılsın mı; true ise tag zorunlufalse
requireInteractionKullanıcı tıklayana ya da kapatana kadar açık kalsın mıfalse
silentSes ve titreşim olmasın mı; true ise vibrate verilemeznull (cihaz ayarı)
vibrateTitreşim deseni; silent true ise kullanılamazYok
dataBildirimle ilişkilendirilen ve structured clone ile kopyalanabilen herhangi bir verinull
timestampBildirimin ilgili olduğu zaman, Unix milisaniyeYok
actionsBildirimde gösterilecek eylem düğmeleri (action, title, icon)Boş dizi
navigateBildirim etkinleştirilince gidilecek adres; click ve notificationclick yerine geçerYok

Seçenekler arasındaki iki kural showNotification() için ayrıca TypeError nedeni olarak listelenir: silent true iken vibrate vermek ve renotify true iken tag değerini boş bırakmak. data seri hâle getirilemezse DataCloneError alınır. Bu kuralları bildirimi göstermeden önce yakalamak için küçük bir denetim fonksiyonu yazdık ve Node.js 24 ile çalıştırdık; data için kullanılan structured clone algoritmasını Web Workers yazısında anlattık.

javascript
// showNotification() için MDN'de TypeError nedeni olarak sayılan iki seçenek kuralı
function secenekSorunlari(secenekler) {
  const sorunlar = [];
  if (secenekler.silent === true && "vibrate" in secenekler) {
    sorunlar.push("silent true iken vibrate verilemez");
  }
  if (secenekler.renotify === true && !secenekler.tag) {
    sorunlar.push("renotify true ise tag boş olamaz");
  }
  return sorunlar;
}

console.log(JSON.stringify(secenekSorunlari({ body: "Yeni sipariş", tag: "siparis" }))); // []
console.log(JSON.stringify(secenekSorunlari({ renotify: true, silent: true, vibrate: [200] })));
// ["silent true iken vibrate verilemez","renotify true ise tag boş olamaz"]

const veri = structuredClone({ siparisNo: 1042, url: "/siparis/1042" });
console.log(veri.url); // /siparis/1042

Bildirimleri tag ile değiştirmek

Kısa sürede çok sayıda bildirim kullanıcıyı rahatsız eder. Bunu önlemek için bildirime bir tag verilir. Aynı etikete sahip ve henüz gösterilmemiş bir bildirim varsa yeni bildirim onun yerine geçer; aynı etiketli bildirim zaten gösterilmişse eskisi kapatılır ve yenisi gösterilir. MDN'in örneğinde 200 milisaniye arayla on bildirim aynı tag ile oluşturulur ve kullanıcı yalnızca sonuncusunu görür. Yer değiştirmede kullanıcının yeniden sesli ya da titreşimli uyarılmasını istiyorsanız renotify: true kullanırsınız.

javascript
let i = 0;
const interval = setInterval(() => {
  // Aynı tag sayesinde yalnızca son bildirim görünür
  new Notification(`Mesaj ${i}`, { tag: "mesajlar" });
  if (i === 9) {
    clearInterval(interval);
  }
  i++;
}, 200);

Bildirim olayları ve close()

Kalıcı olmayan bildirimde Notification nesnesinde dört olay tetiklenir: kullanıcı tıkladığında click, bildirim kapandığında close, bildirim gösterilemediğinde error, gösterildiğinde show. Notification bir EventTarget olduğu için bunlar onclick gibi özelliklerle ya da addEventListener() ile dinlenebilir; olay dinleyicilerinin ayrıntıları addEventListener yazısında. MDN önemli bir uyarı ekler: close olayı geldiğinde bildirimi kullanıcının kapattığının garantisi yoktur, platform da kapatmış olabilir.

Kullanıcı için artık anlamsız olan bir bildirimi close() ile kaldırabilirsiniz; örneğin kullanıcı mesajı sayfada zaten okuduysa. MDN, modern tarayıcıların bildirimleri birkaç saniye sonra (yaklaşık dört saniye) kendiliğinden kapattığını ve bunun kullanıcıya ve tarayıcıya bırakılması gerektiğini belirtir. close() bildirimi bildirim tepsisinden de kaldırdığı için, onu yalnızca sabit bir süre sonra ekrandan kaldırmak amacıyla kullanmamak gerekir.

javascript
const n = new Notification("Yeni şarkı çalıyor");
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "visible") {
    // Sekme görünür oldu, bildirim artık gereksiz
    n.close();
  }
});

visibilitychange olayı ve sayfa yaşam döngüsünün diğer olayları sayfa yaşam döngüsü yazısında anlatılıyor.

Service worker tarafında notificationclick

Kalıcı bildirime tıklandığında service worker kapsamında notificationclick olayı tetiklenir; olay NotificationEvent türündedir, ExtendableEvent arayüzünden türediği için waitUntil() kullanılabilir, iptal edilemez ve kabarcıklanmaz. event.notification tıklanan bildirimi, event.action ise tıklanan eylem düğmesinin kimliğini verir. Aşağıdaki örnek MDN'den uyarlandı: önce bildirimi kapatır, sonra açık bir uygulama penceresi varsa ona odaklanır, yoksa yeni pencere açar.

javascript
// sw.js
self.addEventListener("notificationclick", (event) => {
  event.notification.close();
  if (event.action === "archive") {
    // Kullanıcı "Arşivle" düğmesine bastı
    return;
  }
  event.waitUntil(
    clients.matchAll({ type: "window" }).then((clientList) => {
      for (const client of clientList) {
        if (client.url === new URL("/", self.location.origin).href && "focus" in client) {
          return client.focus();
        }
      }
      if (clients.openWindow) return clients.openWindow("/");
    }),
  );
});

waitUntil() çağrısı, pencere açma ya da odaklama işi bitene kadar service worker'ın sonlandırılmamasını sağlar. Bildirim navigate seçeneğiyle oluşturulduysa tarayıcı bu olayı tetiklemek yerine doğrudan o adrese gider; bu seçeneğin desteği için MDN uyumluluk tablosuna bakın. Aynı kayıt üzerinden gösterilen bildirimlerin listesi registration.getNotifications() ile alınabilir; { tag } seçeneği listeyi etikete göre süzer. Aynı origin'deki farklı kapsamlı service worker'lar birbirinin bildirimlerini göremez.

Eylem düğmeleri: actions

Kalıcı bildirimlere actions seçeneğiyle düğmeler eklenebilir. Her öğe benzersiz bir action kimliği ve kullanıcıya gösterilecek title metni taşır, isteğe bağlı olarak icon da alır. Kullanıcı bir düğmeye bastığında notificationclick işleyicisinde event.action o kimliği verir; kullanıcı bir düğme dışında bir yere tıkladıysa ya da bildirimde düğme yoksa değer boş dizedir ve yukarıdaki örnekte olduğu gibi varsayılan yola düşülür. Tarayıcılar bir bildirimde gösterecekleri eylem sayısını genellikle sınırlar; bu üst sınır Notification.maxActions statik özelliğinden okunur. MDN'in örneği bir e-posta bildirimine "Archive" düğmesi ekler:

javascript
navigator.serviceWorker.ready.then((registration) => {
  registration.showNotification("New mail from Alice", {
    actions: [
      {
        action: "archive",
        title: "Archive",
      },
    ],
  });
});

Sık yapılan hatalar

Sık yapılan hatalar: Sayfa yüklenir yüklenmez requestPermission() çağırmak. İzin bir kullanıcı..., Mobilde new Notification() kullanmak. Çoğu mobil tarayıcıda TypeError...
  • Sayfa yüklenir yüklenmez requestPermission() çağırmak. İzin bir kullanıcı hareketine yanıt olarak istenmelidir.
  • Mobilde new Notification() kullanmak. Çoğu mobil tarayıcıda TypeError fırlatır; service worker ve showNotification() kullanın.
  • Notification.permission değerine bakmadan bildirim oluşturmak. "default" ve "denied" durumunda bildirim gösterilmez.
  • HTTP sitede bildirim izni istemek. MDN'e göre bazı tarayıcılar güvenli bağlam olmadan izin istemine izin vermez.
  • Her mesaj için ayrı bildirim göndermek. Aynı türdeki bildirimleri tag ile birleştirin.
  • renotify: true verip tag eklememek ya da silent: true ile vibrate birlikte vermek. İkisi de TypeError nedenidir.
  • Bildirimi sabit bir süre sonra close() ile kapatmak. Bildirim tepsiden de silinir ve kullanıcı sonradan göremez.
  • notificationclick içinde pencere açma işini waitUntil() ile sarmamak. Service worker iş bitmeden durdurulabilir.

Sık Sorulan Sorular

Kullanıcı izni reddettiyse yeniden sorabilir miyim?

Notification.permission "denied" olduğunda kullanıcı açıkça reddetmiş demektir. MDN'in örneği bu durumda bildirim yerine sayfa içi bir mesajla yetinir ve düğmeyi görünür bırakarak kullanıcının fikrini değiştirmesine alan tanır. İzin kararı genellikle tarayıcı ayarlarından değiştirilir.

Sayfa kapalıyken bildirim gösterebilir miyim?

Sayfa tarafındaki Notification() ile hayır; ömrü sayfaya bağlıdır. Service worker'dan showNotification() ile gösterilen kalıcı bildirimler sayfanın ömrünü aşabilir. Sunucunun tetiklediği bildirimler ise Push API ile service worker'ı uyandırmayı gerektirir.

Bildirime tıklayınca belirli bir sayfayı nasıl açarım?

Kalıcı bildirimde data seçeneğine adresi koyup notificationclick içinde clients.openWindow(event.notification.data.url) çağırabilirsiniz. Alternatif olarak navigate seçeneği, olay işleyici yazmadan doğrudan adrese gitmeyi sağlar; desteğini MDN uyumluluk tablosundan kontrol edin.

Bildirim kendiliğinden kapanıyor, açık kalmasını sağlayabilir miyim?

requireInteraction: true seçeneği, bildirimin kullanıcı tıklayana ya da kapatana kadar açık kalması gerektiğini belirtir. Son kararı yine platform ve tarayıcı verir.

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 · Push bildirim nedir · Service worker kaydı · PWA ve manifest · İzin ve güvenli bağlam hataları