Frame docs · Run your server
Push notifications and the relay
Apple and Google only deliver notifications that are signed with the app publisher's keys, and self-hosted servers can't have those. So your server hands notifications to a small relay run by Crow Tech, the Frame publisher, at https://frame.crow.sg, which passes them on to Apple (APNs) for iPhones and to Google (FCM) for Android phones. Nothing to set up: it's on by default.
What the relay can see
The relay is built to learn as little as possible:
- The content is end-to-end encrypted. Each phone makes its own key and shares it only with your server. The relay, Apple and Google only see ciphertext plus a generic "Frame: New activity". The phone decrypts the notification and shows the real text and thumbnail.
- The relay stores nothing. It has no database and doesn't log device tokens, payloads or IP addresses.
- Your server never sees the phones' real push tokens, only sealed relay tokens that only the relay can open. Your server can't use them to push to anyone else's device.
What the relay can know is that some server, identified by its IP address, asked it to deliver a notification of a certain size at a certain time. It could also drop or delay notifications. It can't read content or learn who your users are.
Push permission expires
Each phone's relay token stops working after 60 days. The apps fetch a fresh one every time they open and send it to your server, so phones that are in use never notice. If someone uninstalls the app or stops using a server, that server loses the ability to notify them after at most 60 days. Signing out removes it immediately.
Widgets
New photos also refresh your friends' home-screen widgets. On iPhone (iOS 26 and later) the server sends a separate widget push for every new moment, so widgets update even when notifications are muted. Without push, widgets refresh about every 15 minutes.
Turn push off
Set an empty value and restart:
FRAME_PUSH_RELAY=The apps still work. Widgets refresh about every 15 minutes, and the app updates live while it's open. Notifications for new messages only arrive when the app is opened. Running your own relay only makes sense if you also build and sign the apps yourself; the protocol is in PUSH.md.
When notifications don't arrive
Check that
FRAME_PUSH_RELAYisn't empty. The admin panel's Overview shows whether the relay is reachable.Check that the server can reach the internet:
Terminalcurl -sI https://frame.crow.sg/healthz # can the server reach the relay?journalctl -u frame | grep "push failed" # or: docker compose logs frame | grep "push failed"On the phone, allow notifications for Frame. On Android, also turn off battery optimisation for Frame. On iOS, check Focus modes.
For AI tools: this page as Markdown, the page index and all pages in one file.