Push notifications
Your users get notified when a long-running agent finishes, even after they close the app. AI Transport keeps the conversation on the channel, and Ably Push delivers the alert to the device that originally subscribed.
Push notifications let you notify users when an agent completes a long-running task, even if the user has closed the app. This uses Ably's native Push Notifications alongside AI Transport.
The pattern
The flow works as follows:
- A user sends a message that triggers a long-running agent task (research, code generation, data analysis).
- The user closes the app or navigates away.
- The agent completes the task and publishes the result to the session channel.
- A push rule on the channel triggers a notification to the user's device.
- The user taps the notification and returns to the completed conversation.
Because AI Transport persists messages on the Ably channel, the full response is available when the user returns. There is no need to store results separately.
Set up push rules
Configure a channel rule in the Ably dashboard to trigger push notifications when the agent publishes a completion event:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Server: publish a completion event when the agent finishes
app.post('/api/chat', async (req, res) => {
const body = await req.json()
const { userId } = body
const invocation = Invocation.fromJSON(body)
const session = createAgentSession({ client: ably, channelName: invocation.sessionName, codec: UIMessageCodec })
await session.connect()
const run = session.createRun(invocation, { signal: req.signal })
await run.start()
await run.loadConversation()
const result = streamText({
model: openai('gpt-4o'),
messages: run.messages,
abortSignal: run.abortSignal,
})
const { reason } = await run.pipe(result.toUIMessageStream())
await run.end({ reason })
session.close()
if (reason === 'complete') {
// Publish a push-eligible event on a notification channel
const notificationChannel = ably.channels.get(`notifications:${userId}`)
await notificationChannel.publish('agent-complete', {
title: 'Your agent has finished',
body: 'Tap to view the response',
sessionName: invocation.sessionName,
})
}
res.json({ ok: true })
})On the client, register the device for push notifications and subscribe to the notification channel:
1
2
3
// Client: subscribe for push notifications
const notificationChannel = ably.channels.get(`notifications:${userId}`)
await notificationChannel.push.subscribeDevice()Combine with AI Transport sessions
The notification payload can include the session ID, so the client opens directly to the right conversation. When the user taps the notification, load the session and use history and replay to display the full conversation including the completed response.
Edge cases and unhappy paths
- A run that ends with reason
'cancelled'or'error'does not publish a completion notification. Gate the push publish onreason === 'complete'. - A device that never registered for push (no
notificationChannel.push.subscribeDevice()call) does not receive the alert. Register on first launch and after a token refresh. - Notification payload limits apply per platform (around 4KB for APNs). Do not embed the full agent response; carry a session pointer and load history when the user returns.
- A user with several devices receives the notification on every registered device. Deduplicate at the device level if you only want one.
- The notification channel is a separate Ably channel from the session channel. Capabilities scope independently; the user's token needs
subscribeon both, pluspush-subscribeon the notification channel.
FAQ
Do I need a separate notification channel?
Yes. The push rule is per-channel; using a dedicated notifications:{userId} channel keeps the push policy off the conversation channel and lets you scope capabilities cleanly.
Does AI Transport publish the notification for me?
No. The SDK has no built-in push integration. The agent decides when the run is "done enough to notify" and calls channel.publish on the notification channel; Ably's push rule converts that publish into a device notification.
Can I reuse the session channel for push?
You can, but every streamed message would then trigger the push rule. Publishing one completion event on a separate channel keeps the notification single-shot.
What happens if the user opens a new device after the run completes?
The notification fires only on devices that had registered for push before the publish. A new device sees the completed conversation when it loads history through useView.
How do I avoid duplicate notifications across devices?
Either subscribe only one device per user, or include a messageId in the payload and dedupe on the client. Ably itself does not dedupe across a device fleet.
Related features
- History and replay: loading completed responses after reconnecting.
- Reconnection and recovery: resuming sessions after disconnection.
- Sessions: how durable sessions persist while users are offline.
- Ably Push: full reference for the Push Notifications API.