Match support tickets to Sentry crashes, and count the users who never wrote in

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.

Runs
Mondays at 8:30
Posts
Report card

From your apps to your board

How the skill works: your agent reads week's tickets with requester emails from Zendesk; customer support from Intercom; each customer's errors in sentry from Sentry; whether anyone is fixing it from Linear; sentry organization slug, support tool, zendesk subdomain from What you tell it, mondays at 8:30, and gives you report card and the report in the chat.

Reads

  • ZendeskWeek's tickets with requester emails
  • IntercomCustomer support
  • SentryEach customer's errors in Sentry
  • LinearWhether anyone is fixing it
  • What you tell itSentry organization slug, Support tool, Zendesk subdomain
reads
Your agentClaude Code, Codex, Cursor or GeminiMondays at 8:30
posts

You get

  • Report cardOn your board, updated in place every run
  • The report in the chatEvery run, with or without Briefkin

What you get

  • 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".

The card on the right is a sample. Yours shows your own numbers and updates in place every run.

What lands on your board

acme-webSupport tickets that are known crashes: Zendesk or Intercom and Sentry · Claude Code

6 tickets this week match Sentry WEB-3K2; 212 users hit it and never wrote in

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.

Sentry issueTicketsUsers hitSilentLinear
WEB-3K2 TimeoutError in POST /api/checkout6218212none
API-1F9 KeyError: currency in invoice render34138ENG-2290 In Progress
WEB-3JX TypeError: plan is null on downgrade21917ENG-2301 Todo
9 of 11 strong matches (within 1 h)7 tickets with no user context

File WEB-3K2 in Linear today: for every customer who wrote in, 35 more hit the checkout timeout without saying anything.

Done
An example with made-up numbers. Your agent posts your real ones.

What it does

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.

How it works

  1. 1Pull the week's tickets with requester emails

    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. 2Find each customer's errors in 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. 3

    3Match 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. 4Count the silent sufferers

    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. 5Check whether anyone is fixing it

    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. 6

    6Post 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.

  7. Post it to the board

    With BRIEFKIN_TOKEN set, the agent sends the result as one card that updates in place every run. Without it, you get the report in the chat.

Install and run it

Pick your agent, where the data comes from and how to schedule it; the commands below follow.

Agent
Data
Schedule
  1. Install the skill

    One command. It puts the SKILL.md in ~/.claude/skills and in ~/.agents/skills, which Codex, Cursor, Gemini CLI, Copilot CLI and OpenCode read too.

    shellcurl -fsSL https://briefkin.dev/skills/sentry-tickets-that-are-crashes/install | sh
  2. Run it

    Ask Claude Code:

    promptRun the sentry-tickets-that-are-crashes skill

    Or paste the prompt instead of installing:

    promptTake this week's tickets from Zendesk or Intercom (whichever I use) with the requester email and created time. For each email, search Sentry issues in <org> with user.email:<email> over the last 8 days and read that user's event times. Match a ticket to a Sentry issue when the same email had an event in the 24 hours before the ticket (within 1 hour is a strong match). For each matched issue, count the unique users it hit this week and subtract the people who wrote in: those are silent sufferers. Check Linear for an issue that links to or mentions the Sentry short ID and give its state. Show me a table of Sentry issue, tickets, users hit, silent users and Linear status, count tickets whose customer never appears in Sentry, and tell me which crash to fix first. Do not show customer emails.
  3. Put it on a schedule

    Mondays at 8:30, from cron on any machine where Claude Code is signed in:

    crontab30 8 * * 1 claude -p "Run the sentry-tickets-that-are-crashes skill"

    Add it with crontab -e. A laptop asleep at that time runs it when it wakes if you use launchd or Task Scheduler instead; GitHub Actions works for the API route.

  4. Send it to your board

    Connect Briefkin once with curl -fsSL https://briefkin.dev/install | sh and every run lands on your board as a report card. How setup works

View the SKILL.mdRaw file
SKILL.md---
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

What your agent needs

  • 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.

Connecting Zendesk

  1. MCP server. Zendesk doesn't list an official one; community MCP servers exist, and they need the same subdomain, email and API token as a direct API call.
  2. API with an API token. An admin enables token access in Admin Center under Apps and integrations > APIs and creates a token. The skill reads ZENDESK_SUBDOMAIN, ZENDESK_EMAIL and ZENDESK_API_TOKEN and sends basic auth as {email}/token:{token}.
  3. OAuth client. For a narrower credential, register an OAuth client in Admin Center and request the read scope.

