A small web app for analyzing Apple crash reports. It accepts .ips JSON crash reports from iOS, macOS, Catalyst, and simulator targets, plus legacy text .crash reports, and produces a structured report that explains the likely root-cause path in plain language.
The analyzer is based on Apple's crash report documentation:
- Diagnosing issues using crash reports and device logs
- Analyzing a crash report
- Examining the fields in a crash report
- Interpreting the JSON format of a crash report
- Identifying the cause of common crashes
- Open or drag in
.ipsand.crashreports. - Keep chosen reports ephemeral: parsing happens in the browser tab, no report file is posted to the server, and Forget Report clears in-memory report data.
- Record public, privacy-preserving aggregate stats for visits, analyses, parse failures, local actions, and real daily buckets without storing report contents or identifiers.
- Parse Apple's two-object IPS JSON format and reject non-crash IPS logs.
- Render summary, environment, exception and termination fields, diagnostics, crashed thread frames, binary images, and raw JSON.
- Explain likely root cause using documented clues such as Last Exception Backtrace, VM Region Info, exception notes, triggered thread, and thread-state registers.
- Surface Crash Story, Symbolication Readiness, and Collection Context sections for dSYM gaps, OS terminations, and related Apple data sources such as Xcode Organizer, device logs, and MetricKit.
- Analyze all local reports from the command line and write Markdown/JSON output.
- Run without runtime dependencies; the app uses browser ES modules and Node.js built-ins.
npm startOpen http://127.0.0.1:4173/. The app lists one sanitized QLThumbnail example from examples/.
Run checks:
npm run ciAnalyze local reports:
npm run analyzeGenerated analysis files are written to reports/.
Crash reports can contain device models, OS builds, process paths, bundle identifiers, incident identifiers, stack traces, and diagnostic messages. This repo intentionally ignores real .ips and .crash files, plus generated reports/ output. Only the sanitized QLThumbnail demo under examples/ is committed.
The browser file-open flow does not transmit report file contents to the server. The file picker and drop target read the report with browser JavaScript in the current tab; they are not network uploads. The report is retained in page memory until the user clicks Forget Report, reloads the page, or closes the tab. Export JSON and Copy Summary are local browser actions initiated by the user.
The hosted page includes /privacy, which states the same policy in user-facing language. CrashPad also exposes /stats, a public page backed by aggregate counters and daily aggregate buckets for visits, reports analyzed, example versus browser-local analyses, parse failures, and user-triggered print/export/copy actions. Those counters do not store IP addresses, user agents, file names, report contents, stack traces, or identifiers.
Before making a fork or deployment public, review any added fixtures and generated artifacts for private paths, identifiers, proprietary symbols, or user data.
The server reads PORT and HOST from the environment. For local development it defaults to 127.0.0.1:4173; container hosts should set HOST=0.0.0.0. Aggregate stats are stored at .data/stats.json by default and can be redirected with CRASHPAD_STATS_PATH.
HOST=0.0.0.0 PORT=8080 npm startA minimal Dockerfile is included for Fly.io-style container deployment. The current public Sprite deployment is documented in docs/DEPLOYMENT.md.
The Root Cause Guide separates the crash mechanism from the likely cause. For example, EXC_CRASH (SIGABRT) usually describes how the process quit, while a Last Exception Backtrace may identify the API path that threw an uncaught language exception. For memory faults, the guide highlights exception subtype, VM Region Info, and CPU registers such as pc, lr, far, and esr.
This tool is a triage aid. It does not replace symbolication, Xcode debugging, sanitizers, device logs, or careful comparison across multiple reports.
npm test
npm run check
npm run analyzeThe parser lives in src/crashParser.js. The browser harness lives in index.html, src/app.js, src/stats.js, and src/styles.css. The local server is scripts/server.js.
The UI targets WCAG 2.2 AA checks for the main analyzer, privacy page, and stats page. Keep interactive controls keyboard reachable, preserve visible :focus-visible styling, and run an axe scan when changing layouts or generated report markup.
Static and dynamic UI strings live in src/i18n/en.js. Static HTML uses data-i18n* attributes applied by src/i18n/dom.js; report rendering calls t() directly. To add a locale, copy the English catalog, translate values only, and load that catalog from the same i18n boundary.
MIT. See LICENSE.