Coding Projects

Send Sentry Error Alerts to Your Phone

Sentry email lands in the same inbox as everything else. A webhook alert rule sends the issues that matter straight to your lock screen instead.

Red and black halftone illustration: a guard box at an empty gate at night, light on inside, the barrier arm lowered across the road (TheNotificationApp)

Sentry catches the exception the instant it happens, groups it, works out whether it is new, and emails you. That email arrives in the same inbox as your invoices and three newsletters, and you read it at 9:40 the next morning.

The detection was perfect. The delivery was the problem. A webhook fixes the delivery in about five minutes, and the rule you attach it to determines whether it stays useful.

What to send, before how to send it

This decision matters more than the configuration. Sentry can notify on every event, and a single bad deploy produces thousands of events. Route that to your phone and you will turn it off the same day.

Three triggers are worth a lock screen:

  • A new issue appeared. First time Sentry has seen this exception. Almost always tied to something you just shipped.
  • A resolved issue came back. A regression is a fix that did not hold, and you want to know before the report comes from a customer.
  • Volume crossed a threshold. An existing error that suddenly happens 500 times an hour is a different event from the same error happening twice a day.

Everything else belongs in the Sentry inbox, where you look on purpose.

Step 1: The webhook URL

Create an application in TheNotificationApp, call it Sentry, and copy the app_key. Build the static webhook URL:

https://thenotification.app/api/webhook/static/?app_key=YOUR_API_KEY&title=Sentry

The static webhook takes whatever JSON arrives and formats the payload into readable text, which suits Sentry because its payload already leads with the culprit and the error message.

Test it first, so you are debugging one thing rather than two:

curl -X POST "https://thenotification.app/api/webhook/static/?app_key=YOUR_API_KEY&title=Sentry" \
  -H "Content-Type: application/json" \
  -d '{"project":"web","culprit":"checkout.tsx","message":"TypeError: cannot read property id of undefined"}'

Step 2: Register it in Sentry

Go to Settings, then Integrations, then WebHooks for your project, and paste the URL into the callback list. Save.

That makes the webhook available as an action. It does not yet send anything, which is the part that confuses people: the integration is the delivery mechanism, the alert rule is the decision to use it.

Step 3: The alert rule

Go to Alerts, then Create Alert, then Issues.

Set the conditions to the narrow version:

WHEN  a new issue is created
OR    an issue changes state from resolved to unresolved
THEN  send a notification via WebHooks

And set the action interval to 30 minutes or longer. That is the rate limit: however many times the rule matches, Sentry will not notify you about the same issue more than once in that window. Without it, a first-seen issue in a hot code path can fire repeatedly while the grouping settles.

Step 4: A second rule for volume

The first rule misses a specific and expensive case: an error that already existed, quietly, at two an hour, and is now happening five hundred times an hour because of a config change. It is not new and it is not a regression, so nothing fires.

Add a second rule:

WHEN  the issue is seen more than 100 times in one hour
THEN  send a notification via WebHooks
Action interval: 1 hour

Two rules, two genuinely different questions: "is this new?" and "is this suddenly a lot?"

Making the notification tappable

Sentry's payload includes a URL for the issue. Switch to the dynamic webhook and you can pull specific fields, including that link:

https://thenotification.app/api/webhook/dynamic/?app_key=YOUR_API_KEY&title=culprit&body=message&url=url

Now the notification headline is the culprit, the body is the error message, and tapping it opens the issue in Sentry with the stack trace already loaded. At 2am that is the difference between triaging from your phone and getting out of bed.

The tradeoff is coupling: you are now depending on Sentry's payload field names, so a change on their side breaks it quietly. The static webhook never breaks and is just wordier. Both are documented in the dynamic webhook docs.

Alerting from your own code instead

Sentry's rules cover the general cases well. Occasionally you have one specific failure that matters more than its volume suggests: a payment webhook that silently stopped, a nightly reconciliation that found a mismatch. Those are worth a direct call rather than a rule you hope fires.

Nothing stops you sending one yourself from the same handler that reports to Sentry:

import os, requests, sentry_sdk

def critical(message: str, detail: str, link: str | None = None) -> None:
    """Report to Sentry and buzz the phone. Used sparingly, on purpose."""
    sentry_sdk.capture_message(f"{message}: {detail}", level="error")
    try:
        requests.post(
            "https://thenotification.app/api/sendNotification",
            headers={"app_key": os.environ["TNA_APP_KEY"], "Content-Type": "application/json"},
            json={"title": message, "body": detail[:180], **({"link": link} if link else {})},
            timeout=10,
        )
    except Exception as exc:
        sentry_sdk.capture_exception(exc)
try:
    reconcile_payments()
except MismatchError as exc:
    critical("Payment reconciliation failed", str(exc),
             link="https://dashboard.example.com/payments")
    raise

The discipline is in how rarely you call it. A codebase with forty of these is a codebase where the phone means nothing. Three or four, on the failures that cost money if they sit unnoticed for a day, is about right.

Environment filters

One filter is worth adding before you go live, because without it your staging environment will page you about errors you deliberately caused:

IF  the event's environment equals production

Obvious in hindsight, routinely forgotten, and the single most common reason people abandon phone alerts from Sentry in the first week.

The honest part

The free tier is 100 notifications for the lifetime of the account, not per month. With the narrow rules above, a stable service sends a handful a month and that lasts a long time. With "notify on every event" it lasts one bad deploy.

The action interval is the safety net. Set it before you enable the rule, not after you have watched forty notifications arrive. Pro is $2.99 a month for 1,000 if you want more room.

Worth being clear about what this is not: it is not an on-call system. There is no escalation, no acknowledgement, no rotation. It is a fast, cheap way for one developer to find out about their own errors within seconds instead of hours. If you need a rota and an escalation policy, buy something that does that.

Where this fits

The same webhook URL works for anything that can POST JSON, which is most of your stack. The general pattern is in webhook push notifications, and the parameters are in the static webhook docs.

Grab a key at thenotification.app and find out about your errors before your users do.

New to this? Start with the server-down alert this is built on.