
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
@dynatrace/react-native-plugin
Advanced tools
This plugin gives you the ability to use the Dynatrace Mobile agent in your react native application.
The Dynatrace React Native plugin helps auto-instrument your React Native app with Dynatrace OneAgent for Android and iOS and also provides an API to add manual instrumentation.
If you want to start using this plugin and are not a Dynatrace customer yet, head to dynatrace.com and sign up for a free trial. For an intro you can also check out our announcement blog post.
Note: With iOS specifically, we noticed that there are some features that are not working the same as when using the current default architecture. You may experience issues with crash reporting being captured and web requests being linked to specific user actions. Per react native, the new architecture is experimental. We will keep an eye on new updates and will continue to improve our support for the new architecture on both platforms.
This agent versions are configured in this plugin:
Note: If you are upgrading to React Native v0.70 (or newer) or using the @react-native-community/cli 9.x+ version, be aware that our automated script running before every start/run-android/run-ios command is no longer working. When your dynatrace.config.js changed be sure to execute
npx instrumentDynatracebeforehand.
npm install @dynatrace/react-native-pluginreact-native install @dynatrace/react-native-plugin.ios directory and execute pod install to install the new Dynatrace dependency to your xCode project.android/ and/or ios/ so the plugin can do the configuration correctly. Furthermore you need to trigger the configuration manually as the plugin is only automatically working with the React Native CLI. This means every time the configuration changes you need to call npx instrumentDynatrace.react-native link doesn't work as expected, manually add the iOS agent to your project.The transformer will add modifications to your code during build. The reporter will notify us if you clear the cache of the metro bundler.
Depending on your React Native version, you will need to use a different way to register the transformer. If you don't know the version, enter react-native --version in your terminal.
The following configuration must be added. If you already have a babel transformer (babelTransformerPath) in place, you need to use the upstreamTransformer property in dynatrace.config.js to use a transformer besides our dynatrace transformer.
In your project's root directory, create or extend metro.config.js so that it contains the following configuration properties transformer.babelTransformerPath and reporter:
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
transformer: {
babelTransformerPath: require.resolve(
'@dynatrace/react-native-plugin/lib/dynatrace-transformer',
),
},
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
};
module.exports = mergeConfig(defaultConfig, config);
const {getDefaultConfig} = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.transformer.babelTransformerPath = require.resolve(
'@dynatrace/react-native-plugin/lib/dynatrace-transformer',
);
config.reporter = require('@dynatrace/react-native-plugin/lib/dynatrace-reporter');
module.exports = config;
module.exports = {
transformer: {
babelTransformerPath: require.resolve(
'@dynatrace/react-native-plugin/lib/dynatrace-transformer'
)
},
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
};
Note: If you are upgrading from a previous version of this plugin, you'll notice that the file format has changed. Your old configuration is still available in
dynatrace.configand you have to copy your values to the newdynatrace.config.js.
Define a mobile app in Dynatrace and open the Mobile app instrumentation settings. In the settings you will see a dynatrace.config.js file which can be downloaded for React Native. Download and copy this file into the root folder of your application. If you are not sure you can always use npx configDynatrace to create a default configuration file.
Note: Define the components that you want to see lifecycle instrumented (example). This is important as you will only see Application startup and Touches out of the box.
For more details about the configuration, see Advanced topics.
Depending on your version of Metro or Expo (if used), your babel configuration babel.config.js will need to be updated.
The changes have to be done in the following cases:
The required changes for the versions above can be found here.
Only for Expo: If using expo make sure that your project is containing a "android" and/or "ios" folder. This can be done by using npx expo prebuild.
Execute npx instrumentDynatrace or react-native instrument-dynatrace in the root of your React Native project. This will configure both Android and iOS projects with the settings from dynatrace.config.js. You can use the same custom arguments as mentioned above. Be aware this configuration step will modify your application's *.plist and build.gradle file. This modification enables auto instrumentation on Android and is writing the configuration for both platforms needed for the OneAgent.
Use react-native run-android or react-native run-ios to rebuild and run your app. Specify custom paths via custom arguments..
Attention: Whenever you change your configuration in dynatrace.config.js please use react-native start --reset-cache option. Metro caches all files and a configuration change might lead to a different situation. Not resetting the cache might result in an mixture of old and new configuration.
If you can't do a automated startup through the dynatrace.config.js, you can always perform a manual startup and decide values such as beaconUrl and applicationId at runtime.
Note: An automated startup usually provides you with a lifecycle application start-up event. A manual startup on the other hand occurs later, thereby causing you to miss everything, including this application startup event, until the startup occurs.
A manual startup requires the following two steps:
dynatrace.config.js:module.exports = {
react: {
autoStart: false,
...
},
android: {
config: `
dynatrace {
configurations {
defaultConfig {
autoStart.enabled false
}
}
}
`
},
ios: {
config: `
<key>DTXAutoStart</key>
<false/>
`
}
}
beaconUrl and applicationId:Example of a startup call:
import { Dynatrace, ConfigurationBuilder } from '@dynatrace/react-native-plugin';
await Dynatrace.start(new ConfigurationBuilder("beaconUrl", "applicationId").buildConfiguration());
For more details see the section about startup API.
Note: If you don't deactivate the automated startup with the dynatrace.config.js file, the beaconUrl and applicationId values have no impact and are thrown away.
To use the API of the React Native plugin, import the API:
import { Dynatrace } from '@dynatrace/react-native-plugin';
The manual startup of the plugin is triggered via the start(configuration: IConfiguration) method. If you configured dynatrace.config.js for manual startup then the plugin doesn't send any data when not calling this function. Besides the application id and the beacon URL, there are several optional configuration parameters, which are shown in the table below.
import { Dynatrace, ConfigurationBuilder, LogLevel } from '@dynatrace/react-native-plugin';
const configurationBuilder = new ConfigurationBuilder("beaconUrl", "applicationId");
configurationBuilder.withCrashReporting(true)
.withErrorHandler(true)
.withReportFatalErrorAsCrash(true)
.withLogLevel(LogLevel.Info)
.withLifecycleUpdate(false)
.withUserOptIn(false)
.withActionNamePrivacy(false)
.withBundleName(undefined);
await Dynatrace.start(configurationBuilder.buildConfiguration());
Info: The value used in the function calls for the parameters is also their default value.
| Property name | Type | Default | Description |
|---|---|---|---|
| beaconUrl | string | undefined | Identifies your environment within Dynatrace. This property is mandatory for manual startup. OneAgent issues an error when the key isn't present. |
| applicationId | string | undefined | Identifies your mobile app. This property is mandatory for manual startup. OneAgent issues an error when the key isn't present. |
| reportCrash | boolean | true | Reports crashes. |
| errorHandler | boolean | true | Enables the error/crash handler. |
| reportFatalErrorAsCrash | boolean | true | Reports an unhandled fatal error as a crash or an error. |
| logLevel | LogLevel | LogLevel.Info | Allows you to choose between LogLevel.Info and LogLevel.Debug. Debug returns more logs. This is especially important when something is not functioning correctly. |
| lifecycleUpdate | boolean | false | Decide if you want to see update cycles on lifecycle actions as well. This is per default false as it creates a lot more actions. |
| userOptIn | boolean | false | Activates the privacy mode when set to true. User consent must be queried and set. The privacy settings for data collection and crash reporting can be changed via OneAgent SDK for Mobile as described under Data privacy. The default value is false. |
| actionNamePrivacy | boolean | false | Activates a privacy mode especially for Touchables and Buttons. Setting this option to true means that a name for the control will no longer be shown, e.g. "Touch on Button". When setting a dtActionName onto the component this setting will be ignored. |
| bundleName | string | undefined | Should be used only if you have a multiple bundle setup where you load several .bundle files within your React Native application. Enter the name of your bundle. This should be unique in comparison to your other bundle names. This will ensure that actions coming from different bundles will not interfere with each other. |
Attention:
dynatrace.config.js file is the basis, even for manual startup. When we look at the lifecycleUpdate property: Per default if not used, it is false. If enabled (set to true) in dynatrace.config.js file, this will be also true if manual startup is used. You can still override this behavior by calling ConfigurationBuilder.withLifecycleUpdate(false).A component can be either monitored automatically or manually. The auto instrumentation is handled via the dynatrace.config.js file. If you want to manually instrument a component you can use the API call withMonitoring.
import { Dynatrace } from '@dynatrace/react-native-plugin';
export function MyFunctionalComponent(){
...
}
Dynatrace.withMonitoring(MyFunctionalComponent, "MyFunctionalComponent");

