App Center Crashes (React Native)

Important

Visual Studio App Center is scheduled for retirement on March 31, 2025. While you can continue to use Visual Studio App Center until it is fully retired, there are several recommended alternatives that you may consider migrating to.

Learn more about support timelines and alternatives.

App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to Google Play. Crash logs contain valuable information for you to help fix the crash.

Follow the Getting Started section if you haven't set up the SDK in your application yet.

Wherever you're using App Center Crashes, add the following import at the top of the file.

// Import App Center Crashes at the top of the file.
import Crashes from 'appcenter-crashes';

Generate a test crash

App Center Crashes provides you with an API to generate a test crash for easy testing of the SDK. This API can only be used in test/beta apps and won't do anything in production apps.

Crashes.generateTestCrash();

It's also easy to generate a JavaScript crash. Add the following line to your code, which throws a JavaScript error and causes a crash.

throw new Error('This is a test javascript crash!');

Tip

Your React Native app needs to be compiled in release mode for this crash to be sent to App Center.

Note

At this time, App Center doesn't support source maps to unminify JavaScript stack traces for Android React Native apps.

Note

It's best practice to avoid JavaScript throw statement with a string value (e.g.: throw 'message'), as React Native doesn't preserve full JavaScript stack in this scenario. Instead, throw a JavaScript Error (e.g.: throw Error('message')).

Get more information about a previous crash

App Center Crashes has two APIs that give you more information in case your app has crashed.

Did the app receive a low memory warning in the previous session?

At any time after starting the SDK, you can check if the app received a memory warning in the previous session:

const hadLowMemoryWarning = await Crashes.hasReceivedMemoryWarningInLastSession();

Note

In some cases, a device with low memory may not send events.

Did the app crash in the previous session?

At any time after starting the SDK, you can check if the app crashed in the previous launch:

const didCrash = await Crashes.hasCrashedInLastSession();

This comes in handy in case you want to adjust the behavior or UI of your app after a crash has occurred. Some developers chose to show additional UI to apologize to their users, or want way to get in touch after a crash has occurred.

Details about the last crash

If your app crashed previously, you can get details about the last crash.

const crashReport = await Crashes.lastSessionCrashReport();

Customize your usage of App Center Crashes

App Center Crashes provides callbacks for developers to perform additional actions before and when sending crash logs to App Center.

Processing crashes in JavaScript

In order for your Crash.setListener methods to work as expected you need to check if your application configured properly.

  1. Open the project's ios/YourAppName/AppDelegate.m file and verify that you have [AppCenterReactNativeCrashes register]; instead of [AppCenterReactNativeCrashes registerWithAutomaticProcessing];.
  2. Open the project's android/app/src/main/res/values/strings.xml file and verify that appCenterCrashes_whenToSendCrashes is set to ASK_JAVASCRIPT.

All the different callbacks of the event listener are discussed one by one in this document, but you need to set one event listener that define all callbacks at once.

Should the crash be processed?

Implement this callback if you want to decide if a particular crash needs to be processed or not. For example, there could be a system level crash that you'd want to ignore and that you don't want to send to App Center.

Crashes.setListener({

    shouldProcess: function (report) {
        return true; // return true if the crash report should be processed, otherwise false.
    },

    // Other callbacks must also be defined at the same time if used.
    // Default values are used if a method with return parameter isn't defined.
});

Note

To use that feature you need to configure your application properly for the Crash service.

This feature depends on Processing crashes in JavaScript.

If user privacy is important to you, you should get user confirmation before sending a crash report to App Center. The SDK exposes a callback that tells App Center Crashes to await user confirmation before sending any crash reports.

If you chose to do so, you're responsible for obtaining the user's confirmation, e.g. through a dialog prompt with one of the following options: Always Send, Send, and Don't send. Based on the input, you'll tell App Center Crashes what to do and the crash will then be handled accordingly.

Note

The SDK doesn't display a dialog for this, the app must provide its own UI to ask for user consent.

The following callback shows how to tell the SDK to wait for user confirmation before sending crashes:

Crashes.setListener({

    shouldAwaitUserConfirmation: function (report) {

        // Build your own UI to ask for user consent here. SDK doesn't provide one by default.

        // Return true if you built a UI for user consent and are waiting for user input on that custom UI, otherwise false.
        return true;
    },

    // Other callbacks must also be defined at the same time if used.
    // Default values are used if a method with return parameter isn't defined.
});

If you return true, your app must obtain (using your own code) the user's permission and update the SDK with the result using the following API:

import Crashes, { UserConfirmation } from 'appcenter-crashes';

// Depending on the user's choice, call Crashes.notifyUserConfirmation() with the right value.
Crashes.notifyUserConfirmation(UserConfirmation.DONT_SEND);
Crashes.notifyUserConfirmation(UserConfirmation.SEND);
Crashes.notifyUserConfirmation(UserConfirmation.ALWAYS_SEND);

Note

To use this feature, configure your application properly for the Crash service. The feature depends on Processing crashes in JavaScript.

Get information about the sending status for a crash log

At times, you want to know the status of your app crash. A common use case is that you might want to show UI that tells the users that your app is submitting a crash report, or, in case your app is crashing quickly after the launch, you want to adjust the behavior of the app to make sure the crash logs can be submitted. App Center Crashes has three different callbacks that you can use in your app to be notified of what's going on.

To do this, define an event listener in your code as shown in the following example:

Crashes.setListener({
    onBeforeSending: function (report) {
        // called after Crashes.process and before sending the crash.
    },
    onSendingSucceeded: function (report) {
        // called when crash report sent successfully.
    },
    onSendingFailed: function (report) {
        // called when crash report couldn't be sent.
    }

    // Other callbacks must also be defined at the same time if used.
    // Default values are used if a method with return parameter isn't defined.
});

All callbacks are optional. You don't have to provide all 3 methods in the event listener object, for example you can implement only onBeforeSending.

Note

To use that feature you need to configure your application properly for the Crash service.

This feature depends on Processing crashes in JavaScript.

Note

If Crashes.setListener is called more than once, the last one wins; it overrides listeners previously set by Crashes.setListener.

Receiving onSendingFailed means a non-recoverable error such as a 4xx code occurred. For example, 401 means the appSecret is wrong.

This callback isn't triggered if it's a network issue. In this case, the SDK keeps retrying (and also pauses retries while the network connection is down). In case we have network issues or an outage on the endpoint, and you restart the app, onBeforeSending is triggered again after process restart.

Add attachments to a crash report

You can add binary and text attachments to a crash report. The SDK will send them along with the crash so that you can see them in App Center portal. The following callback is invoked right before sending the stored crash from previous application launches. It won't be invoked when the crash happens. Be sure the attachment file is not named minidump.dmp as that name is reserved for minidump files. Here is an example of how to attach text and an image to a crash:

import Crashes, { ErrorAttachmentLog } from 'appcenter-crashes';

Crashes.setListener({
    getErrorAttachments(report) {
        const textAttachment = ErrorAttachmentLog.attachmentWithText('Hello text attachment!', 'hello.txt');
        const binaryAttachment = ErrorAttachmentLog.attachmentWithBinary(`${imageAsBase64string}`, 'logo.png', 'image/png');
        return [textAttachment, binaryAttachment];
    }

    // Other callbacks must also be defined at the same time if used.
    // Default values are used if a method with return parameter isn't defined.
});

The fileName parameter is optional (can be null) and is used only in the App Center portal. From a specific crash occurrence in the portal, you can see attachments and download them. If you specified a file name, that will be the file name to download, otherwise the file name is generated for you.

To setup the getErrorAttachments callback to work with ES2017 async/await functions, return a fulfilled Promise instead. The following example attaches a text and an image to a crash in an asynchronous fashion:

import Crashes, { ErrorAttachmentLog } from 'appcenter-crashes';

Crashes.setListener({
    getErrorAttachments(report) {
        return (async () => {
            const textContent = await readTextFileAsync(); // use your async function to read text file
            const binaryContent = await readBinaryFileAsync(); // use your async function to read binary file
            const textAttachment = ErrorAttachmentLog.attachmentWithText(textContent, 'hello.txt');
            const binaryAttachment = ErrorAttachmentLog.attachmentWithBinary(binaryContent, 'logo.png', 'image/png');
            return [textAttachment, binaryAttachment];
        })();
    }

    // Other callbacks must also be defined at the same time if used.
    // Default values are used if a method with return parameter isn't defined.
});

Note

To use that feature you need to configure your application properly for the Crash service.

This feature depends on Processing crashes in JavaScript.

Note

The size limit is currently 1.4 MB on Android and 7 MB on iOS. Attempting to send a larger attachment will trigger an error.

Handled Errors

App Center also allows you to track errors by using handled exceptions via trackError method. An app can optionally attach properties or/and attachments to a handled error report to provide further context.

try {
    // Throw error.
} catch (error) {

    // Prepare properties.
    const properties = { 'Category' : 'Music', 'Wifi' : 'On' };

    // Prepare attachments.
    const textAttachment = ErrorAttachmentLog.attachmentWithText('Hello text attachment!', 'hello.txt');
    const attachments = [textAttachment];

    // Create an exception model from error.
    const exceptionModel1 = ExceptionModel.createFromError(error);

    // ..or generate with your own error data.
    const exceptionModel2 = ExceptionModel.createFromTypeAndMessage("type", "message", "stacktrace");

    // Track error with custom data.
    Crashes.trackError(exceptionModel1, properties, attachments);
    Crashes.trackError(exceptionModel1, properties, nil);
    Crashes.trackError(exceptionModel2, nil, attachments);
    Crashes.trackError(exceptionModel2, nil, nil);
}

Breakpad

App Center supports Breakpad crashes from Android NDK in a React Native apps.

Follow the normal setup steps above, and in your MainActivity.java override OnCreate and add the minidump configuration and call into your native code that sets up your Breakpad configuration.

Example:

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Crashes.getMinidumpDirectory().thenAccept(new AppCenterConsumer<String>() {
      @Override
      public void accept(String path) {
        // Path is null when Crashes is disabled.
        if (path != null) {
          // links to NDK
          setupBreakpadListener(path);
        }
      }
    });
  }

Enable or disable App Center Crashes at runtime

You can enable and disable App Center Crashes at runtime. If you disable it, the SDK won't do any crash reporting for the app.

await Crashes.setEnabled(false);

To enable App Center Crashes again, use the same API but pass true as a parameter.

await Crashes.setEnabled(true);

The state is persisted in the device's storage across application launches.

Check if App Center Crashes is enabled

You can also check if App Center Crashes is enabled or not:

const enabled = await Crashes.isEnabled();