Find IE/Safari/old-Chrome-only crashes

Split client-side errors by browser and version. Surface fingerprints concentrated in one engine — usually older Safari or a stale Chromium.

Updated · published

markdown for agents →

difficulty intermediate · time to value 2 minutes · execution on demand

Start from this

Split client-side errors by browser. Are any fingerprints concentrated in one browser version? Older Safari is the usual suspect.

Why this matters

Browser-specific bugs are the second-loudest support category after payment failures, and the hardest to reproduce on the dev laptop running the latest Chrome. The user emails “I clicked checkout and nothing happened” — you can’t repro, you close the ticket, they churn.

The actual cause is almost always: Safari 14.0 doesn’t support Array.prototype.at(), or some random old Chromium WebView used by an in-app browser is missing Promise.allSettled. Sentry shows you browser as a tag; segmenting by it is a manual filter you forget to apply.

Agentry’s HogQL can group errors by properties.$browser_version in one query. The bugs concentrated in one engine pop out instantly.

What you get

  • A per-fingerprint browser distribution (what % of events came from which browser/version)
  • Top 5 errors that are >80% concentrated in one browser version (= polyfill / compat issue)
  • A “minimum browser version to support” suggestion based on your actual user mix

Walk through it

You

Split client-side errors by browser. Are any fingerprints concentrated in one browser version?

Agent

Let me pull the browser distribution per fingerprint.

Endpoint: POST /v1/projects/:project_id/analytics/query
Exact shape: /v1/openapi.json?path=%2Fv1%2Fprojects%2F%7Bproject_id%7D%2Fanalytics%2Fquery&method=post
Custom HogQL goes in the OpenAPI-defined `query` field.
Concept fields:
  query: "SELECT properties.fingerprint AS fp, properties.$browser AS browser, properties.$browser_version AS ver, count() AS cnt FROM events WHERE event = '$exception' AND properties.$lib = 'web' AND timestamp >= now() - INTERVAL 14 DAY GROUP BY fp, browser, ver HAVING cnt > 10 ORDER BY fp, cnt DESC"
{
  "rows": [
    { "fp": "f_c4a1", "browser": "Safari", "ver": "14.0", "cnt": 88 },
    { "fp": "f_c4a1", "browser": "Safari", "ver": "14.1", "cnt": 12 },
    { "fp": "f_c4a1", "browser": "Chrome", "ver": "120",  "cnt": 2 },
    { "fp": "f_98d2", "browser": "Chrome WebView", "ver": "90", "cnt": 64 },
    { "fp": "f_98d2", "browser": "Chrome", "ver": "121", "cnt": 1 },
    { "fp": "f_4e21", "browser": "Chrome", "ver": "121", "cnt": 410 },
    { "fp": "f_4e21", "browser": "Safari", "ver": "17.4", "cnt": 188 },
    { "fp": "f_4e21", "browser": "Firefox", "ver": "124", "cnt": 91 }
  ]
}
Agent

Two fingerprints are heavily browser-concentrated:

  1. f_c4a1 — 97% Safari 14.x (100 / 102 events). Likely a missing polyfill.
  2. f_98d2 — 98% Chrome WebView 90 (64 / 65 events). In-app browser inside some mobile app.

f_4e21 is well-distributed — that’s a real bug affecting everyone, separate workstream.

Endpoint: GET /v1/cases/:case_id
Exact shape: /v1/openapi.json?path=%2Fv1%2Fcases%2F%7Bcase_id%7D&method=get
Use query parameters, not a JSON body.
{
  "id": "f_c4a1",
  "error_type": "TypeError",
  "message": "undefined is not a function (evaluating 'arr.at(-1)')",
  "stack_top": "dist/app.js:bundled — fn name unknown"
}
Agent

Confirmed: Array.prototype.at() isn’t supported on Safari 14 (added in 15.4). The fix is either a polyfill (core-js/features/array/at) or swap arr.at(-1) for arr[arr.length - 1]. Affects ~100 Safari users in 14 days.

f_98d2 is harder — Chrome WebView 90 is old enough that it might be a custom browser embedded in a partner’s mobile app. Recommend checking your traffic source.

