Push notifications (iOS)
On iOS, Pincer can only post notifications while it’s running and connected. To get notified about finished replies and approvals while it’s closed, you need a push relay.
On macOS you don’t need any of this. Mac notifications arrive while Pincer is running and connected, and the Push relay setting only exists on iOS.
Why a relay
Section titled “Why a relay”iOS gives a suspended app no network, so Pincer can’t keep its connection to the gateway open. Only Apple’s push service (APNs) can wake it, and only a server holding the APNs key of the team that signed the app can send those pushes.
Your gateway sends notifications as standard Web Push instead. The relay is a small server that turns one into the other:
Gateway ──Web Push (encrypted)──▶ relay ──APNs──▶ iPhone ──▶ Pincer decrypts itThe gateway pushes when a reply finishes, an exec approval is waiting, an agent asks a question, or a task fails.
What the relay and Apple can see
Section titled “What the relay and Apple can see”- Not the content. Each notification is end-to-end encrypted (RFC 8291) to a key that exists only on your device. A notification service extension decrypts it on the phone, so neither the relay nor Apple can read it.
- Not much, even decrypted. The gateway sends only a generic title, such as “OpenClaw agent finished”, and which chat or approval it’s about. It never sends message content. Pincer loads the content when you open the notification.
- Not your device token. The relay seals the APNs token into an opaque id, so the gateway never sees it.
- Nothing stored. The relay keeps no database.
The encryption keys are separate for each gateway and stored in the Keychain as this device only. Removing a gateway from Pincer unsubscribes it and deletes its keys.
Set up the relay
Section titled “Set up the relay”The relay is a Node server with no dependencies. The easiest place to run it is the gateway machine. You’ll need:
- Node.js 20 or newer;
- Tailscale on that machine, for HTTPS;
- access to the Apple Developer account that signs your copy of Pincer.
-
Create an APNs key. At developer.apple.com → Keys, click +:
- Key Name:
Pincer Push Relay; - enable Apple Push Notifications service (APNs), then Configure;
- Environment: Sandbox & Production;
- Key restriction: Team Scoped (All Topics), or Topic Specific with
chat.pincer.ios.
Download
AuthKey_XXXXXXXXXX.p8. You can only download it once, so keep a copy. Note the Key ID and your Team ID. - Key Name:
-
Install the relay. On the gateway machine, from a checkout of the Pincer repo:
Terminal window cd push-relaycp ~/Downloads/AuthKey_XXXXXXXXXX.p8 AuthKey.p8./install-service.shThe first run creates
.envwith a randomRELAY_SECRET. SetAPNS_KEY_IDandAPNS_TEAM_IDin it, then run./install-service.shagain. It installs a launchd service on macOS, or a systemd--userservice on Linux, and checks that the relay answers onhttp://127.0.0.1:8787. -
Publish it over HTTPS:
Terminal window ./install-service.sh --serve# or by hand:tailscale serve --bg --https=8443 http://127.0.0.1:8787The URL looks like
https://gateway-host.your-tailnet.ts.net:8443. Iftailscale servecomplains about HTTPS, turn on MagicDNS and HTTPS Certificates in the Tailscale admin console. The relay has to be reachable from both your iPhone and the gateway. -
Turn it on in Pincer. See the next section.
Other HTTPS front ends, such as Caddy or a Cloudflare Tunnel, work too. The push relay README has every option.
Turn it on in Pincer
Section titled “Turn it on in Pincer”On your iPhone or iPad:
- Go to Settings → Notifications.
- Keep Notify about replies and approvals on, and allow notifications when iOS asks.
- Enter the relay’s URL under Push relay, then tap return.
Each gateway gets a row with its push status. It should show Push on within a few seconds.
To test it, send a message, then close Pincer from the app switcher before the reply finishes. You should get an “OpenClaw agent finished” notification that opens the chat.
The relay URL has to start with https://. Plain http:// only works for localhost, 127.0.0.1 and ::1. Turning off Notify about replies and approvals also turns push off.
Status
Section titled “Status”| Status | What it means |
|---|---|
| Push on | Subscribed. The gateway pushes through the relay. |
| Waiting for APNs | iOS hasn’t given Pincer a device token yet. Check that notifications are allowed for Pincer in iOS Settings. |
| Relay must be https:// | The URL isn’t https://. |
| Gateway has no Web Push | The gateway doesn’t support push.web.subscribe. Update OpenClaw. |
| Push off | Notifications are off, or there’s no relay URL yet. |
| Not connected | Pincer subscribes each time it connects. Open the gateway. |
| Anything else | An error, such as “Push relay refused registration (…)”. Usually the phone can’t reach the relay. |
To check the relay from your phone, open https://…:8443/healthz in Safari. It should show {"ok":true}.
Approving from a push
Section titled “Approving from a push”Approval pushes have the same actions as Pincer’s own notifications: Allow once, Always allow and Deny. A push doesn’t know whether Always allow is permitted, so it always offers it. If it isn’t, you get a follow-up saying “Always allow isn’t available for this command.” with Allow once and Deny. See Answering from a notification.
If a push can’t be decrypted, for example because you removed the gateway, iOS shows a generic “New notification” alert instead.
No double alerts
Section titled “No double alerts”Once push is working for a gateway, you won’t get the same notification twice:
- while Pincer is in the background, it stops posting its own notifications for that gateway and leaves it to push;
- while Pincer is open and connected to that gateway, pushes from it are hidden.
Managing the relay
Section titled “Managing the relay”./install-service.sh --print # show the service definition./install-service.sh # reinstall after editing .env or upgrading Node./install-service.sh --uninstallOn Linux, run sudo loginctl enable-linger $USER so the relay keeps running while you’re logged out.
Logs are in ~/Library/Logs/pincer-push-relay.log on macOS, or journalctl --user -u pincer-push-relay on Linux. The relay logs one line per push:
InvalidProviderTokenor403: the Key ID, Team ID or.p8don’t match, or the key doesn’t allow this environment or bundle id.BadDeviceToken: the token is stale. Reopen Pincer.DeviceTokenNotForTopic: the key is Topic Specific for a different bundle id.- No
pushlines at all: the gateway can’t reach the relay.
More fixes are in Troubleshooting.