Add Set up custom push notifications how-to#5080
Conversation
Documents the end-to-end flow for routing trigger push notifications to a custom mobile app instead of the Viam mobile app: Firebase service-account upload via `viam organizations firebase-config set`, device-token registration through the Flutter SDK or raw gRPC, the fragment-ownership trust gate that authorizes a machine to receive pushes for a non-Viam app, trigger config with the `application` field, and a verify/troubleshoot section keyed to the actual server- side log messages. Cross-links: docs/monitor/alert.md, docs/data/trigger-on-data.md, docs/reference/triggers.md, and the application field plus `organizations firebase-config set` section of docs/cli/reference.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
✅ Deploy Preview for viam-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
| | `device_token` | FCM registration token from `FirebaseMessaging.getToken()`. On iOS, call `getAPNSToken()` first; FCM normalizes both. | | ||
| | `device_uuid` | A stable device identifier. Android: `android.id` from `device_info_plus`. iOS: `identifierForVendor`. | | ||
|
|
||
| User identity comes from the authenticated Viam session on the call, so there is no `user_id` parameter. |
There was a problem hiding this comment.
probably don't need to call out the lack of a user_id parameter
| A user can have parallel tokens for `com.viam.viammobile` and a custom app, and only the matching set receives any given push. | ||
| - Viam prunes dead tokens automatically when FCM reports "not registered." | ||
| No server-side cleanup is required for stale tokens. | ||
| - Calling `DeleteDevicePushToken` on logout is still recommended so a shared device does not receive notifications for the previous user. |
There was a problem hiding this comment.
| - Calling `DeleteDevicePushToken` on logout is still recommended so a shared device does not receive notifications for the previous user. | |
| - Calling `DeleteDevicePushToken` on logout is still required so a shared device does not receive notifications for the previous user. |
| `com.viam.viammobile` is exempt from this check. | ||
| Triggers targeting the Viam mobile app work on any machine the recipient owns or operates. |
There was a problem hiding this comment.
might be unnecessary since this section is about third party apps
|
overall looks good but I left a couple of suggestions
also, in reference to this question, I don't personally think we need to give a full explanation as to why this is the design. it's just to add an extra layer of security so that only app owners can send push notifications to their app. without this, anyone who knows the bundle id could theoretically send push notifications to an app they don't own |
The "import that fragment" step was vague. Replace with the actual click sequence the configuration-block dialog uses (`+` → **Configuration block** → search → **Add fragment**) and link to the existing fragments how-to for the "create a fragment" half of the step. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "the Viam mobile app re-uploads if the stored token is older than 30 days" detail came from internal mobile-app code; it can't be verified from public source and is implementation detail that third-party app authors should choose for themselves. Replace with generic guidance to pick a cadence on app startup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ements The Required-fields table stated `FirebaseMessaging.getToken()`, `getAPNSToken()`, `android.id`/`device_info_plus`, and `identifierForVendor` as if they were Viam requirements. They are the Viam mobile app's choices and one valid pattern per platform. Reframe to separate the Viam requirement (an FCM token; a stable device identifier) from the Viam-mobile-app implementation. Surfaced by the identifier sweep during the Playbook 1 pass: these identifiers do not appear in any in-scope public repo and were sourced to the private viam-mobile repo only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three Missing/Prose findings surfaced by walking the page as a first-time reader: - F-WALK-1: Prereqs list mentioned `viam login` but left readers staring at `--org-id <your-org-id>` placeholders with no path to find their org ID. Added one bullet pointing to app.viam.com and `viam organizations list`. - F-WALK-2: Section 3 implied (correctly) that the fragment's owning org must match the Firebase-config-owning org, but did not name the cross-org case. Added a one-sentence clarification that the check compares the fragment's owner, not the machine's. - F-WALK-3: Section 5 verify step did not point readers to the Troubleshoot table for the "no notification arrived" case. Added a one-line pointer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Summary
Documents the end-to-end flow for routing trigger push notifications to a custom mobile app instead of the Viam mobile app. Closes the docs follow-up identified during review of #5079.
The new page at
docs/monitor/custom-push-notifications.mdcovers:viam organizations firebase-config set(with the constraint that it's the Admin SDK service account, notgoogle-services.json/GoogleService-Info.plist).uploadDevicePushToken/deleteDevicePushToken/getDevicePushTokens) for the one language that has them today, plus raw gRPC notes for Python / TypeScript / Go / C++.applicationonly delivers if the machine imports a fragment owned by the same organization that uploaded the Firebase config.com.viam.viammobileis exempt by literal name.applicationfield.trigger push notification failed: app authorization check,recipient is not a robot owner or operator).Cross-links added from
docs/monitor/alert.md,docs/data/trigger-on-data.md,docs/reference/triggers.md, and both theapplicationline and theorganizations firebase-config setentry indocs/cli/reference.md.Open questions for @clintpurser and @martha-johnston
Design rationale: why fragment-ownership?
The page documents what the fragment-ownership trust gate is, but not why the design uses fragment ownership rather than a direct grant API. Two options:
Happy either way — if (2), what's the right one-paragraph explanation?
Technical accuracy spot-check
The page makes several claims I want a second pair of eyes on, especially ones that involve client-side or private-repo behavior I cannot fully verify from public source:
viam-mobileFlutter implementation. Is 30 days current and worth surfacing as guidance for third-party apps, or should the page just say "re-upload periodically" without the specific number?com.viam.viammobileas the only exempt application ID. Verified inapp/triggers/push_notification.go:14-15as a literalconst. Are there or will there be other exempt IDs (an enterprise variant, a partner app) that the page should mention or future-proof against?event_type,robot_part_id,machine_name,part_name,app_idbased onpushNotificationData()pluspushPayloadData(). Is that the complete and stable set, or are additions expected that third-party app developers should code for defensively?app/ui/src/lib/components/robot/add-resource-menu/create-block-modal/create-block-dialog.svelte:31. Just flagging in case there's an updated UI flow in flight.A quick "looks right" / "fix N" reply is plenty — no need to write copy.
Test plan
/monitor/custom-push-notifications/with a clean sidebar entry between Set up alerts and Default control interface./monitor/alert/,/data/trigger-on-data/,/reference/triggers/,/cli/reference/.#troubleshootworks; cross-page anchors/cli/reference/#organizations-firebase-config-set,/cli/reference/#login, and/hardware/fragments/#save-your-own-configurationsjump correctly.🤖 Generated with Claude Code