The String "MyFunctionalComponent" is optional as the name of the component can be retrieved through different properties.
Combining manual and auto instrumentation should not be a problem. As they're running the same execution, the manual instrumentation will only override the content of auto instrumentation happening through the transformer.
There are two options to create an action. Either using enterAutoAction (the previous enterAction) or enterManualAction:
Important: Action names are limited to 250 characters and will be truncated if they exceed this limit.
enterAutoAction - Creates an Action which will be automatically handled by the plugin (This is the type of action which is internally used by the plugin when monitoring components and touchables). This means that the plugin decides about the hierarchy of this action. If there is no open action, the following action will be a root action. All other actions created by this method, while a root action is open, will be automatically inserted as a child action. Furthermore the plugin will automatically link webrequest (if they are not tagged manually) to the open root action. Be aware that the timeout/wait time for sub actions or web requests cannot be modified on the Android side for React Native Auto actions. The timeout is fixed to a 1000ms.import { Dynatrace } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterAutoAction("MyButton tapped");
//Perform the action and whatever else is needed.
myAction.leaveAction();

enterManualAction - Creates an Action which will NOT be handled by the plugin. This means that you have full control about the hierarchy of your actions. This function will create a root action for you, which has the ability to create child actions via enterAction. Be aware, because of the full manual approach the plugin will not link webrequest automatically. Webrequest have to be manually tagged by using the tag provided by the action via getRequestTag.import { Dynatrace } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterManualAction("MyButton tapped");
//Perform the action and whatever else is needed.
myAction.leaveAction();
To create a custom action named "MyButton tapped", use the following code. The leaveAction closes the action again. To report values for this action before closing, see Report Values.
import { Dynatrace } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterAutoAction("MyButton tapped");
//Perform the action and whatever else is needed.
myAction.leaveAction();
You can create a single custom action as well as sub actions. The MyButton Sub Action is automatically put under the MyButton tapped. As long as MyButton tapped is open, it gathers all the web requests.
Important: Action names are limited to 250 characters and will be truncated if they exceed this limit.
import { Dynatrace } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterManualAction("MyButton tapped");
const mySubAction = myAction.enterAction("MyButton Sub Action");
//Perform the action and whatever else is needed.
mySubAction.leaveAction();
myAction.leaveAction();

Actions can be canceled. That means they will not be sent and discarded fully. This also means that any values and sub actions attached to the action will be removed.
import { Dynatrace } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterAutoAction("MyButton tapped");
// Action will be canceled
myAction.cancel();
// Has no impact as the action is already canceled
myAction.leaveAction();
You can manually tag and time your web requests. With the API shown below, you are able to manually capture the web requests of an http framework/library.
Note: Using this API will force the request to be added to the action that is manually created.
import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-plugin';
let url = 'https://www.dynatrace.com';
// You can also use enterAutoAction if desired
let action = Dynatrace.enterManualAction("Manual Web Request");
let tag = await action.getRequestTag(url);
let timing = new DynatraceWebRequestTiming(tag, url);
try {
timing.startWebRequestTiming();
let axiosResponse = await axios.get(url, {
headers: {
timing.getRequestTagHeader(): tag
}
});
timing.stopWebRequestTiming(axiosResponse.status, axiosResponse.data);
} catch (error) {
timing.stopWebRequestTiming(-1, error);
} finally {
action.leaveAction();
}

