Skip to content

Sending / Actions and click tracking

Actions and click tracking

Add buttons to a notification and find out which one the person clicked.

A notification can carry up to 2 action buttons. The browser reports every click, button and dismissal back to Push, so you can see what the person did with each attempt.

Adding actions#

Each action has an id, a title and an optional url. Ids must be unique within the notification. The full rules are in Message options.

⫻

request body

{  "recipient": "ops",  "title": "Payment failed for order #48213",  "url": "https://example.com/orders/48213",  "actions": [    {      "id": "retry",      "title": "Retry payment",      "url": "https://example.com/orders/48213/retry"    },    {      "id": "contact",      "title": "Contact customer"    }  ]}

What a click does#

The personBrowser opensPush records
Clicks the notificationThe notification's url, or nothing when it has noneclickedAt
Clicks an actionThe action's url; without one, the notification's url; without that, nothingclickedAt and actionClicked set to the action's id
Dismisses itNothingclosedAt
  • The notification closes on any click.
  • Only the first click is kept: a later click does not change clickedAt or actionClicked.
  • Only the first dismissal is kept in closedAt.

How events reach Push#

Push's service worker in the person's browser sends each event to POST /v1/events, signed with a token that belongs to that browser and only works for its own attempts. Reporting is best effort: if the device is offline or the browser is closed at that moment, the event can be lost. A missing clickedAt does not prove that nobody saw the notification.

Where buttons appear#

WarningNot every system shows action buttons. Some show none, and others show them only when the notification is expanded. Always set the notification's own url too, so the most important action is one click away everywhere. See Browser compatibility.

Reading the events#

Each attempt in GET /v1/notifications/{id} carries the browser events:

⫻

curl

curl https://api.meslzy.com/push/v1/notifications/0199b1c2-7a4e-7c3d-9f1e-2b6a8d4c5e10 \  -H "Authorization: Bearer $PUSH_API_KEY"

⫻

attempts[0]

{  "id": "0199b1c2-7a52-7aa0-8c11-5d0e4f3b2a91",  "browser": {    "id": "0198f0aa-1c2d-7e3f-9a4b-5c6d7e8f9012",    "label": "Chrome on Windows"  },  "status": "accepted",  "tries": 1,  "acceptedAt": "2026-10-05T09:12:44.610Z",  "clickedAt": "2026-10-05T09:13:02.004Z",  "closedAt": null,  "actionClicked": "open"}
NoteclickedAt, actionClicked and closedAt are null until the browser reports them. What each field means is listed in Statuses.