home / skills / vladimirbrejcha / ios-ai-skills / silent-pushes-setup
This skill helps you set up, debug, and validate iOS silent pushes with APNs, ensuring correct entitlements, registration, and widget refresh.
npx playbooks add skill vladimirbrejcha/ios-ai-skills --skill silent-pushes-setupReview the files below or copy the command above to add this skill to your agents.
---
name: silent-pushes-setup
description: Setup, debug, or validate iOS silent (background) push notifications with APNs, including entitlements, device token registration, backend APNs sending, and widget refresh. Use for silent push setup or troubleshooting (aps-environment errors, token registration, background delivery, APNs headers).
---
# Silent Pushes Setup (iOS + APNs + Backend)
## When to use
Use this skill when the user asks about:
- Silent/background push notifications on iOS
- APNs device token registration
- `aps-environment` entitlement errors
- Backend APNs sending (headers, payloads, JWT)
- Widget refresh triggered by pushes
- Debugging push delivery, throttling, or missing pushes
## Quick path (agent)
1. **Confirm environment**
- Real device vs simulator, Debug vs Release/TestFlight.
- Bundle ID + Team ID.
- Backend environment (prod vs dev) and APNs host.
2. **Verify entitlements in the signed app**
- Inspect entitlements in the built app binary (`codesign -d --entitlements :- ...`).
- Ensure `aps-environment` exists and matches build (`development` for Debug, `production` for Release).
3. **Verify registration flow**
- App calls `registerForRemoteNotifications()` at launch.
- Token is received in delegate and sent to backend.
- Backend stores token + environment.
4. **Verify APNs request**
- Host: `api.sandbox.push.apple.com` (Debug) or `api.push.apple.com` (Release).
- Headers: `apns-push-type: background`, `apns-priority: 5`, `apns-topic: <bundle-id>`.
- Payload: `{ "aps": { "content-available": 1 } }` with no alert/sound/badge keys.
5. **Verify background handling**
- Implement `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`.
- Trigger incremental sync and `WidgetCenter.shared.reloadAllTimelines()`.
6. **Validate throttling behavior**
- Background pushes are best‑effort and may be delayed or coalesced.
## Manual steps (human)
1. **Apple Developer**
- Enable Push Notifications capability on the App ID.
- Token‑based APNs key (p8) is sufficient; no APNs certificate required.
2. **Xcode**
- Add **Push Notifications** capability to app target.
- Add **Background Modes → Remote notifications**.
- Use entitlements with explicit `aps-environment` per build config.
3. **Install & test**
- Build and run on a physical device.
- Confirm device token registration success in logs.
- Trigger backend change and verify push + widget refresh.
## Validation checklist
- [ ] Signed entitlements include `aps-environment`.
- [ ] Device token is stored on backend with environment.
- [ ] APNs request returns 200 and backend records `last_push_at`.
- [ ] App receives background push and updates widget.
## Common issues and fixes (from recent work)
- **Error: “no valid aps‑environment entitlement string found”**
- Root cause: wrong entitlement key or profile stripping it.
- Fix: use `aps-environment` (iOS) not `com.apple.developer.aps-environment` (macOS), and ensure it exists in the *signed* app entitlements.
- **Push capability shows in Xcode but still failing**
- XcodeGen projects can ignore UI toggles. Ensure entitlements are correct in source and the signed app contains `aps-environment`.
- **Duplicate push token registration (UNIQUE constraint)**
- Backend should treat `/v1/device/push/register` as idempotent (upsert + update timestamp).
- **No push after manual refresh**
- Pushes are only sent when data changes and when the backend path actually triggers `sendPushes` (often cron). This is expected.
- **Posts show on previous day**
- Cause: local cache normalized to UTC. Fix: store/display days using local day boundary.
- **Wrangler tail error on close**
- Tail session deletion can fail; this is a Wrangler cleanup issue, not a backend bug.
## References
- Apple docs (background pushes, APNs registration, APNs requests): see `references/apple-docs.md`.
- Codex skill format/reference: see `references/codex-skills.md`.
- Troubleshooting details and commands: see `references/troubleshooting.md`.
This skill helps you set up, validate, and debug iOS silent (background) push notifications via APNs. It covers entitlements, device token registration, correct APNs requests (headers and payload), background handling in the app, and widget refresh behavior. Use it to confirm environment, diagnose delivery failures, and verify backend integration.
The skill walks through a stepwise inspection of the signed app entitlements, runtime token registration, backend token storage, and the APNs HTTP/2 request details. It verifies the correct APNs host, required headers (apns-push-type, apns-priority, apns-topic), and minimal payload for background pushes. It also checks the app-side background handler and widget refresh calls, and explains expected throttling and best-effort delivery behavior.
Why am I not receiving silent pushes on my device?
Confirm you are on a physical device, the app is signed with aps-environment for the correct environment, registerForRemoteNotifications completed and the token was stored on the backend, and the backend sent a background APNs request with apns-push-type: background and content-available:1. Also expect best-effort delivery and possible throttling.
Which APNs host and headers should my backend use for silent pushes?
Use api.sandbox.push.apple.com for development and api.push.apple.com for production. Include apns-push-type: background, apns-priority: 5, and apns-topic equal to the app bundle ID. Payload should be {"aps":{"content-available":1}} with no alert/sound/badge.