macOS Internals · usernoted · SQLite

Where macOS stores Notification Center alerts (group.com.apple.usernoted)

Because macOS offers no public API to observe other apps' notifications, every Mac-to-iPhone notification forwarder reads the per-user usernoted SQLite database. Here is how it works and how to read it without granting Full Disk Access.

Updated · macOS 15.0 or later · 7-day trial

In short

  • macOS stores active Notification Center alerts in ~/Library/Group Containers/group.com.apple.usernoted/db2/db using SQLite WAL mode.
  • Each row in the record table links an app bundle identifier to a Core Data timestamp and a binary plist containing the title, subtitle, and body.
  • Because WAL mode uses db-wal alongside db, readers need read-only access to the db2 folder—not just the db file.
  • NotiFerry runs in the App Sandbox and uses a read-only folder bookmark to db2 instead of requesting Full Disk Access.

Why macOS has no public cross-app notification API

Developers looking to automate or forward macOS notifications quickly discover a platform gap: Apple's UNUserNotificationCenter framework only lets an app schedule and inspect its own notifications, scoped to its bundle identifier. Unlike Android's NotificationListenerService, macOS provides no public entitlement or observer API for a third-party utility to subscribe to banners posted by other apps.

Instead, the per-user system daemon usernoted receives notification requests from apps across the Mac and persists active Notification Center entries in a local SQLite database inside the user's home directory:

# Per-user Notification Center database directory on macOS 15 Sequoia
~/Library/Group Containers/group.com.apple.usernoted/db2/

# Files inside db2/
db        # Main SQLite 3 database
db-wal    # Write-Ahead Log containing recent uncommitted/checkpointed frames
db-shm    # Shared-memory index for WAL readers

Inside the usernoted db2 SQLite schema

Because usernoted opens the database in SQLite Write-Ahead Logging (WAL) mode, newly delivered banners live in db-wal until a checkpoint flushes them into db. Any tool that reads the database must therefore have read access to the entire db2 directory (not only the db file) so SQLite can see both db and db-wal.

Two tables hold the information a notification forwarder needs:

  • app: maps an integer app_id to the sending application's bundle identifier (identifier, such as com.apple.dt.Xcode or com.todesktop.230313mzl4w4u92).
  • record: stores each notification row with a monotonically increasing rec_id, foreign key app_id, delivered_date (seconds since Apple's Core Data reference date of 2001-01-01 00:00:00 UTC, which is 978307200 seconds after the Unix epoch), and a binary property list (bplist00) blob in data containing the notification's req.titl (title), req.subt (subtitle), and req.body (body).
# Read-only inspection of recent notification records (macOS 15)
sqlite3 -readonly \
  "$HOME/Library/Group Containers/group.com.apple.usernoted/db2/db" \
  "SELECT r.rec_id, a.identifier, datetime(r.delivered_date + 978307200, 'unixepoch') AS delivered_utc, length(r.data) AS bytes FROM record r JOIN app a ON r.app_id = a.app_id ORDER BY r.rec_id DESC LIMIT 5;"

Security: single-folder read-only access vs Full Disk Access

On modern macOS, ~/Library/Group Containers/group.com.apple.usernoted is protected by Transparency, Consent, and Control (TCC). Utilities that read this database take one of two security approaches:

Access modelWhat the user grantsBlast radius
Full Disk Access (TCC)System Settings → Privacy & Security → Full Disk AccessApp can read Mail, Messages, Safari history, SSH keys, and every file on the Mac
App Sandbox + security-scoped folder bookmark (NotiFerry)Select the db2 folder once in a standard macOS Open dialogRead-only access to that single db2 folder; no access to the rest of your disk

NotiFerry runs inside the macOS App Sandbox and uses a read-only security-scoped bookmark to db2. It never asks for Full Disk Access or Accessibility permissions, opens the SQLite database in read-only mode so it never locks or mutates usernoted state, and resolves bundle identifiers to the friendly application names Finder displays.

Real-world edge cases when polling usernoted

If you build or choose a tool that reads usernoted, watch out for three practical quirks on macOS 15:

  1. Future timestamps in delivered_date: scheduled or calendar-adjacent system notifications can occasionally appear in record with a timestamp hours in the future. A naive high-water mark on delivered_date will stall all subsequent forwarding until wall-clock time catches up. NotiFerry filters out future-dated rows and repairs invalid cursors automatically.
  2. Paused-window floods: if you pause forwarding for a meeting, you do not want 40 stale banners dumped onto your iPhone when you resume. NotiFerry advances its cursor across paused intervals so only fresh notifications after resuming are sent.
  3. Sensitive message bodies: notification bodies often contain 2FA codes, private messages, or customer data. NotiFerry defaults to Title only (or Generic alert) and lets you disable individual apps with one click in the menu bar.
The menu-bar app

See how NotiFerry runs on your Mac

Grant read-only access to the Notification Center folder (no Full Disk Access), subscribe to your private ntfy topic in the free iPhone app, and confirm that a real test arrived to start your 7-day trial.

Download 7-day free trialbrew install --cask n2ctech/tap/notiferry
What arrives on iPhone (in ntfy)
ntfynow

Claude Code — Permission required

Allow Bash tool in notiferry? · Full notification or Title only

ntfy · burst folded2m ago

Xcode — Build Succeeded (+4 earlier alerts)

NotiFerry dashboard on macOS with forwarding switched on, nine notifications forwarded this session, privacy mode, and buttons to send a phone test and copy the private topic link
NotiFerry on macOS: forwarding status, privacy mode, and one-click phone test confirmation.

Questions

Can reading the usernoted SQLite database corrupt Notification Center?

Not when opened with SQLite's read-only flag (SQLITE_OPEN_READONLY). In WAL mode, SQLite supports concurrent read-only readers alongside usernoted without blocking deliveries or modifying the database files.

Does the usernoted database store notifications after I dismiss them?

usernoted keeps active Notification Center entries in record and prunes rows as banners expire or are cleared from Notification Center. Ephemeral banners that are configured as None in System Settings → Notifications may not be written to record.

Why does Apple not document group.com.apple.usernoted?

group.com.apple.usernoted is an internal macOS storage container for the Notification Center daemon. Because it is undocumented, its schema can change in a future macOS release, which is why any Notification Center forwarder is best-effort.

How do I forward new usernoted records to my iPhone without writing a script?

Install NotiFerry on your Mac and the free ntfy app on your iPhone. Authorize the db2 folder read-only once, scan the topic QR code, and confirm the test alert.

Founding release

Forward macOS Notification Center alerts to your iPhone without Full Disk Access.

The trial starts only after you confirm that a real test reached your phone. Keep NotiFerry with a one-time €9.99license for up to 2 Macs. Purchases include a 30-day full-refund window; mandatory consumer rights remain unaffected.

Download the 7-day free trialOr buy a license now · €9.99brew install --cask n2ctech/tap/notiferryOne-time purchase · up to 2 Macs · periodic online license validation