A small Safari Web Extension that shows the number of unread Inbox mails as a red badge on the Outlook PWA's dock icon (the standalone Outlook web app added to the macOS Dock via Safari).
Modern Outlook (outlook.cloud.microsoft) doesn't keep the dock badge sticky — as soon as you open the inbox, Outlook clears it. This extension hijacks Outlook's calls to navigator.setAppBadge/clearAppBadge and keeps the badge in sync with the actual unread count.
You received OutlookSafariBadge.zip.
- Unzip →
OutlookSafariBadge.app - Drag & drop into
/Applications/ - First launch: right-click the app → „Open" → in the dialog confirm with „Open" (one-time Gatekeeper bypass — the app isn't App-Store-signed)
- The app runs briefly to register the extension with Safari. You can quit it afterwards.
- Safari → Settings (⌘,) → tab „Advanced" → enable „Show features for web developers"
- Safari menu bar → „Develop" → enable „Allow Unsigned Extensions"
⚠️ You must re-enable this after every Safari restart — Apple's security policy for non-certified extensions. - Safari → Settings → „Extensions" → tick „Outlook Unread Badge"
- In the permissions on the right → for
outlook.cloud.microsoft→ „Always Allow on This Website" - Open Outlook PWA from the dock (or as a Safari tab) — badge appears as soon as there are unread mails.
Requirements on the Mac:
- macOS 14+
- Safari 17.4+
- Outlook added as PWA (Safari → File → „Add to Dock") or open as a tab
# Install Xcode from the App Store (free), then:
./setup.sh
# → Generates the Xcode project from the sources in Extension/./build-release.sh # produces dist/OutlookSafariBadge.app (ad-hoc signed, doesn't expire)
./package.sh # packages it into dist/OutlookSafariBadge.zipDistribute the zip. Recipients follow the „For end users" section above.
open dist/OutlookSafariBadge.app
# Then verify in Safari that the extension is active
# and the badge appears on the Outlook PWA dock icon.- Edit files in
Extension/(badge.js,manifest.json) - If icons changed:
swift generate-icons.swift . - Run
./build-release.shagain - Distribute the new zip
| Issue | Impact |
|---|---|
| „Allow Unsigned Extensions" toggle | resets after every Safari quit — must be re-enabled |
| Gatekeeper on first launch | one-time right-click → „Open" per Mac |
| No auto-update | new versions must be distributed manually |
| Not notarized | some security tools may warn |
| Badge persists after quitting the PWA | Mail.app-style: the dock badge keeps its last value until the PWA is reopened. The Web Badging API stores the badge at the OS level by design and can't be cleared reliably from JavaScript at process termination. Reopen the PWA and the badge re-syncs to the actual unread count within ~2 s. |
With Apple Developer Program ($99/yr) + notarization these would all go away.
Extension/badge.jsruns in Outlook's main world ("world": "MAIN"in the manifest), so it can directly interceptnavigator.setAppBadge().- Outlook's own
setAppBadge/clearAppBadgecalls are hijacked into no-ops — otherwise Outlook would wipe our badge as soon as the inbox is viewed. - The unread count is read primarily from
[role="treeitem"][title="Posteingang - N Elemente (X ungelesen)"](the folder tree's tooltip), with fallbacks ondocument.titleand countingaria-label^="Ungelesen "mail rows. - A
MutationObservertriggers updates on DOM changes, plus a 10-second safety-net interval.
OutlookSafariBadge/
├── Extension/ ← Web Extension source
│ ├── manifest.json
│ ├── badge.js
│ └── icons/ ← 48/96/128 px
├── OutlookSafariBadge/ ← generated Xcode project (gitignored)
├── dist/ ← build output (.app + .zip, gitignored)
├── setup.sh ← generates Xcode project from Extension/
├── build-release.sh ← builds release .app
├── package.sh ← packages .app into .zip
├── generate-icons.swift ← icon generator
└── README.md
MIT — see LICENSE.