---
title: "Keep read state the same everywhere · Agent Wranglers"
url: https://agentwranglers.se/playbook/notifications/in-app-notifications/read-state-sync
updated: 2026-10-20
licence: "All rights reserved"
---

# Keep read state the same everywhere

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Recommended
- Chapter: [In-app notifications](https://agentwranglers.se/playbook/notifications/in-app-notifications)
- Rule: Mark an item read once on the server, and clear it in every open tab, every device badge and any pending reminder.
- How: Set `read_at` with a conditional update, so a second click changes nothing. Opening the page an item links to marks it read, as does a tap on its push. Broadcast the change to the user's other sessions over the live channel. Cancel any queued push or email for the same event, as in [send one message per event](https://agentwranglers.se/playbook/notifications/channels-and-preferences/one-message-per-event). Update the app badge with the Badging API or the platform's badge count.
- Check: Open the inbox in two tabs and read an item in one. The other tab's unread count changes within 2 seconds. A pending reminder email for that item is not sent.

Example:

```js
app.post('/api/notifications/:id/read', requireUser, async (req, res) => {
  const changed = await db.query(
    'UPDATE notifications SET read_at = now() WHERE id = $1 AND user_id = $2 AND read_at IS NULL',
    [req.params.id, req.user.id]);
  if (changed.rowCount) await live.publish(req.user.id, { kind: 'read', id: req.params.id });
  res.sendStatus(204);
});
```

```python
@app.post("/api/notifications/<int:item_id>/read")
@login_required
def mark_read(item_id):
    changed = db.execute(
        "UPDATE notifications SET read_at = now() WHERE id = %s AND user_id = %s AND read_at IS NULL",
        (item_id, current_user.id)).rowcount
    if changed:
        live.publish(current_user.id, {"kind": "read", "id": item_id})
    return "", 204
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers notifications playbook: https://agentwranglers.se/playbook/notifications/in-app-notifications/read-state-sync`.

- Previous: [Store every notification in a server-side inbox](https://agentwranglers.se/playbook/notifications/in-app-notifications/notification-inbox)
- Next: [Deliver new items live and catch up after a gap](https://agentwranglers.se/playbook/notifications/in-app-notifications/live-inbox-updates)
- [In-app notifications](https://agentwranglers.se/playbook/notifications/in-app-notifications)
