---
title: "DropletNotificationService, DroppyKit"
description: "Posts notifications into Droppy&#x27;s own banner stack (1.23.0)."
canonical: "https://getdroppy.app/docs/droppykit/api/droplet-notification-service"
last-updated: "2026-09-09"
---

# DropletNotificationService

Posts notifications into Droppy's own banner stack (1.23.0).

`@MainActor protocol DropletNotificationService : AnyObject`

Requires the `notch-banner` capability. Read it as [`notifications`](https://getdroppy.app/docs/droppykit/api/droplet-host#notifications).

What Droppy does with a post, so you do not have to:

- It waits its turn. Banners queue first in, first out behind whatever holds the notch (a system HUD, another banner, an open shelf), and several arriving together stack as rows under one banner.
- It respects the user. Focus silences it the way it silences every app's banners, "Show previews" hides its body, and the user can turn your droplet's notifications off on its page in Settings.
- It is bounded. A handful of new posts a minute; past that, posts are refused until the minute is up.

Available from DroppyKit 1.23.0: declare `minAPI` 1.23.0.

## Properties

### events

`@MainActor var events: AnyPublisher<DropletNotificationEvent, Never> { get }`

What happened to this droplet's notifications, on the main actor.

## Methods

### post(_:)

`@discardableResult @MainActor func post(_ notification: DropletNotification) -> Bool`

Posts a notification. Returns `false` when Droppy refused it: the droplet lacks `notch-banner`, the user turned its notifications off, Focus is silencing banners, or it is over its budget. `true` means it is on screen or waiting in the queue.

### withdraw(id:)

`@MainActor func withdraw(id: String)`

Takes one of this droplet's notifications away, on screen or waiting. Does nothing for an id that is neither.

### withdrawAll()

`@MainActor func withdrawAll()`

Takes every one of this droplet's notifications away.
