All articles

Technical

How to Diagnose and Fix ANRs in Android TWA Apps

November 1, 2026 · 7 min read

When publishing a Progressive Web App (PWA) to the Google Play Store using a Trusted Web Activity (TWA), native quality metrics still apply. One of the most critical performance metrics monitored by the Google Play Console is the App Not Responding (ANR) rate. An elevated ANR rate directly impacts your app visibility in search results and can lead to algorithmic demotions.

For web developers, diagnosing ANRs in a TWA can be challenging because the underlying engine is a browser (typically Google Chrome or another Custom Tabs provider), while the Play Console reports errors from a native Android system perspective. Understanding how web-side performance issues manifest as native ANR events is essential to keeping your app running smoothly.

What is an ANR in a Trusted Web Activity?

On Android, the operating system monitors application responsiveness. If an application blocks the main UI thread for longer than five seconds, Android displays an ANR dialogue box to the user, offering the option to wait or force close the app.

In a TWA, the native wrapper app starts a Custom Tab to render your web application. If the browser main thread is blocked by heavy JavaScript execution, synchronous layouts, or massive service worker activity, the browser engine stops responding to Android input events. Because the TWA wrapper is hosted on the same native process structure, the Android OS attributes this unresponsiveness to your application, triggering a native ANR alert in your Play Console dashboard.

Common Causes of ANRs in TWA Apps

While native apps trigger ANRs due to main-thread disk I/O or network requests, TWAs trigger ANRs due to specific web performance bottlenecks. The table below lists the primary web-side issues that translate into native ANR events:

Web-Side CauseNative Trigger MechanismPrimary Symptom
Long-running synchronous JSBlocks the browser main thread from handling inputTapping or scrolling does not respond for >5 seconds
Heavy Service Worker parsingBlocks the startup pipeline on low-end devicesApp freezes or remains white during initial launch
Synchronous Layout ThrashingForces the rendering engine into deep layout loopsUI freezes during heavy animations or DOM changes
Blocking Local Storage I/OSynchronous read/writes block thread operationsFreeze occurs during state hydration on app start

How to Locate TWA ANRs in the Google Play Console

To identify whether your TWA is suffering from ANR issues, navigate to the Google Play Console and select your app. Under the Quality menu, click on Android Vitals and select ANRs and Crashes.

Because the TWA runs inside a browser engine, the stack traces provided by the Play Console will often look different from typical Java or Kotlin stack traces. You will frequently see references to Chrome native libraries or System WebView internals, such as:

org.chromium.chrome.browser.customtabs or android.widget.FrameLayout.dispatchTouchEvent

These stack traces indicate that the native Android UI system was waiting for Chrome to dispatch a touch or click event, but Chrome was too busy to respond. To fix these, you must shift your debugging focus from native Android tools to web performance profiling tools.

Step-by-Step Guide to Diagnosing TWA Performance

To diagnose the exact JavaScript or CSS operations causing your TWA to freeze, you must profile your web app while running inside the actual Android environment.

Step 1: Set Up Remote Debugging

Connect your test Android device to your development computer via a USB cable. Ensure USB Debugging is enabled in the Developer Options of your device. Open Google Chrome on your desktop and navigate to chrome://inspect. You will see your connected device and the active TWA tab listed. Click Inspect to open the Chrome DevTools panel for your running mobile app.

Step 2: Run a Performance Profile

Switch to the Performance tab in DevTools. Click the record button and interact with the areas of your app that feel sluggish or have triggered ANRs in your console. Stop the recording and inspect the flame chart. Look for long, solid red bars indicating tasks that take longer than 50 milliseconds (Long Tasks). Any task exceeding 500ms is a severe risk; any task approaching 5,000ms will trigger a native ANR.

Step 3: Analyze CPU Bottlenecks

Examine the bottom-up view to see which JavaScript functions are consuming the main thread. Common culprits include deep object cloning, complex regular expression evaluations on large text strings, and synchronous loops processing large datasets (such as state-management hydration routines).

Mitigating and Fixing ANRs in Your PWA

Once you have identified the performance bottlenecks, you can apply several strategies to ensure your main thread remains free to process user inputs.

Utilise Web Workers for Heavy Computations

Any logic that does not directly manipulate the DOM should be offloaded to a Web Worker. Web Workers run on a separate background thread, meaning they can execute long-running JavaScript calculations without blocking the main UI thread. This is ideal for data parsing, cryptography, image processing, or local database querying.

Optimize Service Worker Boot Times

A poorly optimised service worker can delay TWA launch times, leading to ANRs during the cold-start phase. Minimise the amount of synchronous work your service worker performs during its install and activate phases. Avoid using synchronous network requests inside service worker events and make use of IndexedDB instead of synchronous caching structures.

Avoid Synchronous Storage APIs

The classic localStorage API operates synchronously. If your app attempts to read or write large datasets to localStorage on boot, it can block the main thread, particularly on low-end Android devices with slow flash memory. Migrate your state persistence to IndexedDB, which operates asynchronously and does not block the main thread.

Manage Layout Thrashing and DOM Size

Keep your DOM tree shallow and avoid querying DOM properties immediately after changing CSS styles (such as reading offsetHeight right after updating a class). This causes the browser to execute premature synchronous layouts, consuming critical CPU cycles and increasing the risk of interface freezes.

Ready to ship your Android app?

Paste your PWA URL, get a signed APK and a Google Play ready AAB in minutes.

Build my app