---
title: "Open the exact page the push is about · Agent Wranglers"
url: https://agentwranglers.se/playbook/notifications/web-push/push-deep-links
id: NTF-15
level: Recommended
updated: 2026-10-21
build: a2a6bdfed830
tokens: 890
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Open the exact page the push is about

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Web push](https://agentwranglers.se/playbook/notifications/web-push.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: NTF-15
- Level: Recommended
- Chapter: [Web push](https://agentwranglers.se/playbook/notifications/web-push.md)
- Rule: A tap on a notification opens the page it is about, reuses an open tab when there is one, and marks the item as read.
- Check: A browser test receives a push, clicks it, and lands on `/orders/1042` in the open tab. The inbox item for that order is now read.
- How: Put a relative path in the payload, such as `/orders/1042`, never a full outside address. In the service worker's `notificationclick` handler, focus an open window first and then navigate it, or open a new one. Browsers allow focus only while the click is fresh. Native apps use the same path as a universal link or app link. The page itself checks the session, so a shared phone never shows another account's order.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
self.addEventListener('notificationclick', event => {
  event.notification.close();
  const target = new URL(event.notification.data.path, self.location.origin);
  if (target.origin !== self.location.origin) return;
  event.waitUntil((async () => {
    const [open] = await clients.matchAll({ type: 'window' });
    if (!open) return clients.openWindow(target.href);
    const focused = await open.focus();
    return focused.navigate(target.href);
  })());
});
```

### Python example

```python
# Server side: only ever put a path from your own router into the payload
from urllib.parse import urlsplit

def push_payload(title: str, path: str, item_id: str) -> dict:
    parts = urlsplit(path)
    if parts.scheme or parts.netloc or not path.startswith("/"):
        raise ValueError("Push links must be relative paths")
    return {"title": title, "data": {"path": path, "inbox_item": item_id}}
```

## Sources

- [Service Workers, Clients openWindow method](https://www.w3.org/TR/service-workers/#dom-clients-openwindow)
- [Service Workers, WindowClient focus method](https://www.w3.org/TR/service-workers/#dom-windowclient-focus)

## Related rules

- WEB-178 [Open links in your phone apps](https://agentwranglers.se/playbook/website/standard-addresses/app-links.md) in Website
- NTF-41 [Send declarative push messages with a service worker fallback](https://agentwranglers.se/playbook/notifications/web-push/declarative-web-push.md) in Notifications

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/notifications/web-push/push-deep-links">Agent Wranglers notifications playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Send web push with VAPID and an encrypted payload](https://agentwranglers.se/playbook/notifications/web-push/web-push-vapid.md)
- Next: [Show a notification for every push](https://agentwranglers.se/playbook/notifications/web-push/visible-push-only.md)
- [Web push](https://agentwranglers.se/playbook/notifications/web-push.md)