There is also the option to report values for request and response size:
import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-plugin';
let url = 'https://www.dynatrace.com';
// You can also use enterAutoAction if desired
let action = Dynatrace.enterManualAction("Manual Web Request");
let tag = await action.getRequestTag(url);
let timing = new DynatraceWebRequestTiming(url, tag);
try {
timing.startWebRequestTiming();
let axiosResponse = await axios.get(url, {
headers: {
timing.getRequestTagHeader(): tag
}
});
timing.stopWebRequestTimingWithSize(axiosResponse.status, axiosResponse.data, 122, 63);
} catch (error) {
timing.stopWebRequestTiming(-1, error);
} finally {
action.leaveAction();
}

For any open action you can report certain values. The following API is available for action:
reportDoubleValue(valueName: string, value: number, platform?: Platform): void
reportError(errorName: string, errorCode: number, platform?: Platform): void
reportEvent(eventName: string, platform?: Platform): void
reportIntValue(valueName: string, value: number, platform?: Platform): void
reportStringValue(valueName: string, value: string, platform?: Platform): void
Important: All string parameters (errorName, eventName, valueName, value) are limited to 250 characters and will be truncated if they exceed this limit.
To report a string value, use the following:
import { Dynatrace } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterAutoAction("MyButton tapped");
myAction.reportStringValue("ValueName", "ImportantValue");
myAction.leaveAction();

If you look at the API calls, you will see the optional parameter platform?: Platform. This parameter offers the possibility to report values only for a specific platform. to know more, see Platform independent reporting.
To manually report an error stacktrace, use the following API call:
reportErrorStacktrace(errorName: string, errorValue: string, reason: string, stacktrace: string, platform?: Platform): void;

Note: The previous API without errorValue is deprecated and will be removed in the future. Please use the new API with errorValue if possible.
You can identify a user and tag the current session with a name by making the following call:
Important: The user identifier is limited to 250 characters and will be truncated if it exceeds this limit.
import { Dynatrace } from '@dynatrace/react-native-plugin';
Dynatrace.identifyUser("User XY");

To end the current user session, use the following API call:
import { Dynatrace } from '@dynatrace/react-native-plugin';
Dynatrace.endSession();
Note: The user tagging will not carry over to the new user session that is started after using this API. If user tagging is desired in the new user session, please ensure that you call the user tagging API.
You can manually report a crash via the following API call:
reportCrash(crashName: string, reason: string, stacktrace: string, platform?: Platform): void;
reportCrashWithException(crashName: string, crash: Error, platform?: Platform): void;

Note: If you use this API call to report a crash manually, it will force the session to be completed. Any new actions that are captured afterwards will be added into a new session.
reportCrashWithException will use the crashName as name for the crash. It will only report the crash if there is also a stacktrace available.
The privacy API methods allow you to dynamically change the data-collection level based on the individual preferences of your end users. Each end user can select from three data-privacy levels:
export enum DataCollectionLevel {
Off, Performance, UserBehavior
}
Crash reporting is enabled by default. The Mobile agent captures all unhandled exceptions/errors and immediately sends the crash report to the server. With this API you can activate or deactivate crash reporting. To change this behaviour via the API, enable/activate userOptIn and set the User Privacy Options.
The API to get and set the current privacy level looks like this:
async getUserPrivacyOptions(platform?: Platform): Promise<UserPrivacyOptions>;
applyUserPrivacyOptions(userPrivacyOptions: UserPrivacyOptions, platform?: Platform): void;
To check the current privacy options that are set:
import { Dynatrace } from '@dynatrace/react-native-plugin';
const privacyOptions = await Dynatrace.getUserPrivacyOptions();
If you want to create a new UserPrivacyOptions object:
import { DataCollectionLevel, UserPrivacyOptions } from '@dynatrace/react-native-plugin';
let privacyConfig = new UserPrivacyOptions(DataCollectionLevel.UserBehavior, true);
To set new values to this object:
privacyConfig.crashReportingOptedIn = false;
privacyConfig.dataCollectionLevel = DataCollectionLevel.Performance;
The properties that are used to set the privacy options can also be used to fetch the options:
let level = privacyConfig.dataCollectionLevel;
let crashReporting = privacyConfig.crashReportingOptedIn;
To apply the values that were set on the object:
import { Dynatrace } from '@dynatrace/react-native-plugin';
Dynatrace.applyUserPrivacyOptions(privacyConfig);
You can report latitude and longitude and specify an optional platform.
setGPSLocation(latitude: number, longitude: number, platform?: Platform): void
You probably noticed that each method has an additional optional parameter named platform of type Platform. You can use this to only trigger manual instrumentation for a specific OS. The available values are: Platform.Ios and Platform.Android. Default is that it will work on any platform. Otherwise it is passed only to the relevant OS. For example:
import { Dynatrace, Platform } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterAutoAction("MyButton tapped", Platform.Ios);
//Perform the action and whatever else is needed.
myAction.leaveAction("ios");
import { Dynatrace, Platform } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterAutoAction("MyButton tapped", Platform.Android);
//Perform the action and whatever else is needed.
myAction.leaveAction("android");
import { Dynatrace } from '@dynatrace/react-native-plugin';
const myAction = Dynatrace.enterAutoAction("MyButton tapped");
//Perform the action and whatever else is needed.
myAction.leaveAction();
With sendBizEvent, you can report business events. These events are standalone events, as OneAgent sends them detached from user actions or user sessions.
For more information on business events, see dynatrace documentation.
import { Dynatrace } from '@dynatrace/react-native-plugin';
Dynatrace.sendBizEvent("com.easytravel.funnel.booking-finished", {
"event.name" : "Confirmed Booking",
"screen": "booking-confirmation",
"product": "Danube Anna Hotel",
"amount": 358.35,
"currency": "USD",
"reviewScore": 4.8,
"arrivalDate": "2022-11-05",
"departureDate": "2022-11-15",
"journeyDuration": 10,
"adultTravelers": 2,
"childrenTravelers": 0
});

