Spotter catches what went wrong, and routes it to its fix.
When someone reports a problem, or your code notices one, Spotter captures it with the screenshot, the replay, the console and the network requests attached. Every report becomes a ticket beside the ones you import from GitHub, Jira and your own systems, triaged against a rubric you can read and handed to an agent when it is safe to. The same script gives you cookieless web analytics.
clicked Pay → POST /api/charge 502 → error toast shown
Reports that arrive ready to fix.
A report reaches your inbox from a person, from your code or from an error, and it carries what you would otherwise have to ask for.
From the people using your site
A widget with a screenshot they can mark up with arrows, boxes, pins and blur, an element picker, and a field for what they expected to happen. On mobile, they can shake to report.
From your code
Call spotter.report() when something fails, or spotter.flag() and assert() when something looks wrong. Flags are grouped and counted, and a rule turns one into a report, such as "20 in an hour" or "any critical".
With everything attached
The console, errors with source-mapped stack traces, network requests as a HAR file, the path through the site, the browser and device, the release, and steps to reproduce, one line at a time.
One issue, however many times it is reported.
Spotter fingerprints each report and groups repeats under the first, so twenty people hitting the same bug make one issue with twenty votes. Reporters can see similar open reports and add their own.
- Tickets
- Built in and on by default: every report becomes a triaged ticket, and the ticket's status comes back to the report.
- GitHub Issues
- One issue per fingerprint, with two-way status: a merged pull request that says "Fixes #N" resolves the report.
- Routing rules
- "If the category is billing, assign it to Finance and post to #billing." Every rule that matches applies.
- Signed webhooks
- Every new issue and every status change, to any endpoint, with failed deliveries retried.
- Trusplex Operator
- "Investigate in Operator" hands the report to Operator's agent, to look into on your servers.
Every ticket, one queue — reported or imported.
Your site's reports file tickets on their own. Bring in the rest from wherever they start, and every one goes through the same steps: created, triaged, and handed off if you allow it. Each credential is shown once and can be revoked on its own.
- Your site's reports
- Every finalized report becomes a ticket, and its status flows back to the reporter.
- By hand
- File a ticket in the console with a title and a description.
- Intake API keys
- One key for each of your systems. A key files tickets into one project and nowhere else, and only its hash is stored.
- Webhook sources
- A signed endpoint for a monitoring tool, a GitHub repository or a Jira project. GitHub and Jira issues are imported once each.
Noise stays out
Put a webhook source in classify mode and Spotter asks, for each event, whether it is a real problem a person should look at, as opposed to normal operation, a health check or noise. Only real problems become tickets. The rest are logged as suppressed, so you can check its judgement.
# import a ticket from your own system curl -X POST 'https://console.trusplex.com/hooks/spotter/tickets' \ -H 'Authorization: Bearer tpx_…' \ -H 'content-type: application/json' \ -d '{"title":"Checkout fails", "description":"Customers in the EU cannot pay since 09:00."}'
Three questions, one rubric you can read.
Jev scores each ticket for its priority, its type and its danger. The rubric it is given is the same text you read on the Triage rubric page, so what the model sees and what you review never drift.
Priority
Impact and urgency: who is affected, is it production, is there a workaround?
- Critical: an outage, data loss or an active exploit, with no workaround.
- High: major functionality broken for many users, or in production.
- Medium: part of the product impaired for some users, with a workaround.
- Low: cosmetic issues, edge cases, requests and questions with no urgency.
Type
Decided by what the ticket asks for, not by its tone, length or spelling.
- Issue: something doesn't work as intended, and a change could fix it.
- Feature request: new behaviour, or a change by design.
- Non-technical: a real request a person must handle, such as billing.
- Spam: no genuine request or report at all.
Danger
Tickets here can reach an agent that changes your code, so each one gets an estimate of how likely it is to be malicious: prompt injection, attempts to extract secrets, backdoors, social engineering.
An honest report of a security vulnerability is not malicious.
Low-confidence answers and dangerous tickets are flagged for review. A priority you set by hand, or one a routing rule raised, is never replaced by triage, only by an explicit re-triage.
Hand the ticket to an agent, and hear back.
A resolution target is where a ticket goes to be fixed. Spotter delivers the job through one of your project's connections and holds no credential of its own. The runner reports its progress on a one-time callback URL for that job.
- Priority
- High
- Type
- Issue
- Danger
- Low
- Source
- spotter · SPT-1042
- Created by Spotter
- Triaged by Jev: high · issue · danger 0.04
- Dispatched to fix-bugs, a Claude Code routine
- The runner reported RUNNING
- The runner reported SUCCEEDED ·
github.com/…/pull/318
Claude Code routine
Fires a routine on the Anthropic subscription that owns it, with the ticket, your instructions and the callback URL. The routine's own saved prompt decides what it may do.
Claude Code or Codex runner
Sends the job to a runner endpoint you operate, with the repository, the base branch, your instructions and the tools it may use.
Webhook
A signed POST of the ticket to any HTTPS endpoint.
Automatic resolution, off until you say
Turn it on for your organization or for one project, and new tickets go to an agent without waiting for a person. A ticket is handed off only if triage classed it as an issue or a feature request, its danger is below your threshold, and its priority meets the target's minimum.
One timeline for each ticket
Comments, triage, hand-offs and the runner's reports, oldest first. A runner's reply shows as an internal comment, hidden from the person who reported the issue. When Spotter holds a ticket back, the timeline says why.
Like a parcel tracker, for a bug report.
Everyone who reports an issue gets a reference number and a tracking page: Received, In progress, then Resolved or Closed, with the notes your team chooses to share. Nothing technical is ever shown on it.
Updates as it moves
Reporters are told when the report arrives, when someone starts on it, and when it is fixed. The tracking page names the release that fixed it.
Questions, answered in place
Ask the reporter for more detail and they reply from the tracking page or the widget. Their answer lands on the report and on its ticket.
A portal for clients
Invite a client or stakeholder as a guest. They report without an account, and their portal shows their own reports and conversations.
See the problems nobody reported.
Session replay
Replays attach to reports, upload when an error or a flag fires, or are sampled. The player marks clicks, errors, failed requests and rage clicks, and follows along in the console and network panes.
Insights
Reports by page, release, browser and category, a click heatmap, and suggested issues drawn from rage clicks, dead clicks and abandoned forms in your replays.
Web analytics, without cookies
Visitors, pages, sources, campaigns, countries and devices, live. Goals and funnels show where visitors drop off, and which issues were filed on each step.
Web Vitals and releases
LCP, INP and CLS per route at the 75th percentile, issues per 1,000 pageviews, and a flag when a new release makes a route slower.
Share a read-only traffic dashboard with anyone, and export your raw events as CSV whenever you like. Spotter also accepts Plausible-style events, so a site can switch in or out.
Spotter records other people's users, so its defaults are the safe ones.
- No IP addresses
- A visitor is a hash under a random salt that is deleted at the end of each day, so nobody can be followed from one day to the next.
- Masked in the browser
- Replays mask what people type, and never record password fields.
- Encrypted at rest
- Screenshots, recordings, replays and source maps are encrypted before they are stored. Source maps are never served back.
- Your rules
- Honour Global Privacy Control and Do Not Track, keep each kind of data only as long as you choose, and delete everything a reporter filed for a GDPR or CCPA request.
- Locked to your site
- A site's public key only works from the origins you allow, and secret-looking values are scrubbed from URLs as they arrive.
One command on a Next.js site.
Create a site in Trusplex Console, then run the installer. It adds @trusplex/spotter, wraps your Next config, mounts the provider and creates the /api/spotter route. Your builds then declare their release and upload source maps.
Widget settings, sampling and targeting change from the console without a redeploy, and install health warns you about a mistake before it costs you a thin report.
# in your Next.js app npx trusplex spotter init # .env — keys from Spotter → Settings NEXT_PUBLIC_SPOTTER_KEY=pk_live_… SPOTTER_SECRET_KEY=sk_… SPOTTER_INGEST_URL=https://console.trusplex.com/hooks/spotter
Know what went wrong before you have to ask.
Create a site, install Spotter, and the next report arrives with everything attached, already triaged. Add an intake key or a webhook source, and the tickets from your other systems arrive beside it.