BoopErrorTracker
Your Elixir app raised. Your phone knows.
Sends ErrorTracker errors to your iPhone through Boop, the tiny self-hosted push notification inbox.
ErrorTracker deliberately does not do notifications. This package attaches to the telemetry events it already emits, so you install it next to ErrorTracker and nothing about ErrorTracker changes.
Installation
def deps do
[
{:error_tracker, "~> 0.9"},
{:boop_ex, "~> 1.1"},
{:boop_error_tracker, "~> 1.1"}
]
end
Set up ErrorTracker as usual (repo, migration, router). Then configure the Boop client and this package:
# config/runtime.exs
config :boop_ex,
url: System.fetch_env!("BOOP_URL"),
api_key: System.fetch_env!("BOOP_API_KEY")
config :boop_error_tracker,
environment: config_env(), # tagged on every event
source: "my_app", # shown next to the error in Boop; default "error_tracker"
error_tracker_url: "https://my-app.com/dev/errors", # "Open in ErrorTracker" button on every push
enabled: config_env() == :prod
That's it. The handler attaches when the application starts.
What you get
Each push opens a full error page in the Boop app: exception type and message, the stacktrace with your app's frames highlighted, ErrorTracker's context and breadcrumbs, and tags for environment, source function/line and the ErrorTracker ids so you can jump to the ErrorTracker UI.
| Event | Default | Meaning |
|---|---|---|
:new | on | An error ErrorTracker has never seen before |
:unresolved | on | An error you marked resolved in the ErrorTracker UI happened again |
:occurrence | off | Every occurrence of any error, throttled per error (throttle, default 10 minutes) |
Errors muted in ErrorTracker are never sent.
Grouped in the inbox
Each event carries ErrorTracker's fingerprint, and Boop (1.2.0+) shows one inbox row per fingerprint — KeyError ×47 · First seen 09:31 · Last seen 10:42 — that opens the individual occurrences. That makes :occurrence notifications practical: the pushes still arrive, but the inbox stays one row per error.
Buttons on the push
Set error_tracker_url to the base URL of your ErrorTracker dashboard's error pages (the path you gave error_tracker_dashboard in your router plus /errors) and every push carries an Open in ErrorTracker button, on the notification itself and in the event detail. Add your own with actions:
config :boop_error_tracker,
error_tracker_url: "https://my-app.com/dev/errors",
actions: fn error, occurrence ->
[%{label: "Runbook", url: "https://wiki.example.com/errors/#{error.kind}"}]
end
actions may be a static list or a function of the error (and optionally the occurrence). Boop shows at most three buttons; if the function raises, the event is still sent without the extra buttons.
Options
config :boop_error_tracker,
enabled: true,
environment: "prod",
source: "my_app",
level: :error, # :critical makes pushes prominent
notify_on: [:new, :unresolved], # add :occurrence for ongoing errors
throttle: :timer.minutes(10), # minimum gap between :occurrence pushes for the same error
in_app: [:my_app, :my_app_web], # which OTP apps count as "your code" in stacktraces
tags: %{team: "web"}, # static tags on every event
error_tracker_url: "https://my-app.com/dev/errors", # "Open in ErrorTracker" button; nil = none
actions: [] # extra buttons: a list or fn error, occurrence -> [...] end
Sending goes through Boop.send_async/2: it never blocks the process that raised, never raises, and logs failures at :warning.
Usage rules for AI agents
Ships a usage-rules.md for usage_rules: mix usage_rules.sync AGENTS.md --all --link-to-folder deps.
Licence
MIT.