An API token acts as the user who made it, with that agent's full rights; an OAuth token with only read can't update, assign or close tickets.

Connecting Intercom

  1. Intercom MCP server, Intercom's official remote server at https://mcp.intercom.com/mcp (https://mcp.eu.intercom.com/mcp for EU workspaces; Australian workspaces aren't supported yet). Intercom is in Claude's connector directory for US workspaces, and on Team and Enterprise plans an Owner adds it. Its tools search and fetch conversations and contacts (docs).
  2. REST API with an access token. Create an app in the Intercom Developer Hub, store its access token in INTERCOM_ACCESS_TOKEN, and call https://api.intercom.io (api.eu.intercom.io or api.au.intercom.io by region) with an Intercom-Version header. Give the app Read conversations and Read and list users and companies.

The MCP server includes a few write tools (internal notes, Help Center articles), so for unattended reports an app token with read permissions only is the tighter option.

Connecting Sentry

  1. Sentry MCP server, Sentry's official remote server at https://mcp.sentry.dev/mcp, signed in with OAuth. Add Sentry from Claude's connector directory, or run claude mcp add --transport http sentry https://mcp.sentry.dev/mcp. It searches issues and events and pulls stack traces.
  2. sentry-cli. Mostly a release and source map tool, but sentry-cli issues list --project <slug> lists issues when a quick terminal check is enough.
  3. API with an auth token. Create an organization or personal token, store it in SENTRY_AUTH_TOKEN with SENTRY_ORG, and grant org:read, project:read and event:read.

Those three read scopes cover every report here; leave out event:write, which lets a token resolve and assign issues.

Connecting Linear

  1. Linear MCP server, Linear's official remote server at https://mcp.linear.app/mcp. Add Linear from Claude's connector directory, or run claude mcp add --transport http linear https://mcp.linear.app/mcp in Claude Code, and sign in with OAuth.
  2. GraphQL API with a personal API key. Create a key in Linear's settings under Security & access, store it in LINEAR_API_KEY, and send it as the Authorization header with no Bearer prefix. For a workspace bot, an OAuth app with the read scope does the same job.

When you create the key, give it Read access and only the teams in the report; it then can't create or edit issues.

Questions

What if customers write in from a different email than the one they sign in with?

Those tickets will not match, and they land in "no user context" when the address never appears in Sentry. If your app sets a user ID in Sentry (user.id) and the same ID is stored on the Zendesk user (external_id) or Intercom contact (external_id), the skill can match on that ID instead, which survives email changes.

Why look 24 hours back from the ticket, and which time zone?

People usually write in within minutes of a crash, but some write the next morning. 24 hours catches them while keeping chance matches rare; matches within 1 hour are marked strong. All times are compared in UTC: Zendesk and Sentry return ISO 8601 UTC, and Intercom returns Unix seconds.

Do I need Briefkin to use the Support tickets that are known crashes: Zendesk or Intercom and Sentry skill?

No. The skill runs with your own agent and gives you the report in the chat. With a Briefkin token set, each run also posts it to your board as a report card, so you can glance at it instead of asking again.

Which agents can run it?

Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, Windsurf and Amp all read SKILL.md files. The install command puts it in ~/.claude/skills and ~/.agents/skills, where they look. ChatGPT, the Claude app and Grok take the prompt instead. Pick your agent under "Install and run it" and the commands change to match.

Can it work without an API or MCP server, from my browser?

Yes. Switch the data source to "Your browser" and the steps change to the Zendesk, Intercom, Sentry and Linear pages themselves: the agent opens app.intercom.com in a browser you are signed in to and reads the numbers off the page. Claude Code, Codex, Cursor, Claude app and ChatGPT can drive a browser out of the box; Gemini CLI, Copilot CLI and OpenCode need a Playwright or Chrome DevTools MCP server first. It is slower than the API and needs you signed in, so it suits a report you run by hand or from a scheduler on your own computer.

Read this report on your board, not in a chat log

Skills are free to use with any agent. Briefkin is where their results land: one board for every report, number and question your agents send, with a ping when something needs you.

Free during the open beta. No card.