Should I check overall user-mix by browser so we can decide whether to drop Safari 14 support?

The output

Browser-concentrated errors (14d, client-side only)

f_c4a1   TypeError: undefined is not a function (evaluating 'arr.at(-1)')
         97% Safari 14.x   (100 events / 102 total)
         3% other          (2 events)
         ↗ Polyfill `Array.prototype.at` OR replace with `arr[arr.length - 1]`

f_98d2   ReferenceError: globalThis is not defined
         98% Chrome WebView 90  (64 events / 65 total)
         2% other               (1 event)
         ↗ Old in-app browser. Check who's embedding you (referrer logs)

User-mix context (last 14d, all events):
   Chrome 120+      62%
   Safari 16+       21%
   Safari 14-15      4%   ← f_c4a1 users
   Firefox 120+      9%
   Chrome WebView    1%   ← f_98d2 users
   Other             3%

If we drop Safari < 16, we lose ~4% of traffic but kill f_c4a1
and 3 other latent compat bugs.

Setting it up

If you’re already capturing client-side errors via raw fetch, the browser attaches its own User-Agent automatically. Do not set a custom User-Agent from browser fetch; only server, CI, and curl examples should set one. To make the slice richer (especially for HogQL), also send $browser / $browser_version in properties. If you’re rolling your own helper, parse and send:

// In your browser-side error handler
window.addEventListener("error", async (ev) => {
  await fetch(`https://api.agentry.sh/v1/logs/`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${AGENTRY_PUBLIC_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      message: ev.message,
      stack: ev.error?.stack,
      url: window.location.href,
      user_agent: navigator.userAgent,
      tags: {
        $lib: "web",
        // Optionally pre-parse for cleaner HogQL queries:
        // $browser: parsedUa.browser,
        // $browser_version: parsedUa.major,
      },
    }),
  });
});

The server parses user_agent into $browser / $browser_version for you, so you don’t strictly need to pre-parse — but doing so means HogQL queries work without JSONExtract gymnastics.

Variations

  • “Same query but only for users on our paid plans — do enterprise customers have a different browser mix?”
  • “Which OS versions are concentrating errors? iPhone 14.x = old iOS, Android 9 = old Chrome WebView.”
  • “Find errors that only happen on mobile (any browser, screen width < 768).”
  • “Are there errors only on Cypress/Playwright user agents? Probably a flaky test, not a real bug.”

Adapt this workflow in your own agent.

Ask your agent to map the starter prompt to your saved signal map, live events, and the current HTTP API before answering.

Agentry gives coding agents production context from errors, product analytics, and deploys through one HTTP API. Fetch and read https://agentry.sh/install.md completely, then install Agentry's full first-time telemetry baseline in this repository. I authorize device-code login, saving the owner key only to ~/.agentry/credentials.json, creating one Agentry project for this repository, and read-only inspection of shipped source plus hidden CI/provider configuration. Deeply analyze the product's business logic and complete value flow before choosing telemetry. Save the complete source-backed plan and show me its exact contents and hash. Until I explicitly approve that plan or request a replacement, do not edit app/CI source, place runtime/CI credentials, commit, exercise product traffic, start proof, push, or deploy. After approval, I authorize only the reviewed targets: place the required scoped browser/server/CI credentials through the established environment or secret mechanism, preserve existing telemetry, implement and test the baseline, commit it, push that reviewed commit when the shipped CI/provider path requires it, exercise safe proof paths with test/non-customer data, and perform one deployment through the reviewed shipped CI/provider path. Ask first if proof would charge money, contact a third party, change real customer data, or require new external access. After the plan is saved, immediately before every onboarding state-changing POST, GET current onboarding state, perform only its single returned next_action, then read state again; do not batch or infer later stages. Continue until status is verified, installation_complete is true, and next_action is null. Keep all secrets, source snapshots, proof markers, and scratch files outside the repository.

+ Full access
5.5 Extra High
  1. 1. Open your repo in Codex, Claude Code, Cursor etc.
  2. 2. Paste the install prompt.
  3. 3. Your agent reads the install doc and shows you an implementation plan for approval.