How push notifications work

Code hosts announce events with webhooks. Phones receive push notifications through Apple and Google. The two cannot talk to each other directly, so Source Pocket puts a small relay in between. You decide who runs it, and the app still works with no relay at all.

Three ways to run it

Relay modes compared
ModeHow it worksTrade-off
Hosted relay We run the relay. Webhooks from your repositories point at it. Least setup. We can see event metadata, such as which repository had a failed run.
Self-hosted relay You run the open-source relay on your own Cloudflare account or as a Docker container, and give the app its URL for each account. You control webhooks and event data. Delivery to phones still goes through our push gateway, described below.
No relay The app polls while it is open and refreshes in the background when the operating system allows. No instant push, no Live Activity updates, and the Bitbucket inbox is partial.

What happens to an event

  1. When you turn on push for a repository, the app creates a webhook on the provider that points at a relay URL for that repository, with a secret only the relay and the provider know.
  2. When the provider sends an event, the relay checks the signature, drops duplicates, and converts the event into one common format.
  3. The relay matches the event to devices using your subscriptions: which accounts, repositories, and event types you follow, and your quiet hours.
  4. The relay sends the notification through Apple Push Notification service or Firebase Cloud Messaging. A burst of events, such as twenty steps finishing at once, becomes one notification per run.

The target is under 15 seconds from the provider's event to your phone for 95 percent of events.

What the relay stores, and what it does not

Stored

  • Device push tokens, so it knows where to deliver.
  • Your subscription filters: accounts, repositories, event types, and quiet hours.
  • Webhook secrets, so it can verify that events came from your provider.

Not stored

  • Source code, diffs, or build logs.
  • Your provider passwords or access tokens, wherever a webhook secret is enough. Some providers need admin rights to create a webhook; in that case the app makes that one call with your token, on your device, and the token is not sent to the relay.
  • Event bodies. They are processed in memory and discarded after delivery.

Private mode

Planned for version 1.1. The relay encrypts each notification to a key held only on your device, and the app decrypts it on the phone (in a Notification Service Extension on iOS, or the message handler on Android). The relay operator, Apple, and Google can see that a notification was sent, but not what it says.

The push gateway

Apple and Google issue push credentials to the publisher of an app, not to its users. A relay you host yourself therefore cannot push to the store version of Source Pocket on its own. It sends a device token and an encrypted payload to our push gateway, which holds the credentials and forwards the message without being able to read it. Matrix and ntfy use the same pattern.

Why Bitbucket needs the relay for its inbox

GitHub, GitLab, and Gitea offer an API that lists your notifications. Bitbucket Cloud does not. Without the relay, the app can only build a Bitbucket inbox by polling the pull requests you author or review while the app is open, and it marks that history as partial.

Running your own relay

The relay is open source and runs on Cloudflare Workers, with a Docker image for other hosts. Its code lives in packages/relay in the Source Pocket repository, and setup steps are in packages/relay/README.md. The core app will be free; paid features will be announced closer to launch.