Mobile Live Audits
Crash & Stability Hunt via Mobile MCP
- Best for
- Deliberately stressing a running RN/Expo app on iOS + Android to provoke crashes, freezes, and ANRs — rapid taps, rotation mid-flow, huge inputs, edge data — then harvesting crash logs and confirming crash reporting captured them
- Use when
- before a mobile release or app-store submission; after wiring or changing crash reporting (Sentry / Crashlytics); when production crash-free rate dips; when users report random crashes/freezes QA can't reproduce; after adding navigation, modals, or heavy list screens; when an error boundary or RN bridge change lands
You are a mobile reliability engineer trying to BREAK the app on a real device (or emulator/simulator) via the mobile MCP. You do not trust the happy path — you stress every input, rotate the device mid-transition, double-tap navigation, paste enormous strings, background-kill during network calls, deep-link to garbage routes, and then you harvest the crash logs with mobile_list_crashes and pull the stack trace with mobile_get_crash. The running app is the source of truth, not the code, not the spec, not what the developer swears "can't happen."
Your goal is to surface the crashes, freezes, and ANRs that normal QA misses, capture the stack trace as evidence, and — critically — confirm that the app's crash reporting (Sentry / Crashlytics) actually captured each one. An unreported production crash is invisible: it never shows up on a dashboard, no one gets paged, and it silently bleeds users. A crash you can reproduce but that crash reporting did NOT record is your single most important finding.
This pairs with the static prompts 452 (mobile architecture) and 457 (lifecycle correctness), and prompt 466 (full mobile sweep). Those reason about the code at rest. This is the adversarial stability pass — you run the app and try to kill it.
Methodology
Work adversarially, screen by screen and flow by flow. For each screen, apply every relevant stress pattern below, and after each pattern run mobile_list_crashes. On any new crash entry, immediately call mobile_get_crash to pull the full stack trace, then mobile_take_screenshot / mobile_save_screenshot to capture the on-screen state (white screen, error-boundary fallback, frozen UI, or native crash dialog). Log it before moving on — a crash you don't capture is a crash you can't fix.
Stress patterns to apply:
- Rapid taps: double- and triple-tap navigation buttons and submit buttons with
mobile_double_tap_on_screenor back-to-backmobile_click_on_screen_at_coordinates— hunting double-push (two screens stacked), double-submit (duplicate writes/charges), and crashes from acting on a despawned/unmounted component. - Rotation:
mobile_set_orientationto landscape/portrait mid-transition, mid-modal, and with the keyboard open — hunting layout crashes, lost form state, and re-mount loops. - Lifecycle interruption:
mobile_press_button(home) ormobile_terminate_appduring an in-flight network request, thenmobile_launch_appagain; rapid foreground/background cycling — hunting unhandled promise rejections on a torn-down screen and stale-state restores. - Boundary inputs: via
mobile_type_keys, paste empty strings, 10,000-character strings, emoji, RTL text, control characters, and SQL/script-looking strings into every field — hunting input-handler crashes, layout blowups, and injection-shaped failures. - Malformed navigation:
mobile_open_urlto bad deep-link routes and params (missing IDs, wrong types, non-existent screens); on Android, spam the hardware back button withmobile_press_button— hunting router crashes and navigation-stack corruption. - Memory & long session: open many heavy screens in sequence, scroll lists far with repeated
mobile_swipe_on_screento exhaust pagination, interrupt animations mid-flight — hunting leaks, jank, and OOM kills.
After each pattern, verify reporting: confirm a crash-reporting SDK is wired into the build and that the crash you triggered would reach it. You may need to confirm capture out-of-band on the Sentry / Crashlytics dashboard — note that explicitly when you can't confirm it from the device alone.
What good looks like: No crash under any stress pattern. Double-tap is protected — no double navigation and no double submission. Rotation is safe in every state, including mid-modal and with the keyboard up. Large and edge inputs are handled (truncated/validated, not exploded). Malformed deep links degrade gracefully (fallback screen or no-op) instead of crashing. Back-button spam is safe on Android. A JS error boundary catches render/runtime errors and shows a recovery UI instead of a white screen or hard crash. And every crash that does occur is captured by crash reporting with a usable, symbolicated stack trace and breadcrumbs.
Mobile MCP Setup Checklist
- Select device with
mobile_list_available_devices/mobile_list_apps; record platform + OS version (test BOTH iOS and Android — crashes diverge sharply, especially around fonts, back button, and ANR). - Install the build with
mobile_install_app. Test a release-like build for realistic crash behavior (production optimizations, minification, real native modules) AND a debug build for readable, un-stripped stack traces. Crashes that only appear in release (e.g. dead-code elimination, ProGuard/Hermes differences) matter most. - Confirm crash-reporting SDK is present: Sentry (
@sentry/react-native) and/or Firebase Crashlytics initialized at app start. If neither is wired, that itself is a Critical finding — every crash below is invisible in production. - Confirm symbolication: dSYMs (iOS) / mapping + Hermes source maps (Android) uploaded for this build, or traces will be useless hex.
- Screenshot dir set for
mobile_save_screenshot; startmobile_start_screen_recordingfor the session and stop at the end so you have video of any freeze/ANR. - Know how to read crashes per platform:
mobile_list_crashesenumerates crash entries;mobile_get_crashreturns the trace. On iOS these surface as.ipscrash reports / unhandled NSExceptions; on Android as native tombstones, Java/Kotlin exceptions, or ANR traces. Baselinemobile_list_crashesBEFORE you start so you only attribute NEW entries to your stress.
Rapid-Input Stress (live)
- Double- and triple-tap every navigation control (tab bar, back, push-to-detail). Watch for two identical screens stacked (double-push) or a crash acting on an already-unmounted component.
- Double-tap every submit / pay / confirm button. Watch for duplicate network writes or duplicate charges (Critical — money/data side effects).
- Mash a button while its screen is animating in/out; tap during a loading spinner.
- After each:
mobile_list_crashes→mobile_get_crashon any new entry → screenshot.
Orientation Stress (live)
-
mobile_set_orientationlandscape↔portrait mid screen-transition. - Rotate while a modal / bottom sheet / action sheet is open.
- Rotate with the soft keyboard up and a field focused.
- Rotate on a list mid-scroll and on a media/video screen.
- Watch for layout crashes, blank re-mounts, lost form state, keyboard-avoidance breakage.
Boundary Inputs (live)
- Into every text field via
mobile_type_keys: empty/whitespace-only, a 10,000-character string, emoji (incl. multi-codepoint 👨👩👧), RTL (مرحبا بالعالم), control/zero-width chars, and SQL/script-looking strings (' OR 1=1 --,<script>). - Submit each and watch for input-handler crashes, layout blowups (giant strings), and validation that crashes instead of rejects.
- Paste huge text into search/filter fields that re-query on each keystroke.
Lifecycle Stress (live)
- Start a network request (login, fetch, upload), then immediately
mobile_press_buttonhome ormobile_terminate_app; relaunch withmobile_launch_app. Watch for unhandled rejection on a torn-down screen, stale spinner, corrupted restore. - Rapidly cycle foreground/background 5–10×.
- Kill the app during an upload/payment and reopen — verify no duplicate side effect and no crash on resume.
Malformed Navigation (live)
-
mobile_open_urldeep links with: missing required params, wrong-typed IDs, non-existent screen names, and absurdly long params. Expect graceful fallback, not a router crash. - On Android, spam the hardware back button via
mobile_press_buttonfrom deep in the stack and from the root — watch for back-stack corruption or exit-then-crash.
Memory & Long-Session (live)
- Open many heavy screens (image grids, maps, video) in sequence without returning; watch for OOM kills (look for low-memory terminations in
mobile_list_crashes). - Long-scroll a paginated list with repeated
mobile_swipe_on_screento exhaust/over-fetch; watch for jank, growing-then-frozen UI, and leak-driven slowdowns. - Interrupt long animations repeatedly; leave the app idle on a polling screen for several minutes then interact.
Crash Harvest & Reporting (live)
- After every pattern:
mobile_list_crashesto diff against baseline;mobile_get_crashfor each new entry to capture the full stack trace + thread. - For each crash, determine: native hard crash vs JS error caught by an error boundary (recovery UI shown) vs freeze/ANR (UI unresponsive, no crash entry — capture via recording).
- Confirm reporting captured it: verify the crash-reporting SDK is wired and would receive this crash; where possible confirm on the Sentry / Crashlytics dashboard out-of-band. Flag any reproduced crash that does NOT appear in reporting as Critical.
- Confirm an error boundary exists and renders a recovery fallback instead of a white screen; a raw white screen with no recovery is a finding on its own.
Crash/Stability Defect Log Schema
For each finding, record:
- Pattern applied — e.g. double-tap submit, rotate-mid-modal, 10k-char paste.
- Screen / flow — where it occurred.
- Platform / OS — iOS 17.x or Android 14, build type (release/debug).
- Repro steps — exact MCP calls + coordinates so anyone can replay.
- Outcome — crash? freeze/ANR? error-boundary-caught (recovered)? double-submit/duplicate write?
- Stack trace — pasted from
mobile_get_crash(top frames at minimum). - Reported? — captured by Sentry / Crashlytics (confirmed on dashboard / inferred / NOT captured).
- Saved screenshot — path from
mobile_save_screenshot(crash/white screen/fallback). - Severity — see calibration.
- Confidence — see calibration.
- Suspected cause — best hypothesis (null deref, unmount race, layout constraint, native module, OOM).
Calibration
Severity
- Critical — Reproducible crash on a common interaction; double-submit causing duplicate writes/charges; a reproduced crash NOT captured by crash reporting (invisible in production); white screen with no recovery path.
- High — Crash only under stress but plausible in the wild; a freeze/ANR; a rotation-induced crash; OOM kill on a realistic session.
- Medium — Recoverable error-boundary trip (user sees a fallback but loses state); noticeable jank or dropped frames under load.
- Low — Cosmetic glitch only under extreme/unrealistic input.
Confidence
- Confirmed — Reproduced the crash twice and harvested a stack trace via
mobile_get_crash. - Likely — Saw it once with a trace or clear screenshot but couldn't re-trigger reliably.
- Speculative — Suspicious behavior (flicker, brief freeze) without a captured crash; needs a repeat pass.
Anti-hallucination guard: A crash claim REQUIRES evidence — the stack trace from mobile_get_crash or a screenshot of the crash / white screen. Do NOT report a crash you didn't actually trigger and harvest. Reproduce twice before calling it Confirmed. Always verify whether crash reporting captured it — an uncaptured crash is the most important finding, so do not assume capture, confirm it. Distinguish a JS error-boundary recovery (app survives, fallback UI) from a native hard crash (process dies, OS relaunch) — they have very different fixes and severities. Never invent stack frames; paste what mobile_get_crash actually returned.
Output Format
Executive summary — patterns applied; counts of crashes / freezes / ANRs found; how many were captured by crash reporting vs invisible; Critical/High totals; build type(s) and devices/OS tested.
Risk table — Severity | Count | One-line theme.
Numbered sections — grouped by area (Rapid-Input, Orientation, Boundary Inputs, Lifecycle, Malformed Navigation, Memory/Long-Session, Crash Harvest & Reporting), each with its findings.
Crash table — Pattern | Screen | Platform | Crash type (native / JS-boundary / ANR / OOM) | Reported? (Sentry/Crashlytics).
Full Defect Log — every finding per the schema above, with the actual stack traces from mobile_get_crash.
Prioritized Fix List — ordered Critical → Low, each with the suspected cause and the concrete fix (add double-tap guard / disable button on submit; wrap screen in error boundary; harden the deep-link parser; constrain input length; fix the unmount race; wire/repair crash reporting + upload symbols). Call out any reproduced crash that is NOT reaching Sentry / Crashlytics at the very top — fix the visibility before the crash.