Alert Triggers
A trigger is a named DSL query plus a lastSeenAt bookmark. On each page load the app re-evaluates every trigger and flags matches that landed since you last looked.
Overview
Triggers are for intel workers who want to leave the browser and come back to a prioritized list. Instead of polling the API on your own schedule, you declare what matters and let the nav badge surface new matches.
The syntax is the same DSL used on /dashboard/explore and /api/query — so a query you validated in Explore can be pasted directly into a trigger.
Creating a trigger
Three paths:
- In the Explore DSL editor, click + Alert trigger. It deep-links to
/dashboard/alerts?dsl=…with the query prefilled. - Navigate to /dashboard/alerts directly and fill out the New trigger form.
- Programmatically via
localStorage— see Storage below.
Evaluation model
On page load, the app collects all triggers from localStorage and issues a single POST /api/alerts/check call with the full batch. The server evaluates each DSL against the current record set and returns match counts.
Each trigger returns:
match_count— total records currently matchingunread_count— records whoselast_seenis newer than the trigger'slastSeenAtlast_match_at— most recentlast_seenamong matchesexample_record_id— ID of the most recent match (for the “View latest” link)
Unread semantics
“Unread” means new since you last looked, not new since the record was created. When you click Mark read, the trigger's lastSeenAt is set to now — subsequent evaluations only count records that appear or update after that timestamp.
Visiting /dashboard/alerts does not automatically mark everything read — the page shows the unread badge so you can triage. Click into individual triggers, or click Mark all read to clear the nav badge.
Storage
Triggers live in localStorage under the key boarnet.alerts.triggers as a JSON array.
[
{
"id": "trg_m4x82_abc123",
"name": "Alpha pivots in Russia",
"dsl": "tag:credential-stuffing AND country:RU",
"createdAt": 1776400000000,
"lastSeenAt": 1776480000000
}
]API: POST /api/alerts/check
The nav badge and /alerts page both hit this endpoint on mount. It accepts a list of triggers and returns per-trigger evaluation results.
POST /api/alerts/check
Content-Type: application/json
Authorization: Bearer <optional>
{
"triggers": [
{ "id": "trg_1", "dsl": "tag:credential-stuffing", "lastSeenAt": 1776480000000 },
{ "id": "trg_2", "dsl": "ja4:~t13d", "lastSeenAt": 0 }
]
}{
"tier": "anonymous",
"results": [
{
"id": "trg_1",
"ok": true,
"match_count": 8,
"unread_count": 2,
"last_match_at": "2026-04-18T01:59:00.000Z",
"example_record_id": "thr_demo01"
},
{
"id": "trg_2",
"ok": false,
"error": "These fields require a Pro key: ja4",
"match_count": 0,
"unread_count": 0,
"last_match_at": null
}
]
}Limits
- No hard cap on triggers; realistic ceiling is ~50 per browser
- Each POST to
/api/alerts/checkcosts 1 call against your rate limit - Triggers that reference paywalled fields will evaluate with
ok: falseon anonymous keys