This allows you to put a set of http headers on every agent http request (i.e. Authorization header etc.). It will also triggers the agent to reconnect to the beacon endpoint with the new headers.
Note: To clear the previously set headers, call the method without the headers parameter or with a null value for the headers parameter.
setBeaconHeaders(headers?: Map<string, string> | null, platform?: Platform): void;
If you want to instrument a functional component or class component but want to exclude a certain button or element, you can do this via the dtActionIgnore property. Example:
function TouchableHighlightScreen() {
return (
<View>
<TouchableHighlight onPress={onPress}>
<Text>TouchableHighlight that will be monitored</Text>
</TouchableHighlight>
<TouchableHighlight onPress={onPress} dtActionIgnore="true">
<Text>TouchableHighlight that will be ignored</Text>
</TouchableHighlight>
</View>
);
}
function onPress() {
Logger.logDebug("TouchableHighlight Pressed!");
}
export default TouchableHighlightScreen;
This example shows two TouchableHighlight, which will fire the onPress() function when pressed. The property dtActionIgnore="true" will prevent the monitoring of one of them. This means that the onPress will still be executed but we will no longer create a user action which is wrapping the button click.
Attention: If you are using Typescript and want to set this property with type-safety, look here.
⚠️ Preview Feature: The New RUM Experience APIs are currently in preview and may be subject to changes. These APIs provide enhanced event tracking capabilities with the new Dynatrace RUM on Grail feature.
The New RUM Experience introduces a set of advanced APIs that allow you to send custom events, modify event data, track exceptions, monitor HTTP requests, and manage view contexts in your React Native application. These APIs provide more granular control over the data captured by Dynatrace and are designed for the next generation RUM capabilities.
For more detailed information about the New RUM Experience, see the official Dynatrace documentation.
The sendEvent() method allows you to send custom events with arbitrary properties in JSON format. This is useful for tracking specific user interactions or application state changes.
import { Dynatrace } from '@dynatrace/react-native-plugin';
// Send a custom event with properties
Dynatrace.sendEvent({
"event_properties.button_clicked": "login_button",
"event_properties.user_type": "premium",
"event_properties.attempt_count": 3,
"duration": 250
});
Property Requirements:
event_properties.* are allowedduration property is allowedSession properties apply to all events within the current session. Use sendSessionPropertyEvent() to set properties that should be available across the entire user session.
import { Dynatrace } from '@dynatrace/react-native-plugin';
// Set session-wide properties
Dynatrace.sendSessionPropertyEvent({
"session_properties.user_tier": "premium",
"session_properties.app_version": "2.1.0",
"session_properties.feature_flag_enabled": true
});
Important Notes:
session_properties. prefixduration property is allowedEvent modifiers allow you to intercept and modify events before they are sent to Dynatrace. This is useful for adding common properties, filtering sensitive data, or enriching events with additional context.
import { Dynatrace } from '@dynatrace/react-native-plugin';
// Create an event modifier
const myModifier = {
modifyEvent(event) {
// Add common properties to all events
event["event_properties.app_build"] = "1.2.3";
event["event_properties.environment"] = "production";
// Return null to discard the event entirely
if (event["event_properties.ignore"] === true) {
return null;
}
return event;
}
};
// Add the modifier
Dynatrace.addEventModifier(myModifier);
// Remove the modifier when no longer needed
Dynatrace.removeEventModifier(myModifier);
Important Considerations:
null from a modifier discards the event and prevents subsequent modifiers from executingThe sendExceptionEvent() method provides a structured way to report exceptions with additional context and custom properties.
import { Dynatrace } from '@dynatrace/react-native-plugin';
try {
// Code that might throw an error
await riskyOperation();
} catch (error) {
Dynatrace.sendExceptionEvent(error, {
"event_properties.operation_type": "data_sync",
"event_properties.retry_count": 3,
"event_properties.user_id": "user123"
});
}
Parameters:
error: The Error object containing exception information (required)fields: Optional custom properties following the same naming rules as sendEvent()The sendHttpRequestEvent() method allows you to manually report HTTP request events with detailed information about the request and response.
import { Dynatrace, HttpRequestEventBuilder } from '@dynatrace/react-native-plugin';
// Basic HTTP request event
const requestBuilder = new HttpRequestEventBuilder('https://api.example.com/users', 'GET');
Dynatrace.sendHttpRequestEvent(requestBuilder);
// HTTP request with additional details
const detailedBuilder = new HttpRequestEventBuilder('https://api.example.com/data', 'POST')
.setResponseCode(200)
.setRequestHeaders({ 'Content-Type': 'application/json' });
Dynatrace.sendHttpRequestEvent(detailedBuilder);
The view monitoring APIs allow you to track different screens or views in your application, providing context for all events happening within those views.
Use startView() to begin monitoring a specific view or screen. When a view is started, all subsequent events will be associated with that view context.
import { Dynatrace } from '@dynatrace/react-native-plugin';
// Start monitoring a view
Dynatrace.startView("HomeScreen");
Important Considerations:
Use stopView() to stop monitoring the current view. After stopping, events will no longer include view information.
import { Dynatrace } from '@dynatrace/react-native-plugin';
// Stop the current view monitoring
Dynatrace.stopView();
Complete Example:
import { Dynatrace } from '@dynatrace/react-native-plugin';
// User navigates to profile screen
Dynatrace.startView("UserProfile");
// Send custom event within the view
Dynatrace.sendEvent({
"event_properties.profile_action": "edit_profile",
"event_properties.changes_made": true
});
// User navigates away
Dynatrace.stopView();
The following npx commands are available for the plugin:
react-native run-android or react-native run-ios command.npx instrumentDynatrace [optional: config=... gradle=... plist=...]
gradle=C:\MyReactAndroidProject\build.gradle: The location of the root build.gradle file. We will assume that the other gradle file resides in /app/build.gradle. This will add the whole agent dependencies automatically for you and will update the configuration.plist=C:\MyReactIOSProject\projectName\info.plist: Tell the script where your info.plist file is. The plist file is used for updating the configuration for the agent.config=C:\SpecialFolderForDynatrace\dynatrace.config.js: If you have not got your config file in the root folder of the React Native project but somewhere else.npx configDynatrace [optional: config=...]
config=C:\SpecialFolderForDynatrace\dynatrace.config.js: If you have not got your config file in the root folder of the React Native project but somewhere else.Note: This feature works directly on run-android, run-ios or start command only for React Native v0.60.1 or newer until v0.69.x.
MacOS Users: This feature is not working correctly on MacOS. Arguments are not passed between run-ios and starting the webserver. If you still want to use custom arguments you need to start the webserver first with custom arguments and later on executing run-ios, which will then no longer create a webserver as it is already running in background.
Our scripts assumes that the usual React Native project structure is given. The following arguments can be specified for our instrumentation script if the project structure is different.
gradle=C:\MyReactAndroidProject\build.gradle: The location of the root build.gradle file. We will assume that the other gradle file resides in /app/build.gradle. This will add the whole agent dependencies automatically for you and will update the configuration.plist=C:\MyReactIOSProject\projectName\info.plist: Tell the script where your info.plist file is. The plist file is used for updating the configuration for the agent.config=C:\SpecialFolderForDynatrace\dynatrace.config.js: If you have not got your config file in the root folder of the React Native project but somewhere else.Examples:
npx react-native run-android config=C:\SpecialFolderForDynatrace\dynatrace.config.js --port=2000
npx instrumentDynatrace config=C:\SpecialFolderForDynatrace\dynatrace.config.js
npx react-native run-android --port=2000
Note: that custom arguments must not be prefixed with -- !
Adding the iOS agent manually depends on the availability of support for CocoaPods.
Insert the following in your Podfile:
pod 'react-native-dynatrace', :path => '../node_modules/@dynatrace/react-native-plugin'
node_modules/@dynatrace/react-native-plugin/ios.DynatraceRNBridge.xcodeproj into your Libraries group.libRNDynatrace.a under the Workspace group.Note: Testing has only been done using the react-native-tvos package and currently is the only package supported with our plugin.
To allow our plugin to work with tvOS, please follow the below steps:
Before installing the plugin, add the following to your package.json:
"overrides": {
"@react-native-picker/picker": {
"react-native": "<insert-version-here>"
},
"@dynatrace/react-native-plugin": {
"react-native": "<insert-version-here>"
}
},
If you are using the following "react-native": "npm:react-native-tvos@0.69.8-2", use the below snippet:
"overrides": {
"@react-native-picker/picker": {
"react-native": "0.69.8-2"
},
"@dynatrace/react-native-plugin": {
"react-native": "0.69.8-2"
}
},
Once the above is completed, follow the steps from the install plugin section.
When you are ready to build, make sure that you use the plist= parameter when running the npx instrumentDynatrace or npx react-native run-ios commands for the tvOS scheme.
Examples:
Using React Native v0.69.x or lower and @react-native-community/cli v8.x or lower:
npx react-native run-ios --simulator "Apple TV" --scheme "ApplicationName-tvOS" plist=/path/to/application/ios/ApplicationName-tvOS/Info.plist
Using React Native v0.70 or higher or @react-native-community/cli v9.x or higher:
// Update the Info.plist with the properties from the dynatrace.config.js file
npx instrumentDynatrace plist=/path/to/application/ios/ApplicationName-tvOS/Info.plist
// Build your tvOS application
npx react-native run-ios --simulator "Apple TV" --scheme "ApplicationName-tvOS"
For more information regarding the differences in the react native versions, please see the Note from the quick setup section.
dynatrace.js fileThe configuration is structured in the following way:
module.exports = {
react : {
// Configuration for React Native instrumentation
},
android : {
// Configuration for Android auto instrumentation
},
ios : {
// Configuration for iOS auto instrumentation
}
}
Here is a list of all the counterparts for the options that can be used with a manual startup. Below in the counterparts table you will find an example configuration block for both Android and iOS.
| Property Name | Default | Android | iOS | React |
|---|---|---|---|---|
| beaconUrl | undefined | autoStart.beaconUrl | DTXBeaconURL | - |
| applicationId | undefined | autoStart.applicationId | DTXApplicationId | - |
| reportCrash | true | crashReporting | DTXCrashReportingEnabled | - |
| errorHandler | true | - | - | errorHandler.enabled |
| reportFatalErrorAsCrash | true | - | - | errorHandler.reportFatalErrorAsCrash |
| logLevel | LogLevel.Info | debug.agentLogging | DTXLogLevel | debug |
| lifecycleUpdate | false | - | - | lifecycle.includeUpdate |
| userOptIn | false | userOptIn | DTXUserOptIn | - |
| actionNamePrivacy | false | - | - | input.actionNamePrivacy |
| bundleName | undefined | - | - | bundleName |
The react configuration block contains all settings regarding the react instrumentation. The following options are available:
react : {
input : {
instrument(filename) => {
return true;
},
actionNamePrivacy: false,
}
}
This instrument function expects you to return true or false. In this case, all files are instrumented to capture user input.
react : {
lifecycle : {
includeUpdate : false,
instrument(filename) => {
// This will only capture inputs in files in the path src/screens/
return filename.startsWith(require('path').join('src', 'screens'));
}
}
}
The instrument function expects you to return true or false. In this case, all files in the src/screens/ folder are instrumented to capture lifecycle changes.
Note: it is important that you input all files here where you wish lifecycle instrumentation. Probably this should contain all your "real" screens. If you return true for this function, all lifecycle events will be reported, which can be a lot in React Native.
react: {
debug: true
}
This activates the debug mode. You will get more console output during instrumentation and at runtime.
react: {
errorHandler: {
enabled: true,
reportFatalErrorAsCrash: true,
},
}
The enabled property activates our Error/Crash handler which will insert our handler into your React Native application. This is true per default.
The reportFatalErrorAsCrash property should be set to false if you are wanting to report a fatal/unhandled error as an error and NOT a crash. Setting this value to false will keep the current session open.
Note:
if enabled is set to false, the value of reportFatalErrorAsCrash is not be considered/used as our error handler will not be started.
react: {
autoStart: true
}
This activates the AutoStart mode which will insert an auto start call in your React Native application. This is true per default. If you want to use a manual startup call, please have a look into the manual startup section.
Should be used only if you have a multiple bundle setup where you load several .bundle files within your React Native application. Enter the name of your bundle. This should be unique in comparison to your other bundle names. This will ensure that actions coming from different bundles will not interfere with each other.
react: {
bundleName: "MyCustomBundle"
}
The Android block is a wrapper for the Android configuration you find in the WebUI (in the Mobile Application Settings). Copy the content into the following block:
android : {
config : `CONTENT_OF_ANDROID_CONFIG`
}
The content of the config block is directly copied to the Gradle file. To know more about the possible configuration options, see the DSL documentation of our Gradle plugin.
The iOS block is a wrapper for the iOS configuration you find in the WebUI (in the Mobile Application Settings). Copy the content into the following block:
ios : {
config : `CONTENT_OF_IOS_CONFIG`
}
The content of the config block is directly copied to the plist file. Therefore, you can use every setting that is possible and you find in the official Mobile Agent documentation.
If you have several stages such as debug, QA, and production, you probably want to separate them and let them report in different applications. This can be done with two different approaches:
Note: Option 1 has the drawback that you always need to perform the configuration step before a build as you are basically replacing the configuration all the time. So if you made a debug build and want to do a production build, which is reporting to a different environment or has different options, you need to perform
npx instrumentDynatrace(Or if you use RN 0.60+ this happens automatically withreact-native run-androidorreact-native run-ios).
In Android, you can enter all the information in the config file. The following dynatrace {} block must be inserted into the android config variable in your dynatrace.config.js file.
android : {
config : `
dynatrace {
configurations {
dev {
variantFilter "Debug" // build type name is upper case because a product flavor is used
// other variant-specific properties
}
demo {
variantFilter "demo" // the first product flavor name is always lower case
// other variant-specific properties
}
prod {
variantFilter "Release" // build type name is upper case because a product flavor is used
// other variant-specific properties
}
}
}
`
}
This will result in the following:
> Task :app:printVariantAffiliation
Variant 'demoDebug' will use configuration 'dev'
Variant 'demoRelease' will use configuration 'demo'
Variant 'paidDebug' will use configuration 'dev'
Variant 'paidRelease' will use configuration 'prod'
In all these blocks, you can define different application IDs and even use a different environment.
In iOS, you can define some variables in the dynatrace.config.js file. These variables must then be inserted in a prebuild script. The following properties must be inserted into the iOS config variable in your dynatrace.config.js file.
ios: {
config: `
<key>DTXApplicationID</key>
<string>\${APPLICATION_ID}</string>
<key>DTXBeaconURL</key>
<string>Your Beacon URL</string>
`
}
The variable ${APPLICATION_ID} must then be inserted with a prebuild script. Make sure to use \ in front of the ${...}, because if not JavaScript thinks you are trying to insert a variable into the String. For more information, see https://medium.com/@andersongusmao/xcode-targets-with-multiples-build-configuration-90a575ddc687.
Specifies if the user has to opt-in for being monitored. When enabled, you must specify the privacy setting. For more information, see the API section.
android: {
config: `
dynatrace {
configurations {
defaultConfig {
autoStart{
...
}
userOptIn true
}
}
}
`
}
ios: {
config: `
<key>DTXUserOptIn</key>
</true>
`
}
If the instrumentation runs through and your application starts but you see no data, you probably need to dig deeper to find out why the OneAgents aren't sending any data. Opening up a support ticket is a great idea, but gathering logs first is even better.
Add the following configuration snippet to your other configuration in dynatrace.config.js right under the autoStart block (the whole structure is visible, so you know where the config belongs) and run npx instrumentDynatrace:
android: {
config: `
dynatrace {
configurations {
defaultConfig {
autoStart{
...
}
debug.agentLogging true
}
}
}
`
}
Add the following configuration snippet to your other configuration in dynatrace.config.js (the whole structure is visible, so you know where the config belongs) and run npx instrumentDynatrace:
ios: {
config: `
<key>DTXLogLevel</key>
<string>ALL</string>
`
}
Attention: Minification can cause a loss of information.
We check for a property named dtActionName when creating an action. If dtActionName exists, this will be used for the action name above every other option listed in the previous section. Example:
<TouchableHighlight dtActionName="CustomActionName">
<Text>Custom Action Name</Text>
</TouchableHighlight>
Note: actionNamePrivacy has no impact on using dtActionName. dtActionName will always be used.
Attention: If you are using Typescript and want to set this property with type-safety, look here.
In general, Dynatrace always closes the session when a crash occurs. Usually a crash is when the application gets fully terminated. In React Native, we also see fatal errors in the JavaScript part as a full crash even though the native application is still alive. When this happens we will end the session. This is due to visibility reasons and may change in the future. The automated crash reporting will be (automatically) put in place by the transformer at the very beginning of the application. Using a custom error handler afterwards will not interfere with our crash handler.
Note: The behavior mentioned below occurs if an error contains a stacktrace or if the stacktrace is empty/missing.
React introduced with React v17.x, React v16.14.0, React v15.7.0, and React v14.10 the automatic runtime which changes the JSX transformation (https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html).
This impacts our instrumentation as well. To keep the instrumentation in place you need to change your babel configuration.
For our instrumentation to work properly, you will need to add the importSource property:
Attention: In case you are using NativeWind, use 'nativewind' as the importSource for the JSX runtime in babel.config.js, as specified in the NativeWind documentation. Since you cannot stack two JSX runtimes using Babel, we internally make the NativeWind JSX runtime then call our @dynatrace/react-native-plugin JSX runtime.
module.exports = {
plugins: [
[
"@babel/plugin-transform-react-jsx",
{
runtime: "automatic",
importSource: "@dynatrace/react-native-plugin"
}
]
]
}
Using babel-preset-expo:
module.exports = function (api) {
api.cache(true);
return {
presets: [
['babel-preset-expo',
{
jsxRuntime: 'automatic',
jsxImportSource: '@dynatrace/react-native-plugin',
},
],
],
};
};
Using @react-native/babel-preset:
module.exports = {
presets: [
['module:@react-native/babel-preset'],
],
plugins: [
[
'@babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
importSource: "@dynatrace/react-native-plugin"
},
],
],
};
Using metro-react-native-babel-preset:
module.exports = {
presets: [
['module:metro-react-native-babel-preset'],
],
plugins: [
[
'@babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
importSource: "@dynatrace/react-native-plugin"
},
],
],
};
If you want to register the Dynatrace transformer in your configuration and you already have a transformer in place, change the upstreaming transformer for the Dynatrace transformer.
This can be done via a configuration value in the dynatrace.config.js. The following example shows how the configuration might look like for the popular react-native-svg-transformer. Be aware that the following example is targeting React Native v0.72.1 or newer. Be aware if you are using a different second transformer, you need to change react-native-svg-transformer/react-native accordingly.
// The `...` only indicates that there are other values as well, but we've omitted them in this example.
module.exports = {
react : {
upstreamTransformer: require.resolve('react-native-svg-transformer/react-native'),
...
},
...
}
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
const {assetExts, sourceExts} = defaultConfig.resolver;
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
transformer: {
babelTransformerPath: require.resolve(
'@dynatrace/react-native-plugin/lib/dynatrace-transformer',
),
},
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
resolver: {
assetExts: assetExts.filter(ext => ext !== 'svg'),
sourceExts: [...sourceExts, 'cjs', 'svg'],
},
};
module.exports = mergeConfig(defaultConfig, config);
const { getDefaultConfig } = require("metro-config");
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts }
} = await getDefaultConfig();
return {
transformer: {
babelTransformerPath: require.resolve('@dynatrace/react-native-plugin/lib/dynatrace-transformer')
},
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
resolver: {
assetExts: assetExts.filter((ext) => ext !== "svg"),
sourceExts: [...sourceExts, "cjs", "svg"]
}
};
})();
Because the Dynatrace Android agent now requires the MavenCentral repository, if either jcenter() or mavenCentral() is not added inside of ALL the repositories blocks via the top-level build.gradle, the build will fail.
Below is an example of what a basic top-level build.gradle file should look like after adding mavenCentral() to all repository blocks:

