---
name: sentry-tickets-that-are-crashes
description: "Every Monday: this week's Zendesk or Intercom tickets matched to Sentry issues by user email and time, and how many more users hit the same crash in silence. Use when the user asks for this, or when it runs on a schedule."
---

# Support tickets that are known crashes: Zendesk or Intercom and Sentry

Every Monday: this week's Zendesk or Intercom tickets matched to Sentry issues by user email and time, and how many more users hit the same crash in silence.

Support sees six tickets saying "checkout just spins". Engineering sees a TimeoutError in Sentry. Neither knows they are the same thing, and nobody knows that for every customer who wrote in, thirty-five more hit it and left without a word. The ticket count makes the bug look small; the error count makes it look abstract.

This skill is for support and engineering leads who want one shared answer. Every Monday the agent joins the week's tickets to Sentry by the customer's email and the time of the ticket, counts the affected users who never contacted you, and checks Linear for an issue that covers the crash. The card shows which Sentry issues are generating tickets and which of them nobody is fixing yet.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- Sentry user context with the email set (`Sentry.setUser({ email })` after sign-in): it is the key that joins a ticket to an error, and it must be the same email the customer writes in from.
- Read access to tickets: a Zendesk API token or OAuth with `read`, or an Intercom token with Read conversations and Read users; a Sentry token with `event:read` or the Sentry MCP server.
- The Linear MCP server or `LINEAR_API_KEY` with read access to the teams that own the Sentry projects.

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **Pull the week's tickets with requester emails** (Zendesk): Whichever you use. Zendesk: `GET /api/v2/search.json?query=type:ticket created>=<7 days ago>`, then `GET /api/v2/users/show_many.json?ids=<requester_ids>` for emails. Intercom: `POST /conversations/search` with `created_at` greater than the week's start, then each contact's email. Keep ticket ID, subject, `created_at` in UTC and the email lowercased and trimmed; drop your own team's domain.
2. **Find each customer's errors in Sentry** (Sentry): For each email, `GET /api/0/organizations/{org}/issues/?query=user.email:<email>&statsPeriod=8d`. For each issue returned, `GET /api/0/organizations/{org}/issues/{issue_id}/events/?query=user.email:<email>&statsPeriod=8d` gives that user's event times (`dateCreated`). Cap at 200 tickets a run to stay inside rate limits.
3. **Match on email and time**: A ticket matches a Sentry issue when the same email had an event of that issue in the 24 hours before the ticket was created; within 1 hour is a strong match. When one email has several issues, take the one with the latest event before the ticket. Tickets with no Sentry events for that email are not known crashes; if the customer's email never appears in Sentry at all, count it as "no user context" instead.
4. **Count the silent sufferers** (Sentry): For each matched issue, `GET /api/0/organizations/{org}/events/?field=count_unique(user)&query=issue:<shortId>&statsPeriod=7d` gives the users it hit this week. Silent users are that count minus the distinct emails that wrote in about it.
5. **Check whether anyone is fixing it** (Linear): For each matched issue, query `attachmentsForURL(url: "<Sentry permalink>")` and `searchIssues(term: "<shortId>")` in Linear, and note the issue key and its state. A Sentry issue with tickets and no Linear issue goes to the top.
6. **Post the card**: Lead with the issue that has the most tickets and its silent user count. Table: Sentry issue, tickets, users hit, silent, Linear status. Post counts and short IDs only, never customer emails.

## Route B: the browser

### What you need

- Signed in to Intercom or Zendesk as an agent who can see all tickets, to Sentry as a member of the organization, and to Linear.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://app.intercom.com/. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **List the week's tickets**: In Intercom, open the Inbox, show all conversations created in the last 7 days and note each one's customer email and created time. On Zendesk, open `https://<subdomain>.zendesk.com/agent/` and search `type:ticket created>` with the date a week ago instead.
2. **Search Sentry by email**: Open `https://sentry.io/`, go to **Issues**, set the date to **Last 7 days** and search `user.email:<email>` for each customer. Open any issue found and use its events list to read the event times for that user.
3. **Match and count the silent users**: A ticket matches when the same email had an event in the 24 hours before it (within 1 hour is strong). On each matched issue's page, read the users count for the last 7 days and subtract the customers who wrote in.
4. **Check Linear**: Open `https://linear.app/` and search each matched Sentry short ID. Note the issue key and state, or that there is none, and report the table without customer emails.

Note: One Sentry search per customer makes this slow past about 40 tickets a week; the API route batches it. The Sentry users count on the issue page follows the date picker, so keep it on Last 7 days. Customers whose email Sentry never saw cannot be matched from either route.

## The report

- **Tickets that are known crashes**: how many of the week's tickets matched a Sentry issue.
- **By Sentry issue**: tickets, users hit this week, silent users, and the Linear issue and its state.
- **No user context**: tickets whose customers never appear in Sentry, a sign the SDK is not setting the user.
- The first thing to do, for example "File WEB-3K2: 6 tickets, 212 silent users, no Linear issue".

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "sentry-tickets-that-are-crashes/<date of this run, e.g. 2026-10-16>",
  "item_key": "sentry-tickets-that-are-crashes",
  "project": "acme-web",
  "source": "Support tickets that are known crashes: Zendesk or Intercom and Sentry skill",
  "kind": "update",
  "title": "6 tickets this week match Sentry WEB-3K2; 212 users hit it and never wrote in",
  "summary": "**11 of 148 tickets** this week match a known Sentry crash. **WEB-3K2** (TimeoutError in POST /api/checkout) drew 6 of them, hit **218 users**, and has **no Linear issue**.",
  "widget": [
    {
      "type": "Table",
      "props": {
        "columns": [
          "Sentry issue",
          "Tickets",
          "Users hit",
          "Silent",
          "Linear"
        ],
        "align": [
          "left",
          "right",
          "right",
          "right",
          "left"
        ],
        "rows": [
          [
            "WEB-3K2 TimeoutError in POST /api/checkout",
            6,
            218,
            212,
            "none"
          ],
          [
            "API-1F9 KeyError: currency in invoice render",
            3,
            41,
            38,
            "ENG-2290 In Progress"
          ],
          [
            "WEB-3JX TypeError: plan is null on downgrade",
            2,
            19,
            17,
            "ENG-2301 Todo"
          ]
        ]
      }
    },
    {
      "type": "Badges",
      "props": {
        "items": [
          {
            "label": "9 of 11 strong matches (within 1 h)",
            "tone": "info"
          },
          {
            "label": "7 tickets with no user context",
            "tone": "warn"
          }
        ]
      }
    },
    {
      "type": "Callout",
      "props": {
        "text": "File WEB-3K2 in Linear today: for every customer who wrote in, 35 more hit the checkout timeout without saying anything.",
        "tone": "bad"
      }
    }
  ]
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

## Run it on a schedule

Suggested: Mondays at 8:30 (`30 8 * * 1`). From cron, with the agent signed in on that machine:

```bash
30 8 * * 1 claude -p "Run the sentry-tickets-that-are-crashes skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/sentry-tickets-that-are-crashes#schedule

Source: https://briefkin.dev/skills/sentry-tickets-that-are-crashes