The location of the top-level build.gradle should be:
<rootOfProject>\android\build.gradleNote:
JCenter has noted its sunset on May 1st. Though, JCenter is still syncing with Maven Central so havingjcenter() in your build.gradle file without the use of mavenCentral() will retrieve the Dynatrace Android Gradle Plugin no problem.
Updating Gradle only affects your Android build. To update your project to Gradle 7, modify the following 3 files in your Android folder.
ProjectFolder\android\gradle\wrapper\gradle-wrapper.properties Update the distributionUrl to get a newer gradle version.distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-all.zip
ProjectFolder\android\build.gradle Update the version of your Android gradle plugin (minimum 7.x) as Gradle 7 needs a newer one. To get the newer versions, add google() in your repositories. Example of a build.gradle file:buildscript {
repositories {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:x.x.x'
}
}
allprojects {
repositories {
google()
mavenLocal()
jcenter()
maven {
url "$rootDir/../node_modules/react-native/android"
}
}
}
ProjectFolder\android\app\build.gradle This depends on how old your React Native project really is. You must change your used buildTools, compileSdkVersion, targetSdkVersion and support libaries. Older build.gradle files might look similar to this with unimportant parts removed to make the snippet smaller:...
apply from: "../../node_modules/react-native/react.gradle"
...
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
...
}
...
}
dependencies {
compile "com.android.support:appcompat-v7:28.0.0"
compile "com.facebook.react:react-native:+"
}
...
Our Android Agent currently requires Kotlin 2.0.21. However, it should be noted that using this version may cause compatibility issues with older versions of React Native and the corresponding react-native-gradle-plugin due to, for instance, differences in Kotlin metadata:
Kotlin embeds language-specific features that Java doesn't natively support (like nullability and extension functions) into bytecode using @Metadata annotations. These annotations include a metadataVersion.
react-native-gradle-plugin does not use Kotlin, avoiding metadata conflicts.react-native-gradle-plugin compiled with Kotlin 1.7.22, which expects metadataVersion 1.6.0. Using Kotlin 2.0.21 (which produces metadataVersion 1.9.0) can lead to build failures.react-native-gradle-plugin expects a metadata version that is compatible with 1.9.0.In summary, ensure your build fulfills our Kotlin 2.0.21 requirement while simultaneously fulfilling the requirements of your React Native version and its react-native-gradle-plugin.
Our Android Agent currently supports Jetpack Compose 1.4 - 1.9. If you are using an incompatible version of Jetpack Compose, you may encounter the following error message during build:
Could not resolve all dependencies for configuration ':app:debugCompileClasspath'.
Version '1.0.0' of artifact 'androidx.compose.material:material' is not supported.
Please use the latest version of the Dynatrace Android Gradle plugin.
If you encounter compatibility issues or want to disable Jetpack Compose instrumentation, you can configure this in your dynatrace.config.js file. Note: Disabling Jetpack Compose instrumentation will skip the compatibility check, allowing you to build with any version of Jetpack Compose without triggering version validation errors.
Important: The configuration example below shows only the Compose-specific setting. You must ensure that your complete dynatrace.config.js file includes all other required configuration settings (such as beaconUrl, applicationId, etc.) as described in the Android block section of this documentation.
module.exports = {
...
android: {
config: `
dynatrace {
configurations {
defaultConfig {
userActions {
composeEnabled false
}
}
}
}
`
},
For more information about Jetpack Compose instrumentation and monitoring capabilities, please refer to the official Dynatrace documentation for Android OneAgent.
This section explains the configuration of a standalone React Native project. This means you have a React Native project, but don't use the typical iOS and android folders. Instead you have a separate native iOS or android project which is embedding your React Native project.
To get the same experience as somebody who has a combined project, you roughly need to do the following things:
The mobile application in the web UI offers you a configuration wizard (see settings page) for your native project (Android/iOS). Use it and apply it to your separated native project according to this documentation:
After you have added the auto instrumentation to your native project, you need to add this plugin to your standalone react native project.
You can simply follow the setup shown in the beginning of this documentation. There is no special handling needed, except skipping step 4, as it is of course not needed as you usually create a bundle when building a standalone project.
The OneAgent for Android and iOS documentation is available at the following locations:
Note: The Dynatrace Android Gradle plugin is hosted on Maven Central. JCenter has noted it's sunset on May 1st so Maven Central is the primary source of the Dynatrace Android Gradle plugin.
When using auto-instrumenation through our plugin, here are some examples of the size differences before and after instrumentation for release builds:
| Operating System | App template | Version | Size Before | Size After | Difference |
|---|---|---|---|---|---|
| Android | Default new app | 0.74.3 | 50.7 MB | 50.9 MB | 0.2 MB |
| iOS | Default new app | 0.74.3 | 28.1 MB | 36.5 MB | 8.4 MB |
We are using module augmentation to augment the IntrinsicAttributes Interface in the JSX namespace in the React module with dtActionName and dtActionIgnore. The IntrinsicAttributes Interface in the JSX namespace contains properties that you can pass to every JSX element, thus, in short, you can use dtActionName and dtActionIgnore with full type-safety on every JSX element if you follow the setup below.
In general, ambient/global type declarations in packages like @dynatrace/react-native-plugin in your node_modules are visible and thus available to you for type checking in at least these cases:
You import any type from a .ts or .d.ts file located in our package anywhere in your project. For instance, if you do import { Dynatrace } from '@dynatrace/react-native-plugin' anywhere in your project, Typescript will consider our Types and the module augmentation will work.
You update your tsconfig.json to include our types, which will also make the module augmentation work:
"compilerOptions": {
"types": [
"@dynatrace/react-native-plugin"
]
}
We recommend the second option, since it works independent of whether you import anything from @dynatrace/react-native-plugin. We simply show the first option in case you wonder why dtActionName and dtActionIgnore are available on JSX elements despite not having added any configuration.
Attention: If you think something is not working the way it should, ALWAYS try to reset the cache of metro first before starting a support case. You can do this via the CLI react-native start --reset-cache. If it still does not work feel free to open a support case.
To resolve problems with the plugin, first look at creating logs and identify what went wrong. The logs can be found in the plugins folder of your React Native project (usually node_modules/@dynatrace/react-native-plugin/logs).
DynatraceNative.PLATFORM_ANDROID is null indicates that the linking of the native library didn't work correctly. Often, React Native is unable to link correctly. Simply unlink (react-native unlink) and link (react-native link) again and the error should be gone.Missing property DTXApplicationID indicates that there is no configuration available. Ensure that you've called npm run updateConfiguration at least once.15+ and version 2.231.1 of our plugin you could encounter the following error: npm ERR! Could not resolve dependency: npm ERR! peer react@"^16.0" from @react-native-community/picker@1.8.1. Using the old deprecrated Picker dependency was causing peer dependency issues so we updated the auto-instrumentation to use the new Picker dependency. If you are still using this @react-native-community/picker, you can manually instrument the picker without issue (create custom actions).ConfigurationBuilder instead of the deprecated ManualStartupConfiguration. There is no option to disable the crash handler using ManualStartupConfiguration.Important note: If the library you are using is not on either the support or unsupported list, that does not mean that this plugin is not compatible with the library.
Supported:
Attention: In case you are using NativeWind, use 'nativewind' as the importSource for the JSX runtime in babel.config.js, as specified in the NativeWind documentation. Since you cannot stack two JSX runtimes using Babel, we internally make the NativeWind JSX runtime then call our @dynatrace/react-native-plugin JSX runtime.
Attention: If you think something is not working the way it should, ALWAYS try to reset the cache of metro first before starting a support case. You can do this via the CLI react-native start --reset-cache. If it still does not work feel free to open a support case.
If you are struggling with a problem, submit a support ticket to Dynatrace (support.dynatrace.com) and provide the following details:
node_modules/@dynatrace/react-native-plugin/logs2.327.1
2.325.2
2.325.1
2.323.2
2.323.1
2.321.1
2.319.1
2.317.2
2.313.1
2.311.2
2.309.1
2.307.1
2.305.1
2.303.2
2.301.2
reportCrashWithException2.299.1
2.297.2
2.295.1
2.293.2
2.291.2
2.289.1
2.287.3
2.285.2
2.283.3
2.279.4
2.277.1
ConfigurationBuilder for Manual StartupManualStartupConfiguration for Manual Startup2.275.1
2.273.1
2.271.3
2.269.1
2.267.1
2.265.2
2.263.2
2.261.1
2.259.2
2.257.1
2.255.1
2.253.2
2.249.1
2.247.1
instrumentDynatrace from package.jsonnpx instrumentDynatrace and npx configDynatrace command2.243.0
2.231.1
2.227.0
2.225.0
2.217.0
2.214.0
2.207.1
1.205.0
1.202.0
1.201.0
1.200.0
1.198.0
1.192.2
0.186.0
0.182.2
0.182.1
0.181.1
0.179.1
0.174.0
0.172.0
0.171.0
0.168.0
FAQs
This plugin gives you the ability to use the Dynatrace Mobile agent in your react native application.
The npm package @dynatrace/react-native-plugin receives a total of 11,443 weekly downloads. As such, @dynatrace/react-native-plugin popularity was classified as popular.
We found that @dynatrace/react-native-plugin demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.