@dynatrace/react-native-plugin 2.343.1 → 2.347.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +674 -656
  2. package/android/build.gradle +6 -2
  3. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +24 -0
  4. package/files/plugin-runtime.gradle +17 -33
  5. package/files/plugin.gradle +1 -1
  6. package/instrumentation/BabelPluginDynatrace.js +1 -1
  7. package/instrumentation/libs/UserInteraction.js +20 -6
  8. package/instrumentation/libs/react-native/Lists.js +94 -0
  9. package/instrumentation/libs/react-native/index.js +4 -1
  10. package/instrumentation/libs/react-native.js +3 -0
  11. package/instrumentation/libs/react-navigation/ReactNavigation.js +14 -58
  12. package/instrumentation/libs/withOnPressMonitoring.js +3 -54
  13. package/internal.d.ts +2 -0
  14. package/internal.js +5 -1
  15. package/ios/DynatraceRNBridge.mm +37 -1
  16. package/lib/core/configuration/ConfigurationHandler.js +0 -21
  17. package/lib/core/logging/LogMessages.js +50 -0
  18. package/lib/dynatrace-reporter.js +1 -30
  19. package/lib/dynatrace-transformer.js +6 -34
  20. package/lib/next/configuration/INativeRuntimeConfiguration.js +0 -1
  21. package/lib/next/configuration/RuntimeConfigurationObserver.js +1 -6
  22. package/lib/next/events/spec/EventSpecContstants.js +1 -1
  23. package/lib/next/navigation/NavigationTracker.js +101 -0
  24. package/lib/next/navigation/useNavigationTracking.js +54 -0
  25. package/lib/next/triggers/TableReloadTracker.js +23 -0
  26. package/package.json +11 -21
  27. package/public.js +3 -1
  28. package/react-native-dynatrace.podspec +1 -1
  29. package/scripts/Android.js +1 -20
  30. package/scripts/Config.js +0 -4
  31. package/scripts/Deprecations.js +18 -0
  32. package/scripts/Install.js +13 -0
  33. package/scripts/PathsConstants.js +0 -4
  34. package/scripts/Uninstall.js +0 -15
  35. package/scripts/core/InstrumentCall.js +2 -3
  36. package/scripts/util/DeprecationReport.js +24 -0
  37. package/types.d.ts +212 -10
  38. package/instrumentation/DynatraceInstrumentation.js +0 -1
  39. package/instrumentation/libs/community/Picker.InstrInfo.js +0 -20
  40. package/instrumentation/libs/community/gesture-handler/Touchables.InstrInfo.js +0 -25
  41. package/instrumentation/libs/react-native/RefreshControl.InstrInfo.js +0 -12
  42. package/instrumentation/libs/react-native/Switch.InstrInfo.js +0 -12
  43. package/instrumentation/libs/react-native/Touchables.InstrInfo.js +0 -25
  44. package/instrumentation/model/Reference.js +0 -2
  45. package/instrumentation/parser/Babel.js +0 -60
  46. package/instrumentation/parser/ParserUtil.js +0 -11
  47. package/lib/features/ui-interaction/Config.js +0 -42
  48. package/lib/features/ui-interaction/IUserInteractionEvent.js +0 -16
  49. package/lib/features/ui-interaction/Plugin.Fragment.Test.js +0 -170
  50. package/lib/features/ui-interaction/Plugin.js +0 -289
  51. package/lib/features/ui-interaction/RootDetection.js +0 -51
  52. package/lib/features/ui-interaction/RootWrapper.js +0 -236
  53. package/lib/features/ui-interaction/Run.js +0 -38
  54. package/lib/features/ui-interaction/Runtime.js +0 -843
  55. package/lib/features/ui-interaction/TouchMetaResolver.js +0 -493
  56. package/lib/features/ui-interaction/Types.js +0 -14
  57. package/lib/metro/getSourceMapInfo.js +0 -26
  58. package/scripts/LineOffsetAnalyze.js +0 -25
  59. package/scripts/core/LineOffsetAnalyzeCall.js +0 -165
  60. package/scripts/util/SourceMapUtil.js +0 -68
package/README.md CHANGED
@@ -35,8 +35,8 @@ If you want to start using this plugin and are not a Dynatrace customer yet, hea
35
35
  ## Agent Versions
36
36
  These agent versions are configured in this plugin:
37
37
 
38
- * Android Agent: 8.343.1.1038
39
- * iOS Agent: 8.343.1.1007
38
+ * Android Agent: 8.347.1.1003
39
+ * iOS Agent: 8.347.1.1004
40
40
 
41
41
  ## Quick Setup
42
42
 
@@ -48,36 +48,36 @@ These agent versions are configured in this plugin:
48
48
 
49
49
  ## Advanced topics
50
50
  * [Manual OneAgent Startup](#manual-oneagent-startup)
51
- * [Manual instrumentation](#manual-instrumentation)
52
- * [Plugin Startup](#plugin-startup)
51
+ * [Real User Monitoring (RUM)](#real-user-monitoring-rum)
52
+ * [User Interaction](#user-interaction)
53
+ * [Send Event](#send-event)
54
+ * [Send Session Property Event](#send-session-property-event)
55
+ * [Event Modifier](#event-modifier)
56
+ * [Send Exception Event](#send-exception-event)
57
+ * [Send HTTP Request Event](#send-http-request-event)
58
+ * [View Monitoring](#view-monitoring)
59
+ * [App start user action](#app-start-user-action)
60
+ * [React Native Symbolication](#react-native-symbolication)
61
+ * [RUM Classic](#rum-classic)
53
62
  * [Monitor a Component](#monitor-a-component)
54
63
  * [Create Custom Action](#create-custom-actions)
55
64
  * [Cancel Actions](#cancel-actions)
56
65
  * [Manual Web Request Tagging](#manual-web-request-tagging)
57
66
  * [Report Values](#report-values)
58
67
  * [Report Stacktrace](#report-an-error-stacktrace)
59
- * [Identify User](#identify-a-user)
60
- * [End Session](#end-the-current-user-session)
61
68
  * [Crash Reporting](#manually-report-a-crash)
62
- * [User Privacy Options](#user-privacy-options)
63
69
  * [Report GPS Position](#report-gps-location)
64
70
  * [Business event capturing](#business-event-capturing)
65
71
  * [Platform independent reporting](#platform-independent-reporting)
66
72
  * [Set beacon headers](#setting-beacon-headers)
67
73
  * [Exclude Individual JSX Elements](#exclude-individual-jsx-elements)
68
- * [New RUM experience](#new-rum-experience)
69
- * [User Interaction](#user-interaction)
70
- * [Send Event](#send-event)
71
- * [Send Session Property Event](#send-session-property-event)
72
- * [Event Modifier](#event-modifier)
73
- * [Send Exception Event](#send-exception-event)
74
- * [Send HTTP Request Event](#send-http-request-event)
75
- * [View Monitoring](#view-monitoring)
76
- * [React Native Symbolication](#react-native-symbolication)
74
+ * [Extended topics](#extended-topics)
75
+ * [Identify User](#identify-a-user)
76
+ * [End Session](#end-the-current-user-session)
77
+ * [User Privacy Options](#user-privacy-options)
77
78
  * [NPX Commands](#npx-commands)
78
79
  * [npx instrumentDynatrace](#npx-instrumentdynatrace)
79
80
  * [npx configDynatrace](#npx-configdynatrace)
80
- * [npx lineOffsetDynatrace](#npx-lineoffsetdynatrace)
81
81
  * [Customizing paths for configuration](#customizing-paths-for-configuration)
82
82
  * [Manual adding iOS Agent to project](#manually-adding-ios-oneagent-to-a-project)
83
83
  * [Setup for tvOS](#setup-for-tvos)
@@ -91,10 +91,8 @@ These agent versions are configured in this plugin:
91
91
  * [Autostart](#autostart)
92
92
  * [Bundle Name and Version](#bundle-name-and-version)
93
93
  * [Navigation](#navigation)
94
- * [Source Map](#source-map)
95
94
  * [User Interaction Configuration](#user-interaction-configuration)
96
95
  * [Debugging our auto-instrumentation](#debugging-our-auto-instrumentation)
97
- * [Using our legacy jscodeshift auto-instrumentation](#using-our-legacy-jscodeshift-auto-instrumentation)
98
96
  * [Android block](#android-block)
99
97
  * [iOS block](#ios-block)
100
98
  * [Lifecycle modes](#lifecycle)
@@ -221,31 +219,7 @@ module.exports = {
221
219
  };
222
220
  ```
223
221
 
224
- 2. Make the start-up call with at least `beaconUrl` and `applicationId`:
225
-
226
- Example of a startup call:
227
-
228
- ```ts
229
- import { Dynatrace, ConfigurationBuilder } from '@dynatrace/react-native-plugin';
230
-
231
- await Dynatrace.start(new ConfigurationBuilder("beaconUrl", "applicationId").buildConfiguration());
232
- ```
233
-
234
- For more details see the section about [startup API](#plugin-startup).
235
-
236
- **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.
237
-
238
- ## Manual instrumentation
239
-
240
- To use the API of the React Native plugin, import the API:
241
-
242
- ```ts
243
- import { Dynatrace } from '@dynatrace/react-native-plugin';
244
- ```
245
-
246
- ### Plugin startup
247
-
248
- 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.
222
+ 2. Call `Dynatrace.start()` with your configuration. The startup call is triggered via the `start(configuration: IConfiguration)` method — if you configured `dynatrace.config.js` for manual startup, the plugin doesn't send any data until this function is called. At minimum you need `beaconUrl` and `applicationId`, but there are several optional configuration parameters as well:
249
223
 
250
224
  ```ts
251
225
  import { Dynatrace, ConfigurationBuilder, LogLevel } from '@dynatrace/react-native-plugin';
@@ -265,6 +239,8 @@ configurationBuilder.withCrashReporting(true)
265
239
  await Dynatrace.start(configurationBuilder.buildConfiguration());
266
240
  ```
267
241
 
242
+ **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.
243
+
268
244
  **Info**: The value used in the function calls for the parameters is also their default value.
269
245
 
270
246
  | Property name | Type | Default | Description |
@@ -282,866 +258,899 @@ await Dynatrace.start(configurationBuilder.buildConfiguration());
282
258
  |actionNameAlgorithm |string |'depth-first' |Controls the traversal algorithm used when searching the component tree for the name of an `onPress` action. `'depth-first'` follows the first child branch fully before trying siblings. `'breadth-first'` visits all siblings at a level before going deeper, returning the shallowest match first.|
283
259
  |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.
284
260
 
285
- **Attention:**
261
+ **Attention:**
286
262
  * Keep in mind that configuration within the `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)`.
287
263
  * Please use those parameters only when doing a manual startup. If you want to do an automated startup, please configure the properties via the [auto startup configuration](#manual-startup-counterparts). You will find a list which explains all the counterparts for the available options here.
288
264
 
289
- ### Monitor a Component
265
+ ## Real User Monitoring (RUM)
290
266
 
291
- 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`.
267
+ Real User Monitoring 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.
292
268
 
293
- * Example with Functional Component:
269
+ For more detailed information about Real User Monitoring, see the [official Dynatrace documentation](https://docs.dynatrace.com/docs/shortlink/react-native-main).
294
270
 
295
- ```ts
296
- import { Dynatrace } from '@dynatrace/react-native-plugin';
297
- import { FunctionComponent } from 'react';
271
+ ### Send Event
298
272
 
299
- export const MyFunctionalComponent: FunctionComponent<{}> = () => {
300
- return null;
301
- }
273
+ The `sendEvent()` method allows you to send custom events with arbitrary properties using the EventData class. This is useful for tracking specific user interactions or application state changes.
302
274
 
303
- Dynatrace.withMonitoring(MyFunctionalComponent, "MyFunctionalComponent");
275
+ ```ts
276
+ import { Dynatrace, EventData } from '@dynatrace/react-native-plugin';
277
+
278
+ // Send a custom event with properties
279
+ Dynatrace.sendEvent(new EventData()
280
+ .addEventProperty("event_properties.button_clicked", "login_button")
281
+ .addEventProperty("event_properties.user_type", "premium")
282
+ .addEventProperty("event_properties.attempt_count", 3)
283
+ .withDuration(250)
284
+ );
304
285
  ```
305
- ![rnFunctionalComp](https://dt-cdn.net/images/rnfunctionalcomp-800-d98eacef6d.png)
306
286
 
307
- The String "MyFunctionalComponent" is optional as the name of the component can be retrieved through [different properties](#how-does-dynatrace-determine-the-user-action-name).
287
+ **Property Requirements:**
288
+ * Only properties prefixed with `event_properties.*` are allowed
289
+ * Additionally, the `duration` property is allowed
290
+ * Maximum of 50 custom properties per event
291
+ * If the limit is exceeded, properties are sorted alphabetically by key and excess properties are dropped deterministically
292
+ * String properties are limited to 5000 characters (exceeding characters are truncated)
293
+ * Field names must contain only alphabetic characters, numbers, underscores, and dots
294
+ * Each dot must be followed by an alphabetic character
295
+ * Each underscore must be followed by an alphabetic character or number
296
+ * Values must be primitive types (string, number, boolean)
297
+ * Cannot contain functions, undefined, Infinity, or NaN as values (they will be replaced with null)
308
298
 
309
- 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.
299
+ ### Send Session Property Event
310
300
 
311
- ### Create custom actions
301
+ Session properties apply to all events within the current session. Use `sendSessionPropertyEvent()` to set properties that should be available across the entire user session.
312
302
 
313
- There are two options to create an action. Either using `enterAutoAction` (the previous `enterAction`) or `enterManualAction`:
303
+ ```ts
304
+ import { Dynatrace, SessionPropertyEventData } from '@dynatrace/react-native-plugin';
314
305
 
315
- **Important:** Action names are limited to 250 characters and will be truncated if they exceed this limit.
306
+ // Set session-wide properties
307
+ Dynatrace.sendSessionPropertyEvent(new SessionPropertyEventData()
308
+ .addSessionProperty("session_properties.user_tier", "premium")
309
+ .addSessionProperty("session_properties.app_version", "2.1.0")
310
+ .addSessionProperty("session_properties.feature_flag_enabled", true)
311
+ );
312
+ ```
316
313
 
317
- * `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.
314
+ **Important Notes:**
315
+ * Session properties persist throughout the entire session
316
+ * If you send the same property multiple times, only one value will be kept (first or last)
317
+ * Use session properties for data that applies to the entire user session
318
+ * Field naming follows the same rules as events, but with `session_properties.` prefix
319
+ * Maximum of 50 custom properties per event
320
+ * If the limit is exceeded, properties are sorted alphabetically by key and excess properties are dropped deterministically
318
321
 
319
- ```ts
320
- import { Dynatrace } from '@dynatrace/react-native-plugin';
322
+ ### Event Modifier
321
323
 
322
- const myAction = Dynatrace.enterAutoAction("MyButton tapped");
323
- //Perform the action and whatever else is needed.
324
- myAction.leaveAction();
325
- ```
326
- ![rnSingle](https://dt-cdn.net/images/rnsingle-800-e7e1b343ed.png)
324
+ Event 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. Event modifiers apply to all event types, including custom events, session properties, exceptions, and HTTP events.
327
325
 
328
- * `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`.
326
+ If multiple event modifiers are added, they are executed in the order they were added.
329
327
 
330
- ```ts
331
- import { Dynatrace } from '@dynatrace/react-native-plugin';
328
+ Most fields and namespaces can't be modified in any way (added, removed or overridden), while others are open for modification.
332
329
 
333
- const myAction = Dynatrace.enterManualAction("MyButton tapped");
334
- //Perform the action and whatever else is needed.
335
- myAction.leaveAction();
336
- ```
330
+ **Open for modification and can be added:**
331
+ - `event_properties.*`
332
+ - `session_properties.*`
337
333
 
338
- 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](#report-values).
334
+ `session_properties.*` are only allowed to be on a session property event.
335
+
336
+ **Open for modification only:**
337
+ - `url.full`
338
+ - `exception.stack_trace`
339
+
340
+ #### Example
339
341
 
340
342
  ```ts
341
- import { Dynatrace } from '@dynatrace/react-native-plugin';
343
+ import { Dynatrace, IEventModifier } from '@dynatrace/react-native-plugin';
342
344
 
343
- const myAction = Dynatrace.enterAutoAction("MyButton tapped");
344
- //Perform the action and whatever else is needed.
345
- myAction.leaveAction();
345
+ // Create an event modifier
346
+ const myModifier: IEventModifier = {
347
+ modifyEvent(event) {
348
+ // Add common properties to all events
349
+ event["event_properties.app_build"] = "1.2.3";
350
+ event["event_properties.environment"] = "production";
351
+
352
+ // Return null to discard the event entirely
353
+ if (event["event_properties.ignore"] === true) {
354
+ return null;
355
+ }
356
+
357
+ return event;
358
+ }
359
+ };
360
+
361
+ // Add the modifier
362
+ Dynatrace.addEventModifier(myModifier);
363
+
364
+ // Remove the modifier when no longer needed
365
+ Dynatrace.removeEventModifier(myModifier);
346
366
  ```
347
367
 
348
- ### Create custom sub actions
368
+ #### Important Considerations
349
369
 
350
- 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.
370
+ - **Execution order**: If multiple event modifiers are added, they are executed in the order they were added
371
+ - **Returning null**: Returning `null` discards the event and prevents future modifier functions from being executed
372
+ - **Performance**: Event modifiers should be efficient as they are called for every event
373
+ - **Field naming**: Custom properties must follow the `event_properties.*` or `session_properties.*` prefix naming convention
374
+ - **Reserved fields**: Certain reserved fields and namespaces cannot be modified. Attempts to modify them will be ignored
375
+ - **Error handling**: If a modifier throws an exception, it will be logged but won't prevent other modifiers from executing
376
+ - **Primitive values**: Event fields can only contain primitive values (String, int, double, bool)
377
+ - **Invalid argument**: In case you pass an invalid argument to `addEventModifier`, we return a no-op placeholder modifier.
351
378
 
352
- **Important:** Action names are limited to 250 characters and will be truncated if they exceed this limit.
379
+ ### Send Exception Event
380
+
381
+ The `sendExceptionEvent()` method provides a structured way to report exceptions with additional context and custom properties using the ExceptionEventData class.
353
382
 
354
383
  ```ts
355
- import { Dynatrace } from '@dynatrace/react-native-plugin';
384
+ import { Dynatrace, ExceptionEventData } from '@dynatrace/react-native-plugin';
356
385
 
357
- const myAction = Dynatrace.enterManualAction("MyButton tapped");
358
- const mySubAction = myAction.enterAction("MyButton Sub Action");
359
- //Perform the action and whatever else is needed.
360
- mySubAction.leaveAction();
361
- myAction.leaveAction();
386
+ try {
387
+ // Code that may throw an error
388
+ throw new Error('Something went wrong');
389
+ } catch (error) {
390
+ if (error instanceof Error) {
391
+ Dynatrace.sendExceptionEvent(new ExceptionEventData(error)
392
+ .addEventProperty('event_properties.custom_key', 'custom_value')
393
+ .addEventProperty('event_properties.error_context', 'user_action')
394
+ );
395
+ }
396
+ }
362
397
  ```
363
- ![subAction](https://dt-cdn.net/images/subaction-800-172dbcca6c.png)
364
398
 
365
- ### Cancel actions
399
+ **Parameters:**
400
+ * `error`: The Error object containing exception information (required)
366
401
 
367
- 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.
402
+ ### Send HTTP Request Event
403
+
404
+ The `sendHttpRequestEvent()` method allows you to manually report HTTP request events with detailed information about the request and response.
368
405
 
369
406
  ```ts
370
- import { Dynatrace } from '@dynatrace/react-native-plugin';
407
+ import { Dynatrace, HttpRequestEventData } from '@dynatrace/react-native-plugin';
371
408
 
372
- const myAction = Dynatrace.enterAutoAction("MyButton tapped");
373
- // Action will be canceled
374
- myAction.cancel();
409
+ // Basic HTTP request event
410
+ const requestEventData = new HttpRequestEventData('https://api.example.com/users', 'GET');
411
+ Dynatrace.sendHttpRequestEvent(requestEventData);
375
412
 
376
- // Has no impact as the action is already canceled
377
- myAction.leaveAction();
413
+ // HTTP request with additional details
414
+ const detailedRequestEventData = new HttpRequestEventData('https://api.example.com/data', 'POST')
415
+ .withStatusCode(200)
416
+ .addEventProperty('event_properties.headers.content_type', 'application/json');
417
+ Dynatrace.sendHttpRequestEvent(detailedRequestEventData);
378
418
  ```
379
419
 
380
- ### Manual Web Request Tagging
420
+ **Parameters:**
421
+ * `url`: The URL of the HTTP request (required)
422
+ * `method`: The HTTP method (e.g., 'GET', 'POST', 'PUT', 'DELETE') (required)
381
423
 
382
- 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.
424
+ ### View Monitoring
383
425
 
384
- **Note:**
385
- Using this API will force the request to be added to the action that is manually created.
426
+ The view monitoring APIs allow you to track different screens or views in your application, providing context for all events happening within those views.
386
427
 
387
- ```ts
388
- import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-plugin';
428
+ There are two ways to monitor views:
429
+ 1. **Automatic view monitoring** - Enable navigation tracking in your configuration to automatically capture view changes through supported navigation libraries (enabled by default)
430
+ 2. **Manual view monitoring** - Use the `startView()` API to manually control when view contexts are created and updated
389
431
 
390
- const action = Dynatrace.enterManualAction('API Data Fetch');
391
- const url = 'https://api.example.com/data';
392
- const tag = await action.getRequestTag(url);
393
- const timing = new DynatraceWebRequestTiming(tag, url);
432
+ > **Important:** These approaches should not be mixed, as the outcome is unpredictable. Choose either automatic or manual view monitoring for your application.
394
433
 
395
- try {
396
- timing.startWebRequestTiming();
397
- const response = await fetch(url, {
398
- headers: {
399
- [timing.getRequestTagHeader()]: tag
400
- }
401
- });
402
- timing.stopWebRequestTiming(response.status, response.statusText);
403
- } catch (error) {
404
- if (error instanceof Error) {
405
- timing.stopWebRequestTiming(-1, error.message);
406
- } else {
407
- timing.stopWebRequestTiming(-1, (error as any).toString());
434
+ #### Automatic Navigation tracking
435
+
436
+ > **Note:** This feature only works with `@react-navigation` versions 5.x through 7.x.
437
+
438
+ The following is an example of how this feature can be configured in your `dynatrace.config.js` file. Note that this feature is enabled by default.
439
+
440
+ ```js
441
+ react: {
442
+ navigation: {
443
+ enabled: true
408
444
  }
409
- } finally {
410
- action.leaveAction();
411
445
  }
412
446
  ```
413
- ![rnManualWeb](https://dt-cdn.net/images/rnmanualweb-800-662d009613.png)
414
447
 
415
- There is also the option to report values for request and response size:
448
+ When this feature is enabled, the view context will represent the current state of the `@react-navigation` `NavigationContainer`. The state gets represented as a URL-style route. All subsequent events get associated with the view context and thus with the current route.
416
449
 
417
- ```ts
418
- import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-plugin';
450
+ For instance, assume the following setup:
451
+ ```js
452
+ const Drawer = createDrawerNavigator();
419
453
 
420
- const action = Dynatrace.enterManualAction('API Data Upload');
421
- const url = 'https://api.example.com/upload';
422
- const tag = await action.getRequestTag(url);
423
- const timing = new DynatraceWebRequestTiming(tag, url);
424
- const requestData = JSON.stringify({ key: 'value' });
454
+ function App() {
455
+ return (
456
+ <NavigationContainer>
457
+ <Drawer.Navigator initialRouteName="Home">
458
+ <Drawer.Screen name="Home" component={HomeScreen} />
459
+ <Drawer.Screen name="Feature" component={FeatureScreen}/>
460
+ </Drawer.Navigator>
461
+ </NavigationContainer>
462
+ );
463
+ }
425
464
 
426
- try {
427
- timing.startWebRequestTiming();
428
- const response = await fetch(url, {
429
- method: 'POST',
430
- headers: {
431
- [timing.getRequestTagHeader()]: tag,
432
- 'Content-Type': 'application/json'
433
- },
434
- body: requestData
435
- });
436
- const responseData = await response.text();
437
- timing.stopWebRequestTimingWithSize(
438
- response.status,
439
- response.statusText,
440
- requestData.length,
441
- responseData.length
465
+ const Stack = createStackNavigator();
466
+
467
+ function FeatureScreen() {
468
+ return (
469
+ <Stack.Navigator initialRouteName="ScreenOne">
470
+ <Stack.Screen name="ScreenOne" component={NestedScreenOne} />
471
+ <Stack.Screen name="ScreenTwo" component={NestedScreenTwo} />
472
+ </Stack.Navigator>
442
473
  );
443
- } catch (error) {
444
- if (error instanceof Error) {
445
- timing.stopWebRequestTiming(-1, error.message);
446
- } else {
447
- timing.stopWebRequestTiming(-1, (error as any).toString());
448
- }
449
- } finally {
450
- action.leaveAction();
451
474
  }
452
475
  ```
453
- ![rnBytes](https://dt-cdn.net/images/rnbytes-800-139042060c.png)
454
476
 
455
- ### Report values
477
+ When navigating to `Home`, the view context will be set to `/Home`. When navigating to `Feature` and being redirected to the nested `ScreenOne`, the view context will be set to `/Home/ScreenOne`. When navigating to `ScreenTwo` within `Feature`, the view context will be set to `/Feature/ScreenTwo`.
456
478
 
457
- For any open action you can report certain values. The following API is available for action:
479
+ #### Start View
480
+
481
+ 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.
458
482
 
459
483
  ```ts
460
- import { Platform } from '@dynatrace/react-native-plugin';
484
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
461
485
 
462
- interface IDynatraceAction {
463
- reportDoubleValue(valueName: string, value: number, platform?: Platform): void;
464
- reportError(errorName: string, errorCode: number, platform?: Platform): void;
465
- reportEvent(eventName: string, platform?: Platform): void;
466
- reportIntValue(valueName: string, value: number, platform?: Platform): void;
467
- reportStringValue(valueName: string, value: string, platform?: Platform): void;
468
- }
486
+ // Start monitoring a view
487
+ Dynatrace.startView("HomeScreen");
469
488
  ```
470
489
 
471
- **Important:** All string parameters (errorName, eventName, valueName, value) are limited to 250 characters and will be truncated if they exceed this limit.
490
+ **Important Considerations:**
491
+ * Only one view can be active at a time
492
+ * Starting a new view will automatically stop the previous one
493
+ * View names should be meaningful and consistent across your application
494
+ * All events captured after starting a view will include the view context
472
495
 
473
- To report a string value, use the following:
496
+ **Complete Example:**
474
497
 
475
498
  ```ts
476
- import { Dynatrace } from '@dynatrace/react-native-plugin';
499
+ import { Dynatrace, EventData } from '@dynatrace/react-native-plugin';
477
500
 
478
- const myAction = Dynatrace.enterAutoAction("MyButton tapped");
479
- myAction.reportStringValue("ValueName", "ImportantValue");
480
- myAction.leaveAction();
481
- ```
482
- ![rnReportString](https://dt-cdn.net/images/rnreportstring-800-739e5ba752.png)
501
+ // User navigates to profile screen
502
+ Dynatrace.startView("UserProfile");
483
503
 
484
- 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](#platform-independent-reporting).
504
+ // Send custom event within the view
505
+ Dynatrace.sendEvent(new EventData()
506
+ .addEventProperty("event_properties.profile_action", "edit_profile")
507
+ .addEventProperty("event_properties.changes_made", true)
508
+ );
485
509
 
510
+ // User navigates away
511
+ Dynatrace.startView("UserProfileDetailed");
512
+ ```
486
513
 
487
- ### Report an error stacktrace
514
+ ### User Interaction
488
515
 
489
- To manually report an error stacktrace, use the following API call:
516
+ User Interaction is an automatic instrumentation feature that captures touch and press events in your React Native application without requiring any manual API calls. When enabled, the plugin instruments your UI components at build time and sends structured interaction events to Dynatrace at runtime.
490
517
 
491
- ```ts
492
- import { Dynatrace } from '@dynatrace/react-native-plugin';
518
+ The following is an example of how this feature can be configured in your `dynatrace.config.js` file. Note that this feature is enabled by default.
493
519
 
494
- try {
495
- throw new Error('Database connection failed');
496
- } catch (error) {
497
- if (error instanceof Error) {
498
- Dynatrace.reportErrorStacktrace(
499
- 'DatabaseError',
500
- error.message,
501
- 'Failed to connect to remote database',
502
- error.stack || 'No stack trace available'
503
- );
504
- }
520
+ ```js
521
+ react: {
522
+ userInteraction: true
505
523
  }
506
524
  ```
507
- ![rnStack](https://dt-cdn.net/images/rnstack-800-26c6ac7408.png)
508
-
509
- **Note:**
510
- The previous API without *errorValue* is deprecated and will be removed in the future. Please use the new API with errorValue if possible.
511
525
 
512
- ### Identify a user
526
+ When enabled, UI Interaction can be controlled by two layers:
513
527
 
514
- You can identify a user and tag the current session with a name by making the following call:
528
+ 1. **Build/config layer (`dynatrace.config.js`)**
529
+ - `react.userInteraction: true|false` controls whether the UI Interaction instrumentation feature is applied.
515
530
 
516
- **Important:** The user identifier is limited to 250 characters and will be truncated if it exceeds this limit.
531
+ 2. **Runtime remote layer**
532
+ - CP always forwards User Interaction Actions (UIA) to the native agent unconditionally. The native agent decides whether to record or discard each UIA based on its own remote configuration (e.g. `touch_interaction_enabled`).
517
533
 
518
- ```ts
519
- import { Dynatrace } from '@dynatrace/react-native-plugin';
534
+ #### Masking sensitive UI labels
520
535
 
521
- Dynatrace.identifyUser("User XY");
522
- ```
523
- ![rnTag](https://dt-cdn.net/images/rntag-800-77fe848023.png)
536
+ UI Interaction also supports masking sensitive labels before events are sent.
524
537
 
525
- ### End the current user session
538
+ Masking is applied when:
526
539
 
527
- To end the current user session, use the following API call:
540
+ * the touched element or one of its parents is marked with `dtMask`
541
+ * the runtime masking rules classify the detected text as sensitive
542
+ * the runtime masking rules classify the element `testID` as sensitive
528
543
 
529
- ```ts
530
- import { Dynatrace } from '@dynatrace/react-native-plugin';
544
+ When masking is active:
531
545
 
532
- Dynatrace.endSession();
533
- ```
546
+ * the interaction path and component information are still reported
547
+ * the detected UI label is replaced with the configured replacement string (default: `***`)
548
+ * `ui_element.name_origin` is reported as `masked`
534
549
 
535
- **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](#identify-a-user) API.
550
+ Example using `dtMask`:
536
551
 
537
- ### Manually report a crash
552
+ ```tsx
553
+ <View dtMask>
554
+ <Pressable onPress={onPress}>
555
+ <Text>john.doe@example.com</Text>
556
+ </Pressable>
557
+ </View>
558
+ ```
538
559
 
539
- You can manually report a crash via the following API calls:
560
+ This allows you to preserve interaction analytics while avoiding exposure of sensitive text in the emitted UI Interaction event.
540
561
 
541
- ```ts
542
- import { Dynatrace } from '@dynatrace/react-native-plugin';
543
562
 
544
- try {
545
- throw new Error('Fatal memory allocation failure');
546
- } catch (error) {
547
- if (error instanceof Error) {
548
- Dynatrace.reportCrash(
549
- 'MemoryError',
550
- error.message,
551
- error.stack || 'No stack trace available'
552
- );
563
+ #### Produced data
553
564
 
554
- // or directly via the full error
555
- Dynatrace.reportCrashWithException('MemoryError', error);
556
- }
557
- }
558
- ```
559
- ![rnCrash](https://dt-cdn.net/images/rncrash-800-3e7391140f.png)
565
+ Each captured interaction produces an event describing what the user touched and where. The event includes:
560
566
 
561
- > **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.
567
+ - **Detected name** — the resolved label of the touched element, derived from its visible text, accessibility label, component name, or test ID.
568
+ - **Component** — the type of the UI component that was touched (e.g. `Pressable`).
569
+ - **Component Path** — a stable path through the component tree that uniquely identifies the element (e.g. `App/View[1]/Pressable[1]`).
570
+ - **Interaction type** — how the user interacted (e.g. `touch`).
571
+ - **Position** — the screen coordinates where the touch occurred.
562
572
 
563
- *reportCrashWithException* will use the crashName as name for the crash. It will only report the crash if there is also a stacktrace available.
573
+ In some cases, a **responder** is also included. The responder is the component that ultimately handled the user's touch — for example, a `Pressable` that received the press event. It carries the same name, component type, and path information as the touched element, and can differ when a touch is visually on a child element but handled by a parent.
564
574
 
565
- ### User Privacy Options
575
+ If masking is active for an interaction, the event still contains the same structural information, but the detected name is replaced and the name origin changes to `masked`.
566
576
 
567
- 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:
577
+ #### Example event
568
578
 
569
- ```ts
570
- export enum DataCollectionLevel {
571
- Off, Performance, UserBehavior
579
+ ```json
580
+ {
581
+ "characteristics.has_user_interaction": true,
582
+ "ui_element.detected_name": "LoginButton",
583
+ "ui_element.components": ["Pressable"],
584
+ "ui_element.id": "App/View/Pressable",
585
+ "ui_element.name_origin": "component",
586
+ "interaction.type": "touch",
587
+ "positions": [{ "x": 120, "y": 460 }],
588
+ "ui_element.responder.detected_name": "Pressable",
589
+ "ui_element.responder.components": ["Pressable"],
590
+ "ui_element.responder.id": "App/View[/Pressable",
591
+ "ui_element.responder.name_origin": "component"
572
592
  }
573
593
  ```
574
594
 
575
- 1. Off: Native Agent doesn't capture any monitoring data.
576
- 2. Performance: Native Agent captures only anonymous performance data. Monitoring data that can be used to identify individual users, such as user tags and custom values, aren't captured.
577
- 3. UserBehavior: Native Agent captures both performance and user data. In this mode, Native Agent recognizes and reports users who re-visit in future sessions.
595
+ #### Custom Names for Components
578
596
 
579
- 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`](#user-opt-in-mode) and set the User Privacy Options.
597
+ You can assign custom names to your components. A custom name affects both the **Component** and the **Component Path** described above. There are two ways to do this, depending on how the component is used.
580
598
 
581
- The API to get and set the current privacy level looks like this:
599
+ ##### 1. As a JSX prop (`dtActionName`)
582
600
 
583
- ```ts
584
- import { Platform, UserPrivacyOptions } from '@dynatrace/react-native-plugin';
601
+ Use this when you render the component as JSX. Pass `dtActionName` as a prop, and it overrides the auto-detected name for that specific usage:
585
602
 
586
- interface IDynatrace {
587
- getUserPrivacyOptions(platform?: Platform): Promise<UserPrivacyOptions>;
588
- applyUserPrivacyOptions(userPrivacyOptions: UserPrivacyOptions, platform?: Platform): void;
589
- }
603
+ ```tsx
604
+ <TouchableOpacity dtActionName="Checkout Button" onPress={onCheckout}>
605
+ <Text dtActionName="Checkout Text">Buy now</Text>
606
+ </TouchableOpacity>
590
607
  ```
591
608
 
592
- To check the current privacy options that are set:
593
-
594
- ```ts
595
- import { Dynatrace } from '@dynatrace/react-native-plugin';
609
+ Touching it produces:
596
610
 
597
- const privacyOptions = await Dynatrace.getUserPrivacyOptions();
611
+ ```json
612
+ "ui_element.components": ["Checkout Text"],
613
+ "ui_element.id": ".../Checkout Button/Checkout Text"
598
614
  ```
599
615
 
600
- If you want to create a new `UserPrivacyOptions` object and pass it to Dynatrace:
601
-
602
- ```ts
603
- import { Dynatrace, DataCollectionLevel, UserPrivacyOptions } from '@dynatrace/react-native-plugin';
616
+ ##### 2. As a static property (`Component.dtActionName`)
604
617
 
605
- const privacyConfig = new UserPrivacyOptions(DataCollectionLevel.UserBehavior, true);
618
+ Use this when the component is **not** rendered as JSX, so the prop approach above is not available — for example, a screen component you define once and hand to a navigator by reference. Set `dtActionName` directly on the component. This affects **every** place the component is used at once:
606
619
 
607
- // Getter and setter available for UserPrivacyOptions
608
- privacyConfig.crashReportingOptedIn = false;
609
- privacyConfig.dataCollectionLevel = DataCollectionLevel.Performance;
620
+ ```tsx
621
+ import { NavigationContainer } from '@react-navigation/native';
622
+ import { createDrawerNavigator } from '@react-navigation/drawer';
610
623
 
611
- const level = privacyConfig.dataCollectionLevel;
612
- const crashReporting = privacyConfig.crashReportingOptedIn;
624
+ const Drawer = createDrawerNavigator();
613
625
 
614
- Dynatrace.applyUserPrivacyOptions(privacyConfig);
615
- ```
626
+ function ProfileScreen() {
627
+ return (/* ... */);
628
+ }
616
629
 
617
- ### Report GPS Location
630
+ // Applies to all usages of ProfileScreen below
631
+ ProfileScreen.dtActionName = 'User Profile';
618
632
 
619
- You can report latitude and longitude and specify an optional platform.
633
+ function App() {
634
+ return (
635
+ <NavigationContainer>
636
+ <Drawer.Navigator>
637
+ {/* Both screens reference the same component,
638
+ so both pick up the 'User Profile' name */}
639
+ <Drawer.Screen name="Me" component={ProfileScreen} />
640
+ <Drawer.Screen name="Account" component={ProfileScreen} />
641
+ </Drawer.Navigator>
642
+ </NavigationContainer>
643
+ );
644
+ }
645
+ ```
620
646
 
621
- ```ts
622
- import { Dynatrace } from '@dynatrace/react-native-plugin';
647
+ Touches inside one of the 2 screens now produce:
623
648
 
624
- Dynatrace.setGPSLocation(48.31518732698596, 14.305245274594471);
649
+ ```json
650
+ "ui_element.id": ".../User Profile/..."
625
651
  ```
626
652
 
627
- ### Platform independent reporting
653
+ > **Note:** The static property applies to *all* uses of the component. If you need a different name per usage, render the component as JSX and use the `dtActionName` prop (option 1) instead.
654
+ >
655
+ > **Note:** The static property has no effect when a component is rendered as JSX. In that case the name is taken from either the `dtActionName` prop passed to it (option 1) or the name of the JSX component.
628
656
 
629
- 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:
630
- * Passing to **iOS** only:
631
- ```ts
632
- import { Dynatrace, Platform } from '@dynatrace/react-native-plugin';
657
+ ### App start user action
633
658
 
634
- const myAction = Dynatrace.enterAutoAction("MyButton tapped", Platform.Ios);
635
- //Perform the action and whatever else is needed.
636
- myAction.leaveAction(Platform.Ios);
637
- ```
638
-
639
- * Passing to **Android** only:
640
- ```ts
641
- import { Dynatrace, Platform } from '@dynatrace/react-native-plugin';
659
+ OneAgent automatically creates a user action for each app start. The action starts at the first measured React Native startup phase (`runJsBundleStart`) and ends when `contentAppeared` fires — once the JavaScript bundle has loaded and the first content is displayed. The action groups all web requests, navigations, and errors that occur during startup.
642
660
 
643
- const myAction = Dynatrace.enterAutoAction("MyButton tapped", Platform.Android);
644
- //Perform the action and whatever else is needed.
645
- myAction.leaveAction(Platform.Android);
646
- ```
647
-
648
- * Passing to **both**:
649
- ```ts
650
- import { Dynatrace } from '@dynatrace/react-native-plugin';
661
+ **Startup phases captured (in order):**
651
662
 
652
- const myAction = Dynatrace.enterAutoAction("MyButton tapped");
653
- //Perform the action and whatever else is needed.
654
- myAction.leaveAction();
655
- ```
663
+ | Phase | Android | iOS |
664
+ |---|---|---|
665
+ | `downloadStart` / `downloadEnd` | Dev mode only (Metro bundle download) | Not captured |
666
+ | `runJsBundleStart` / `runJsBundleEnd` | Yes | Yes |
667
+ | `contentAppeared` | Yes | Yes |
656
668
 
657
- ### Business event capturing
669
+ > **Note:** Unlike Android and iOS native agents, the React Native plugin does not distinguish cold, warm, and hot start types — the native SDK sets the start type when it receives the event.
658
670
 
659
- With `sendBizEvent`, you can report business events. These events are standalone events, as OneAgent sends them detached from user actions or user sessions.
671
+ **Controlling the app start user action**
660
672
 
661
- For more information on business events, see [dynatrace documentation](https://docs.dynatrace.com/docs/observe/business-observability/explore-business-events).
673
+ The app start user action is part of automatic user action detection and is controlled at runtime with `setAutomaticUserActionDetection`:
662
674
 
663
675
  ```ts
664
676
  import { Dynatrace } from '@dynatrace/react-native-plugin';
665
677
 
666
- Dynatrace.sendBizEvent("com.easytravel.funnel.booking-finished", {
667
- "event.name" : "Confirmed Booking",
668
- "screen": "booking-confirmation",
669
- "product": "Danube Anna Hotel",
670
- "amount": 358.35,
671
- "currency": "USD",
672
- "reviewScore": 4.8,
673
- "arrivalDate": "2022-11-05",
674
- "departureDate": "2022-11-15",
675
- "journeyDuration": 10,
676
- "adultTravelers": 2,
677
- "childrenTravelers": 0
678
- });
678
+ // Disable all automatic user actions including the app start user action
679
+ Dynatrace.setAutomaticUserActionDetection(false);
680
+
681
+ // Re-enable
682
+ Dynatrace.setAutomaticUserActionDetection(true);
679
683
  ```
680
- ![rnBiz](https://dt-cdn.net/images/rnbiz-1262-f57a0a67f3.png)
681
684
 
682
- ### Setting beacon headers
685
+ This call applies to all automatic user actions (app start, touch/press interactions). To disable only touch interactions while keeping the app start user action, use `react.userInteraction: false` in `dynatrace.config.js` instead.
683
686
 
684
- 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.
687
+ For more details, see the [App start user action documentation](https://docs.dynatrace.com/docs/shortlink/react-native-app-performance#app-start-user-action).
685
688
 
686
- **Note:** To clear the previously set headers, call the method without the headers parameter or with a null value for the headers parameter.
689
+ ### React Native Symbolication
687
690
 
688
- ```ts
689
- import { Dynatrace } from '@dynatrace/react-native-plugin';
691
+ Dynatrace can automatically symbolicate JavaScript stack traces captured by the plugin using sourcemaps. This allows you to view human-readable file names, line numbers, and column information in your crash reports.
690
692
 
691
- const beaconHeaders = new Map<string, string>();
692
- beaconHeaders.set('headerName', 'headerValue');
693
- Dynatrace.setBeaconHeaders(beaconHeaders);
694
- ```
693
+ #### Generating Sourcemaps
695
694
 
696
- ### Exclude Individual JSX Elements
695
+ Sourcemaps are generated during release builds and map bytecode offsets (Hermes) and locations in the minified JavaScript bundle (JavaScriptCore) back to your original source code. We support sourcemaps for both Hermes and JavaScriptCore. For detailed instructions on generating sourcemaps, see the [React Native debugging release builds guide](https://reactnative.dev/docs/debugging-release-builds).
697
696
 
698
- 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:
697
+ To generate a sourcemap:
699
698
 
700
- ```tsx
701
- import React from 'react';
702
- import { TouchableHighlight, Text, View } from 'react-native';
699
+ **Android:**
700
+ * Run `npx react-native run-android --mode release` in your project root, or
701
+ * Run `gradlew assembleRelease` in the `/android` directory
703
702
 
704
- const TouchableHighlightScreen = () => {
705
- return (
706
- <View>
707
- <TouchableHighlight onPress={onPress}>
708
- <Text>TouchableHighlight that will be monitored</Text>
709
- </TouchableHighlight>
710
- <TouchableHighlight onPress={onPress} dtActionIgnore="true">
711
- <Text>TouchableHighlight that will be ignored</Text>
712
- </TouchableHighlight>
713
- </View>
714
- );
715
- };
703
+ **iOS:**
704
+ * First, enable sourcemaps according to the [React Native debugging release builds guide](https://reactnative.dev/docs/debugging-release-builds)
705
+ * Then run `npx react-native run-ios --mode Release`, or
706
+ * Build for release in Xcode
716
707
 
717
- const onPress = () => {
718
- console.log("TouchableHighlight Pressed!");
719
- };
708
+ #### Uploading Sourcemaps
720
709
 
721
- export default TouchableHighlightScreen;
722
- ```
710
+ Once generated, upload your sourcemaps to Dynatrace. For detailed instructions, see the [symbol file management documentation](https://docs.dynatrace.com/docs/observe/digital-experience/mobile-applications/analyze-and-use/upload-and-manage-symbol-files).
723
711
 
724
- 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.
712
+ ## RUM Classic
725
713
 
726
- >*Attention:* If you are using Typescript and want to set this property with type-safety, look [here](#typescript-setup-for-dtactionignore-and-dtactionname).
714
+ ### Monitor a Component
727
715
 
728
- ## New RUM experience
716
+ 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`.
729
717
 
730
- 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.
718
+ * Example with Functional Component:
731
719
 
732
- For more detailed information about the New RUM Experience, see the [official Dynatrace documentation](https://docs.dynatrace.com/docs/shortlink/react-native-main).
720
+ ```ts
721
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
722
+ import { FunctionComponent } from 'react';
733
723
 
734
- ### Send Event
724
+ export const MyFunctionalComponent: FunctionComponent<{}> = () => {
725
+ return null;
726
+ }
735
727
 
736
- The `sendEvent()` method allows you to send custom events with arbitrary properties using the EventData class. This is useful for tracking specific user interactions or application state changes.
728
+ Dynatrace.withMonitoring(MyFunctionalComponent, "MyFunctionalComponent");
729
+ ```
730
+ ![rnFunctionalComp](https://dt-cdn.net/images/rnfunctionalcomp-800-d98eacef6d.png)
737
731
 
738
- ```ts
739
- import { Dynatrace, EventData } from '@dynatrace/react-native-plugin';
732
+ The String "MyFunctionalComponent" is optional as the name of the component can be retrieved through [different properties](#how-does-dynatrace-determine-the-user-action-name).
740
733
 
741
- // Send a custom event with properties
742
- Dynatrace.sendEvent(new EventData()
743
- .addEventProperty("event_properties.button_clicked", "login_button")
744
- .addEventProperty("event_properties.user_type", "premium")
745
- .addEventProperty("event_properties.attempt_count", 3)
746
- .withDuration(250)
747
- );
748
- ```
734
+ 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.
749
735
 
750
- **Property Requirements:**
751
- * Only properties prefixed with `event_properties.*` are allowed
752
- * Additionally, the `duration` property is allowed
753
- * Maximum of 50 custom properties per event
754
- * If the limit is exceeded, properties are sorted alphabetically by key and excess properties are dropped deterministically
755
- * String properties are limited to 5000 characters (exceeding characters are truncated)
756
- * Field names must contain only alphabetic characters, numbers, underscores, and dots
757
- * Each dot must be followed by an alphabetic character
758
- * Each underscore must be followed by an alphabetic character or number
759
- * Values must be primitive types (string, number, boolean)
760
- * Cannot contain functions, undefined, Infinity, or NaN as values (they will be replaced with null)
736
+ ### Create custom actions
761
737
 
762
- ### Send Session Property Event
738
+ There are two options to create an action. Either using `enterAutoAction` (the previous `enterAction`) or `enterManualAction`:
763
739
 
764
- Session properties apply to all events within the current session. Use `sendSessionPropertyEvent()` to set properties that should be available across the entire user session.
740
+ **Important:** Action names are limited to 250 characters and will be truncated if they exceed this limit.
741
+
742
+ * `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.
765
743
 
766
744
  ```ts
767
- import { Dynatrace, SessionPropertyEventData } from '@dynatrace/react-native-plugin';
745
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
768
746
 
769
- // Set session-wide properties
770
- Dynatrace.sendSessionPropertyEvent(new SessionPropertyEventData()
771
- .addSessionProperty("session_properties.user_tier", "premium")
772
- .addSessionProperty("session_properties.app_version", "2.1.0")
773
- .addSessionProperty("session_properties.feature_flag_enabled", true)
774
- );
747
+ const myAction = Dynatrace.enterAutoAction("MyButton tapped");
748
+ //Perform the action and whatever else is needed.
749
+ myAction.leaveAction();
775
750
  ```
751
+ ![rnSingle](https://dt-cdn.net/images/rnsingle-800-e7e1b343ed.png)
776
752
 
777
- **Important Notes:**
778
- * Session properties persist throughout the entire session
779
- * If you send the same property multiple times, only one value will be kept (first or last)
780
- * Use session properties for data that applies to the entire user session
781
- * Field naming follows the same rules as events, but with `session_properties.` prefix
782
- * Maximum of 50 custom properties per event
783
- * If the limit is exceeded, properties are sorted alphabetically by key and excess properties are dropped deterministically
753
+ * `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`.
784
754
 
785
- ### Event Modifier
755
+ ```ts
756
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
786
757
 
787
- Event 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. Event modifiers apply to all event types, including custom events, session properties, exceptions, and HTTP events.
758
+ const myAction = Dynatrace.enterManualAction("MyButton tapped");
759
+ //Perform the action and whatever else is needed.
760
+ myAction.leaveAction();
761
+ ```
788
762
 
789
- If multiple event modifiers are added, they are executed in the order they were added.
763
+ 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](#report-values).
790
764
 
791
- Most fields and namespaces can't be modified in any way (added, removed or overridden), while others are open for modification.
765
+ ```ts
766
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
792
767
 
793
- **Open for modification and can be added:**
794
- - `event_properties.*`
795
- - `session_properties.*`
768
+ const myAction = Dynatrace.enterAutoAction("MyButton tapped");
769
+ //Perform the action and whatever else is needed.
770
+ myAction.leaveAction();
771
+ ```
796
772
 
797
- `session_properties.*` are only allowed to be on a session property event.
773
+ ### Create custom sub actions
798
774
 
799
- **Open for modification only:**
800
- - `url.full`
801
- - `exception.stack_trace`
775
+ 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.
802
776
 
803
- #### Example
777
+ **Important:** Action names are limited to 250 characters and will be truncated if they exceed this limit.
804
778
 
805
779
  ```ts
806
- import { Dynatrace, IEventModifier } from '@dynatrace/react-native-plugin';
780
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
807
781
 
808
- // Create an event modifier
809
- const myModifier: IEventModifier = {
810
- modifyEvent(event) {
811
- // Add common properties to all events
812
- event["event_properties.app_build"] = "1.2.3";
813
- event["event_properties.environment"] = "production";
814
-
815
- // Return null to discard the event entirely
816
- if (event["event_properties.ignore"] === true) {
817
- return null;
818
- }
819
-
820
- return event;
821
- }
822
- };
782
+ const myAction = Dynatrace.enterManualAction("MyButton tapped");
783
+ const mySubAction = myAction.enterAction("MyButton Sub Action");
784
+ //Perform the action and whatever else is needed.
785
+ mySubAction.leaveAction();
786
+ myAction.leaveAction();
787
+ ```
788
+ ![subAction](https://dt-cdn.net/images/subaction-800-172dbcca6c.png)
823
789
 
824
- // Add the modifier
825
- Dynatrace.addEventModifier(myModifier);
790
+ ### Cancel actions
826
791
 
827
- // Remove the modifier when no longer needed
828
- Dynatrace.removeEventModifier(myModifier);
829
- ```
792
+ 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.
830
793
 
831
- #### Important Considerations
794
+ ```ts
795
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
832
796
 
833
- - **Execution order**: If multiple event modifiers are added, they are executed in the order they were added
834
- - **Returning null**: Returning `null` discards the event and prevents future modifier functions from being executed
835
- - **Performance**: Event modifiers should be efficient as they are called for every event
836
- - **Field naming**: Custom properties must follow the `event_properties.*` or `session_properties.*` prefix naming convention
837
- - **Reserved fields**: Certain reserved fields and namespaces cannot be modified. Attempts to modify them will be ignored
838
- - **Error handling**: If a modifier throws an exception, it will be logged but won't prevent other modifiers from executing
839
- - **Primitive values**: Event fields can only contain primitive values (String, int, double, bool)
840
- - **Invalid argument**: In case you pass an invalid argument to `addEventModifier`, we return a no-op placeholder modifier.
797
+ const myAction = Dynatrace.enterAutoAction("MyButton tapped");
798
+ // Action will be canceled
799
+ myAction.cancel();
841
800
 
842
- ### Send Exception Event
801
+ // Has no impact as the action is already canceled
802
+ myAction.leaveAction();
803
+ ```
843
804
 
844
- The `sendExceptionEvent()` method provides a structured way to report exceptions with additional context and custom properties using the ExceptionEventData class.
805
+ ### Manual Web Request Tagging
806
+
807
+ 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.
808
+
809
+ **Note:**
810
+ Using this API will force the request to be added to the action that is manually created.
845
811
 
846
812
  ```ts
847
- import { Dynatrace, ExceptionEventData } from '@dynatrace/react-native-plugin';
813
+ import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-plugin';
814
+
815
+ const action = Dynatrace.enterManualAction('API Data Fetch');
816
+ const url = 'https://api.example.com/data';
817
+ const tag = await action.getRequestTag(url);
818
+ const timing = new DynatraceWebRequestTiming(tag, url);
848
819
 
849
820
  try {
850
- // Code that may throw an error
851
- throw new Error('Something went wrong');
821
+ timing.startWebRequestTiming();
822
+ const response = await fetch(url, {
823
+ headers: {
824
+ [timing.getRequestTagHeader()]: tag
825
+ }
826
+ });
827
+ timing.stopWebRequestTiming(response.status, response.statusText);
852
828
  } catch (error) {
853
829
  if (error instanceof Error) {
854
- Dynatrace.sendExceptionEvent(new ExceptionEventData(error)
855
- .addEventProperty('event_properties.custom_key', 'custom_value')
856
- .addEventProperty('event_properties.error_context', 'user_action')
857
- );
830
+ timing.stopWebRequestTiming(-1, error.message);
831
+ } else {
832
+ timing.stopWebRequestTiming(-1, (error as any).toString());
858
833
  }
834
+ } finally {
835
+ action.leaveAction();
859
836
  }
860
837
  ```
838
+ ![rnManualWeb](https://dt-cdn.net/images/rnmanualweb-800-662d009613.png)
861
839
 
862
- **Parameters:**
863
- * `error`: The Error object containing exception information (required)
840
+ There is also the option to report values for request and response size:
864
841
 
865
- ### Send HTTP Request Event
842
+ ```ts
843
+ import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-plugin';
866
844
 
867
- The `sendHttpRequestEvent()` method allows you to manually report HTTP request events with detailed information about the request and response.
845
+ const action = Dynatrace.enterManualAction('API Data Upload');
846
+ const url = 'https://api.example.com/upload';
847
+ const tag = await action.getRequestTag(url);
848
+ const timing = new DynatraceWebRequestTiming(tag, url);
849
+ const requestData = JSON.stringify({ key: 'value' });
868
850
 
869
- ```ts
870
- import { Dynatrace, HttpRequestEventData } from '@dynatrace/react-native-plugin';
851
+ try {
852
+ timing.startWebRequestTiming();
853
+ const response = await fetch(url, {
854
+ method: 'POST',
855
+ headers: {
856
+ [timing.getRequestTagHeader()]: tag,
857
+ 'Content-Type': 'application/json'
858
+ },
859
+ body: requestData
860
+ });
861
+ const responseData = await response.text();
862
+ timing.stopWebRequestTimingWithSize(
863
+ response.status,
864
+ response.statusText,
865
+ requestData.length,
866
+ responseData.length
867
+ );
868
+ } catch (error) {
869
+ if (error instanceof Error) {
870
+ timing.stopWebRequestTiming(-1, error.message);
871
+ } else {
872
+ timing.stopWebRequestTiming(-1, (error as any).toString());
873
+ }
874
+ } finally {
875
+ action.leaveAction();
876
+ }
877
+ ```
878
+ ![rnBytes](https://dt-cdn.net/images/rnbytes-800-139042060c.png)
871
879
 
872
- // Basic HTTP request event
873
- const requestEventData = new HttpRequestEventData('https://api.example.com/users', 'GET');
874
- Dynatrace.sendHttpRequestEvent(requestEventData);
880
+ ### Report values
875
881
 
876
- // HTTP request with additional details
877
- const detailedRequestEventData = new HttpRequestEventData('https://api.example.com/data', 'POST')
878
- .withStatusCode(200)
879
- .addEventProperty('event_properties.headers.content_type', 'application/json');
880
- Dynatrace.sendHttpRequestEvent(detailedRequestEventData);
882
+ For any open action you can report certain values. The following API is available for action:
883
+
884
+ ```ts
885
+ import { Platform } from '@dynatrace/react-native-plugin';
886
+
887
+ interface IDynatraceAction {
888
+ reportDoubleValue(valueName: string, value: number, platform?: Platform): void;
889
+ reportError(errorName: string, errorCode: number, platform?: Platform): void;
890
+ reportEvent(eventName: string, platform?: Platform): void;
891
+ reportIntValue(valueName: string, value: number, platform?: Platform): void;
892
+ reportStringValue(valueName: string, value: string, platform?: Platform): void;
893
+ }
881
894
  ```
882
895
 
883
- **Parameters:**
884
- * `url`: The URL of the HTTP request (required)
885
- * `method`: The HTTP method (e.g., 'GET', 'POST', 'PUT', 'DELETE') (required)
896
+ **Important:** All string parameters (errorName, eventName, valueName, value) are limited to 250 characters and will be truncated if they exceed this limit.
886
897
 
887
- ### View Monitoring
898
+ To report a string value, use the following:
888
899
 
889
- The view monitoring APIs allow you to track different screens or views in your application, providing context for all events happening within those views.
900
+ ```ts
901
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
890
902
 
891
- There are two ways to monitor views:
892
- 1. **Automatic view monitoring** - Enable navigation tracking in your configuration to automatically capture view changes through supported navigation libraries (enabled by default)
893
- 2. **Manual view monitoring** - Use the `startView()` API to manually control when view contexts are created and updated
903
+ const myAction = Dynatrace.enterAutoAction("MyButton tapped");
904
+ myAction.reportStringValue("ValueName", "ImportantValue");
905
+ myAction.leaveAction();
906
+ ```
907
+ ![rnReportString](https://dt-cdn.net/images/rnreportstring-800-739e5ba752.png)
894
908
 
895
- > **Important:** These approaches should not be mixed, as the outcome is unpredictable. Choose either automatic or manual view monitoring for your application.
909
+ 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](#platform-independent-reporting).
896
910
 
897
- #### Automatic Navigation tracking
898
911
 
899
- > **Note:** This feature only works with `@react-navigation` versions 5.x through 7.x.
912
+ ### Report an error stacktrace
900
913
 
901
- The following is an example of how this feature can be configured in your `dynatrace.config.js` file. Note that this feature is enabled by default.
914
+ To manually report an error stacktrace, use the following API call:
902
915
 
903
- ```js
904
- react: {
905
- navigation: {
906
- enabled: true
916
+ ```ts
917
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
918
+
919
+ try {
920
+ throw new Error('Database connection failed');
921
+ } catch (error) {
922
+ if (error instanceof Error) {
923
+ Dynatrace.reportErrorStacktrace(
924
+ 'DatabaseError',
925
+ error.message,
926
+ 'Failed to connect to remote database',
927
+ error.stack || 'No stack trace available'
928
+ );
907
929
  }
908
930
  }
909
931
  ```
932
+ ![rnStack](https://dt-cdn.net/images/rnstack-800-26c6ac7408.png)
910
933
 
911
- When this feature is enabled, the view context will represent the current state of the `@react-navigation` `NavigationContainer`. The state gets represented as a URL-style route. All subsequent events get associated with the view context and thus with the current route.
934
+ **Note:**
935
+ The previous API without *errorValue* is deprecated and will be removed in the future. Please use the new API with errorValue if possible.
912
936
 
913
- For instance, assume the following setup:
914
- ```js
915
- const Drawer = createDrawerNavigator();
937
+ ### Manually report a crash
916
938
 
917
- function App() {
918
- return (
919
- <NavigationContainer>
920
- <Drawer.Navigator initialRouteName="Home">
921
- <Drawer.Screen name="Home" component={HomeScreen} />
922
- <Drawer.Screen name="Feature" component={FeatureScreen}/>
923
- </Drawer.Navigator>
924
- </NavigationContainer>
925
- );
926
- }
939
+ You can manually report a crash via the following API calls:
927
940
 
928
- const Stack = createStackNavigator();
941
+ ```ts
942
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
929
943
 
930
- function FeatureScreen() {
931
- return (
932
- <Stack.Navigator initialRouteName="ScreenOne">
933
- <Stack.Screen name="ScreenOne" component={NestedScreenOne} />
934
- <Stack.Screen name="ScreenTwo" component={NestedScreenTwo} />
935
- </Stack.Navigator>
936
- );
944
+ try {
945
+ throw new Error('Fatal memory allocation failure');
946
+ } catch (error) {
947
+ if (error instanceof Error) {
948
+ Dynatrace.reportCrash(
949
+ 'MemoryError',
950
+ error.message,
951
+ error.stack || 'No stack trace available'
952
+ );
953
+
954
+ // or directly via the full error
955
+ Dynatrace.reportCrashWithException('MemoryError', error);
956
+ }
937
957
  }
938
958
  ```
959
+ ![rnCrash](https://dt-cdn.net/images/rncrash-800-3e7391140f.png)
939
960
 
940
- When navigating to `Home`, the view context will be set to `/Home`. When navigating to `Feature` and being redirected to the nested `ScreenOne`, the view context will be set to `/Home/ScreenOne`. When navigating to `ScreenTwo` within `Feature`, the view context will be set to `/Feature/ScreenTwo`.
961
+ > **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.
941
962
 
942
- #### Start View
963
+ *reportCrashWithException* will use the crashName as name for the crash. It will only report the crash if there is also a stacktrace available.
943
964
 
944
- 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.
965
+ ### Report GPS Location
966
+
967
+ You can report latitude and longitude and specify an optional platform.
945
968
 
946
969
  ```ts
947
970
  import { Dynatrace } from '@dynatrace/react-native-plugin';
948
971
 
949
- // Start monitoring a view
950
- Dynatrace.startView("HomeScreen");
972
+ Dynatrace.setGPSLocation(48.31518732698596, 14.305245274594471);
951
973
  ```
952
974
 
953
- **Important Considerations:**
954
- * Only one view can be active at a time
955
- * Starting a new view will automatically stop the previous one
956
- * View names should be meaningful and consistent across your application
957
- * All events captured after starting a view will include the view context
958
-
959
- **Complete Example:**
975
+ ### Platform independent reporting
960
976
 
977
+ 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:
978
+ * Passing to **iOS** only:
961
979
  ```ts
962
- import { Dynatrace, EventData } from '@dynatrace/react-native-plugin';
980
+ import { Dynatrace, Platform } from '@dynatrace/react-native-plugin';
963
981
 
964
- // User navigates to profile screen
965
- Dynatrace.startView("UserProfile");
982
+ const myAction = Dynatrace.enterAutoAction("MyButton tapped", Platform.Ios);
983
+ //Perform the action and whatever else is needed.
984
+ myAction.leaveAction(Platform.Ios);
985
+ ```
986
+
987
+ * Passing to **Android** only:
988
+ ```ts
989
+ import { Dynatrace, Platform } from '@dynatrace/react-native-plugin';
966
990
 
967
- // Send custom event within the view
968
- Dynatrace.sendEvent(new EventData()
969
- .addEventProperty("event_properties.profile_action", "edit_profile")
970
- .addEventProperty("event_properties.changes_made", true)
971
- );
991
+ const myAction = Dynatrace.enterAutoAction("MyButton tapped", Platform.Android);
992
+ //Perform the action and whatever else is needed.
993
+ myAction.leaveAction(Platform.Android);
994
+ ```
995
+
996
+ * Passing to **both**:
997
+ ```ts
998
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
972
999
 
973
- // User navigates away
974
- Dynatrace.startView("UserProfileDetailed");
1000
+ const myAction = Dynatrace.enterAutoAction("MyButton tapped");
1001
+ //Perform the action and whatever else is needed.
1002
+ myAction.leaveAction();
975
1003
  ```
976
1004
 
977
- ### User Interaction
1005
+ ### Business event capturing
978
1006
 
979
- User Interaction is an automatic instrumentation feature that captures touch and press events in your React Native application without requiring any manual API calls. When enabled, the plugin instruments your UI components at build time and sends structured interaction events to Dynatrace at runtime.
1007
+ With `sendBizEvent`, you can report business events. These events are standalone events, as OneAgent sends them detached from user actions or user sessions.
980
1008
 
981
- The following is an example of how this feature can be configured in your `dynatrace.config.js` file. Note that this feature is enabled by default.
1009
+ For more information on business events, see [dynatrace documentation](https://docs.dynatrace.com/docs/observe/business-observability/explore-business-events).
982
1010
 
983
- ```js
984
- react: {
985
- userInteraction: true
986
- }
1011
+ ```ts
1012
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
1013
+
1014
+ Dynatrace.sendBizEvent("com.easytravel.funnel.booking-finished", {
1015
+ "event.name" : "Confirmed Booking",
1016
+ "screen": "booking-confirmation",
1017
+ "product": "Danube Anna Hotel",
1018
+ "amount": 358.35,
1019
+ "currency": "USD",
1020
+ "reviewScore": 4.8,
1021
+ "arrivalDate": "2022-11-05",
1022
+ "departureDate": "2022-11-15",
1023
+ "journeyDuration": 10,
1024
+ "adultTravelers": 2,
1025
+ "childrenTravelers": 0
1026
+ });
987
1027
  ```
1028
+ ![rnBiz](https://dt-cdn.net/images/rnbiz-1262-f57a0a67f3.png)
988
1029
 
989
- When enabled, UI Interaction can be controlled by two layers:
1030
+ ### Setting beacon headers
990
1031
 
991
- 1. **Build/config layer (`dynatrace.config.js`)**
992
- - `react.userInteraction: true|false` controls whether the UI Interaction instrumentation feature is applied.
1032
+ 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.
993
1033
 
994
- 2. **Runtime remote layer (`RuntimeConfigurationObserver`)**
995
- - Runtime emission checks the remote flag `touch_interaction_enabled`.
996
- - If remote flag is present, it is used as the source of truth.
997
- - If remote flag is temporarily unavailable, the plugin falls back to the last known good remote value.
998
- - If no remote value was received yet, runtime defaults to enabled behavior.
1034
+ **Note:** To clear the previously set headers, call the method without the headers parameter or with a null value for the headers parameter.
999
1035
 
1000
- #### Masking sensitive UI labels
1036
+ ```ts
1037
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
1001
1038
 
1002
- UI Interaction also supports masking sensitive labels before events are sent.
1039
+ const beaconHeaders = new Map<string, string>();
1040
+ beaconHeaders.set('headerName', 'headerValue');
1041
+ Dynatrace.setBeaconHeaders(beaconHeaders);
1042
+ ```
1003
1043
 
1004
- Masking is applied when:
1044
+ ### Exclude Individual JSX Elements
1005
1045
 
1006
- * the touched element or one of its parents is marked with `dtMask`
1007
- * the runtime masking rules classify the detected text as sensitive
1008
- * the runtime masking rules classify the element `testID` as sensitive
1046
+ 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:
1009
1047
 
1010
- When masking is active:
1048
+ ```tsx
1049
+ import React from 'react';
1050
+ import { TouchableHighlight, Text, View } from 'react-native';
1011
1051
 
1012
- * the interaction path and component information are still reported
1013
- * the detected UI label is replaced with the configured replacement string (default: `***`)
1014
- * `ui_element.name_origin` is reported as `masked`
1052
+ const TouchableHighlightScreen = () => {
1053
+ return (
1054
+ <View>
1055
+ <TouchableHighlight onPress={onPress}>
1056
+ <Text>TouchableHighlight that will be monitored</Text>
1057
+ </TouchableHighlight>
1058
+ <TouchableHighlight onPress={onPress} dtActionIgnore="true">
1059
+ <Text>TouchableHighlight that will be ignored</Text>
1060
+ </TouchableHighlight>
1061
+ </View>
1062
+ );
1063
+ };
1015
1064
 
1016
- Example using `dtMask`:
1065
+ const onPress = () => {
1066
+ console.log("TouchableHighlight Pressed!");
1067
+ };
1017
1068
 
1018
- ```tsx
1019
- <View dtMask>
1020
- <Pressable onPress={onPress}>
1021
- <Text>john.doe@example.com</Text>
1022
- </Pressable>
1023
- </View>
1069
+ export default TouchableHighlightScreen;
1024
1070
  ```
1025
1071
 
1026
- This allows you to preserve interaction analytics while avoiding exposure of sensitive text in the emitted UI Interaction event.
1027
-
1072
+ 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.
1028
1073
 
1029
- #### Produced data
1074
+ >*Attention:* If you are using Typescript and want to set this property with type-safety, look [here](#typescript-setup-for-dtactionignore-and-dtactionname).
1030
1075
 
1031
- Each captured interaction produces an event describing what the user touched and where. The event includes:
1076
+ ## Extended topics
1032
1077
 
1033
- - **Detected name** — the resolved label of the touched element, derived from its visible text, accessibility label, component name, or test ID.
1034
- - **Component** — the type of the UI component that was touched (e.g. `Pressable`).
1035
- - **Component Path** — a stable path through the component tree that uniquely identifies the element (e.g. `App/View[1]/Pressable[1]`).
1036
- - **Interaction type** — how the user interacted (e.g. `touch`).
1037
- - **Position** — the screen coordinates where the touch occurred.
1078
+ ### Identify a user
1038
1079
 
1039
- In some cases, a **responder** is also included. The responder is the component that ultimately handled the user's touch — for example, a `Pressable` that received the press event. It carries the same name, component type, and path information as the touched element, and can differ when a touch is visually on a child element but handled by a parent.
1080
+ You can identify a user and tag the current session with a name by making the following call:
1040
1081
 
1041
- If masking is active for an interaction, the event still contains the same structural information, but the detected name is replaced and the name origin changes to `masked`.
1082
+ **Important:** The user identifier is limited to 250 characters and will be truncated if it exceeds this limit.
1042
1083
 
1043
- #### Example event
1084
+ ```ts
1085
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
1044
1086
 
1045
- ```json
1046
- {
1047
- "characteristics.has_user_interaction": true,
1048
- "ui_element.detected_name": "LoginButton",
1049
- "ui_element.components": ["Pressable"],
1050
- "ui_element.id": "App/View/Pressable",
1051
- "ui_element.name_origin": "component",
1052
- "interaction.type": "touch",
1053
- "positions": [{ "x": 120, "y": 460 }],
1054
- "ui_element.responder.detected_name": "Pressable",
1055
- "ui_element.responder.components": ["Pressable"],
1056
- "ui_element.responder.id": "App/View[/Pressable",
1057
- "ui_element.responder.name_origin": "component"
1058
- }
1087
+ Dynatrace.identifyUser("User XY");
1059
1088
  ```
1089
+ ![rnTag](https://dt-cdn.net/images/rntag-800-77fe848023.png)
1060
1090
 
1061
- #### Custom Names for Components
1062
-
1063
- You can assign custom names to your components. A custom name affects both the **Component** and the **Component Path** described above. There are two ways to do this, depending on how the component is used.
1091
+ ### End the current user session
1064
1092
 
1065
- ##### 1. As a JSX prop (`dtActionName`)
1093
+ To end the current user session, use the following API call:
1066
1094
 
1067
- Use this when you render the component as JSX. Pass `dtActionName` as a prop, and it overrides the auto-detected name for that specific usage:
1095
+ ```ts
1096
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
1068
1097
 
1069
- ```tsx
1070
- <TouchableOpacity dtActionName="Checkout Button" onPress={onCheckout}>
1071
- <Text dtActionName="Checkout Text">Buy now</Text>
1072
- </TouchableOpacity>
1098
+ Dynatrace.endSession();
1073
1099
  ```
1074
1100
 
1075
- Touching it produces:
1101
+ **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](#identify-a-user) API.
1076
1102
 
1077
- ```json
1078
- "ui_element.components": ["Checkout Text"],
1079
- "ui_element.id": ".../Checkout Button/Checkout Text"
1080
- ```
1103
+ ### User Privacy Options
1081
1104
 
1082
- ##### 2. As a static property (`Component.dtActionName`)
1105
+ 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:
1083
1106
 
1084
- Use this when the component is **not** rendered as JSX, so the prop approach above is not available — for example, a screen component you define once and hand to a navigator by reference. Set `dtActionName` directly on the component. This affects **every** place the component is used at once:
1107
+ ```ts
1108
+ export enum DataCollectionLevel {
1109
+ Off, Performance, UserBehavior
1110
+ }
1111
+ ```
1085
1112
 
1086
- ```tsx
1087
- import { NavigationContainer } from '@react-navigation/native';
1088
- import { createDrawerNavigator } from '@react-navigation/drawer';
1113
+ 1. Off: Native Agent doesn't capture any monitoring data.
1114
+ 2. Performance: Native Agent captures only anonymous performance data. Monitoring data that can be used to identify individual users, such as user tags and custom values, aren't captured.
1115
+ 3. UserBehavior: Native Agent captures both performance and user data. In this mode, Native Agent recognizes and reports users who re-visit in future sessions.
1089
1116
 
1090
- const Drawer = createDrawerNavigator();
1117
+ 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`](#user-opt-in-mode) and set the User Privacy Options.
1091
1118
 
1092
- function ProfileScreen() {
1093
- return (/* ... */);
1094
- }
1119
+ The API to get and set the current privacy level looks like this:
1095
1120
 
1096
- // Applies to all usages of ProfileScreen below
1097
- ProfileScreen.dtActionName = 'User Profile';
1121
+ ```ts
1122
+ import { Platform, UserPrivacyOptions } from '@dynatrace/react-native-plugin';
1098
1123
 
1099
- function App() {
1100
- return (
1101
- <NavigationContainer>
1102
- <Drawer.Navigator>
1103
- {/* Both screens reference the same component,
1104
- so both pick up the 'User Profile' name */}
1105
- <Drawer.Screen name="Me" component={ProfileScreen} />
1106
- <Drawer.Screen name="Account" component={ProfileScreen} />
1107
- </Drawer.Navigator>
1108
- </NavigationContainer>
1109
- );
1124
+ interface IDynatrace {
1125
+ getUserPrivacyOptions(platform?: Platform): Promise<UserPrivacyOptions>;
1126
+ applyUserPrivacyOptions(userPrivacyOptions: UserPrivacyOptions, platform?: Platform): void;
1110
1127
  }
1111
1128
  ```
1112
1129
 
1113
- Touches inside one of the 2 screens now produce:
1114
-
1115
- ```json
1116
- "ui_element.id": ".../User Profile/..."
1117
- ```
1118
-
1119
- > **Note:** The static property applies to *all* uses of the component. If you need a different name per usage, render the component as JSX and use the `dtActionName` prop (option 1) instead.
1120
- >
1121
- > **Note:** The static property has no effect when a component is rendered as JSX. In that case the name is taken from either the `dtActionName` prop passed to it (option 1) or the name of the JSX component.
1122
-
1123
- ### React Native Symbolication
1130
+ To check the current privacy options that are set:
1124
1131
 
1125
- Dynatrace can automatically symbolicate JavaScript stack traces captured by the plugin using sourcemaps. This allows you to view human-readable file names, line numbers, and column information in your crash reports.
1132
+ ```ts
1133
+ import { Dynatrace } from '@dynatrace/react-native-plugin';
1126
1134
 
1127
- #### Generating Sourcemaps
1135
+ const privacyOptions = await Dynatrace.getUserPrivacyOptions();
1136
+ ```
1128
1137
 
1129
- Sourcemaps are generated during release builds and map bytecode offsets (Hermes) and locations in the minified JavaScript bundle (JavaScriptCore) back to your original source code. We support sourcemaps for both Hermes and JavaScriptCore. For detailed instructions on generating sourcemaps, see the [React Native debugging release builds guide](https://reactnative.dev/docs/debugging-release-builds).
1138
+ If you want to create a new `UserPrivacyOptions` object and pass it to Dynatrace:
1130
1139
 
1131
- To generate a sourcemap:
1140
+ ```ts
1141
+ import { Dynatrace, DataCollectionLevel, UserPrivacyOptions } from '@dynatrace/react-native-plugin';
1132
1142
 
1133
- **Android:**
1134
- * Run `npx react-native run-android --mode release` in your project root, or
1135
- * Run `gradlew assembleRelease` in the `/android` directory
1143
+ const privacyConfig = new UserPrivacyOptions(DataCollectionLevel.UserBehavior, true);
1136
1144
 
1137
- **iOS:**
1138
- * First, enable sourcemaps according to the [React Native debugging release builds guide](https://reactnative.dev/docs/debugging-release-builds)
1139
- * Then run `npx react-native run-ios --mode Release`, or
1140
- * Build for release in Xcode
1145
+ // Getter and setter available for UserPrivacyOptions
1146
+ privacyConfig.crashReportingOptedIn = false;
1147
+ privacyConfig.dataCollectionLevel = DataCollectionLevel.Performance;
1141
1148
 
1142
- #### Uploading Sourcemaps
1149
+ const level = privacyConfig.dataCollectionLevel;
1150
+ const crashReporting = privacyConfig.crashReportingOptedIn;
1143
1151
 
1144
- Once generated and patched, upload your sourcemaps to Dynatrace. For detailed instructions, see the [symbol file management documentation](https://docs.dynatrace.com/docs/observe/digital-experience/mobile-applications/analyze-and-use/upload-and-manage-symbol-files).
1152
+ Dynatrace.applyUserPrivacyOptions(privacyConfig);
1153
+ ```
1145
1154
 
1146
1155
  ## NPX Commands
1147
1156
 
@@ -1149,7 +1158,6 @@ The following npx commands are available for the plugin:
1149
1158
 
1150
1159
  * npx instrumentDynatrace - Is triggering the configuration process and will insert the configuration into the Android and iOS application. This is mandatory and should usually happen automatically when doing `react-native run-android` or `react-native run-ios` command.
1151
1160
  * npx configDynatrace - Is checking the current configuration and is creating a default configuration if there is none.
1152
- * npx lineOffsetDynatrace - ...
1153
1161
 
1154
1162
  ### npx instrumentDynatrace
1155
1163
 
@@ -1520,18 +1528,6 @@ The changes our auto-instrumentation is making now get dumped into the `node_mod
1520
1528
 
1521
1529
  > **Note:** This feature increases the time it takes to build the Javascript bundle. Only use it for debugging purposes. Deactivate it otherwise, especially when fast build times are important.
1522
1530
 
1523
- #### Using our legacy jscodeshift auto-instrumentation
1524
-
1525
- We recently moved our auto-instrumentation to a babel plugin. In case you need to, you can still switch to the old jscodeshift auto-instrumentation with this flag:
1526
-
1527
- ```js
1528
- react: {
1529
- useLegacyJscodeshift: true
1530
- }
1531
- ```
1532
-
1533
- > **Note:** When we moved our auto-instrumentation to a babel plugin, we removed documentation that was only relevant for the jscodeshift auto-instrumentation. Most notably, we removed documentation concerning registering a custom metro transformer and patching sourcemaps. If you use the `useLegacyJscodeshift` flag, please refer to the [legacy documentation (v2.333.1)](https://www.npmjs.com/package/@dynatrace/react-native-plugin/v/2.333.1) for details on custom metro transformers and sourcemap patching.
1534
-
1535
1531
  ### Android block
1536
1532
 
1537
1533
  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:
@@ -1701,7 +1697,7 @@ ios: {
1701
1697
  * class name: If the display name is not available, the class name is used by taking the property name from the constructor
1702
1698
  * Touchables, Buttons, Pressable
1703
1699
  * dtActionName: Use a custom property called dtActionName
1704
- * If [actionNamePrivacy](#plugin-startup) is activated anything below will not be detected
1700
+ * If [actionNamePrivacy](#manual-oneagent-startup) is activated anything below will not be detected
1705
1701
  * title property
1706
1702
  * accessibilityLabel property
1707
1703
  * If none of the above exist, we recursively traverse `children` to find a name. We consider text, the source property of any `ReactNative.Image` and the name property of any functional component called `Icon`.
@@ -1751,7 +1747,7 @@ import { Text } from 'react-native';
1751
1747
  </TouchableHighlight>
1752
1748
  ```
1753
1749
 
1754
- *Note:* [actionNamePrivacy](#plugin-startup) has no impact on using dtActionName. dtActionName will always be used.
1750
+ *Note:* [actionNamePrivacy](#manual-oneagent-startup) has no impact on using dtActionName. dtActionName will always be used.
1755
1751
 
1756
1752
  >*Attention:* If you are using Typescript and want to set this property with type-safety, look [here](#typescript-setup-for-dtactionignore-and-dtactionname).
1757
1753
 
@@ -1765,7 +1761,7 @@ In general, Dynatrace always closes the session when a crash occurs. Usually a c
1765
1761
  * Fatal error: If the error is considered as fatal by the React Native crash handler, it will be treated as crash.
1766
1762
  * Native crashes: If a crash appears solely on the native side and is not noticed by the internal React Native crash handler, it will be reported directly by the Android or iOS agent.
1767
1763
  * Exception: Some JavaScript crashes will result in Native crashes. Therefore, they are filtered on the native side as normally the crash would be reported twice. On the JavaScript side, these crashes are already reported by us before they hit the native side resulting in no lost information.
1768
- Additionally, you can use our crash and error reporting APIs which are available with [manual instrumentation](#manual-instrumentation).
1764
+ Additionally, you can use our crash and error reporting APIs which are available with [RUM Classic](#rum-classic).
1769
1765
 
1770
1766
 
1771
1767
  ## React Automatic Runtime
@@ -2088,6 +2084,27 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2088
2084
  <br/><br/>
2089
2085
  ## Changelog
2090
2086
 
2087
+ In Progress
2088
+
2089
+ 2.347.1
2090
+ * Updated Android (8.347.1.1003) & iOS Agent (8.347.1.1004)
2091
+ * Renamed `registerEventTrigger` to `registerNavigationEventTrigger` for clarity
2092
+ * Fixed re-configure failure to properly clear the table reload trigger
2093
+ * Updated `xmldom` dependency in Session Replay to a non-vulnerable version (DEM-32539)
2094
+
2095
+
2096
+ 2.345.1
2097
+ * Updated Android (8.345.1.1003) & iOS Agent (8.345.1.1003)
2098
+ * Renamed `monitorNavigation` to `useNavigationMonitor`; React Navigation screen changes are now detected automatically, stamped with `start_time` and `duration`, and trigger Session Replay capture after the incoming screen settles
2099
+ * Added React Navigation support: settle detection on both Android and iOS bridges, UI-change capture toggling restored
2100
+ * Removed the bridge-side settle helper — the native agent now owns coalescing on both platforms
2101
+ * Added a runtime deprecation warning system
2102
+ * Removed the option to use the legacy jscodeshift auto-instrumentation by removing the `useLegacyJscodeshift` flag from `dynatrace.config.js`
2103
+ * Removed leading slash from reported view names
2104
+ * Discard user interaction actions when 3rd-gen instrumentation is disabled, even without an `onPress` callback
2105
+ * Android: compatibility fixes for AGP 9 and Kotlin 2.2 (React Native 0.87)
2106
+ * iOS: app-start measurement fixes for the new architecture
2107
+
2091
2108
  2.343.1
2092
2109
  * Updated Android (8.343.1.1038) & iOS Agent (8.343.1.1007)
2093
2110
  * Added User Actions feature
@@ -2101,6 +2118,7 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2101
2118
  * Added `DYNATRACE_CONFIG` environment variable as an alternative way to specify the config file path for the Metro/Babel transformer.
2102
2119
  * Added `npx instrumentDynatrace --reset` flag to clear a previously-persisted custom config path and revert the Metro/Babel transformer to the default `dynatrace.config.js` lookup. Useful after switching between build flavors that each use a different config file.
2103
2120
  * Fixed incorrect `start_time` on Android app start events when `3rd_gen_enabled` is false. The `EventPipeline` was suppressing the `forwardAppStartEvent` timing-correction call along with all other 3rd-gen events, causing the native Dynatrace SDK to report its own stale process-creation timestamp instead of the actual JS bundle load time.
2121
+ * CP now always forwards User Interaction Actions (UIA) to the native agent unconditionally, regardless of the `touch_interaction_enabled` server configuration flag. The native agent is responsible for deciding whether to record or discard each UIA. This applies to both the Babel-instrumented (`AnalyticsRoot`/`TouchCapture`) and the legacy JSX-wrapped Touchables UIA paths.
2104
2122
 
2105
2123
  2.341.1
2106
2124
  * Updated Android (8.341.1.1004) & iOS Agent (8.341.1.1010)
@@ -2128,7 +2146,7 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2128
2146
  * Updated Android (8.337.2.1010) & iOS Agent (8.337.1.1003)
2129
2147
  * Fixed gradle path derivation for custom `--gradle` arguments: the plugin now correctly probes the filesystem to auto-detect `app/build.gradle(.kts)` with proper Kotlin DSL support, and validates that only `build.gradle` or `build.gradle.kts` files are accepted (not `settings.gradle`).
2130
2148
  * Enables [pnpm monorepo instrumentation](#pnpm-monorexpo-setup) by allowing explicit `config=`, `gradle=`, and `plist=` arguments in root `package.json` scripts, supporting shared native project layouts where `android/` and `ios/` are not co-located with each app.
2131
- * Added [actionNamePreference](#plugin-startup) and [actionNameAlgorithm](#plugin-startup) configuration flags.
2149
+ * Added [actionNamePreference](#manual-oneagent-startup) and [actionNameAlgorithm](#manual-oneagent-startup) configuration flags.
2132
2150
 
2133
2151
  2.335.1
2134
2152
  * Updated Android (8.335.1.1001) & iOS Agent (8.335.1.1009)
@@ -2152,12 +2170,12 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2152
2170
 
2153
2171
  2.329.1
2154
2172
  * Updated Android (8.329.1.1014) & iOS Agent (8.329.1.1017)
2155
- * [New RUM experience](#new-rum-experience) Removed Dynatrace.stopView() API
2156
- * [New RUM experience](#new-rum-experience) Enforcing length limitation of 5000 characters for user input values
2157
- * [New RUM experience](#new-rum-experience) React Native Deobfuscation service via sourcemaps
2173
+ * [New RUM experience](#real-user-monitoring-rum) Removed Dynatrace.stopView() API
2174
+ * [New RUM experience](#real-user-monitoring-rum) Enforcing length limitation of 5000 characters for user input values
2175
+ * [New RUM experience](#real-user-monitoring-rum) React Native Deobfuscation service via sourcemaps
2158
2176
  * Adding [`npx lineOffsetDynatrace`](#npx-lineoffsetdynatrace) command
2159
- * [New RUM experience](#new-rum-experience) Added automated view tracking via [navigation](#automatic-navigation-tracking)
2160
- * [New RUM experience](#new-rum-experience) Event and session properties are now sorted alphabetically when the limit of 50 is exceeded, ensuring deterministic property dropping
2177
+ * [New RUM experience](#real-user-monitoring-rum) Added automated view tracking via [navigation](#automatic-navigation-tracking)
2178
+ * [New RUM experience](#real-user-monitoring-rum) Event and session properties are now sorted alphabetically when the limit of 50 is exceeded, ensuring deterministic property dropping
2161
2179
 
2162
2180
  2.327.2
2163
2181
  * Fixed iOS startup time calculation issues for React Native 0.72 and lower
@@ -2166,7 +2184,7 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2166
2184
 
2167
2185
  2.327.1
2168
2186
  * Added [Compose Compatibility Note](#compose-compatibility-note)
2169
- * Added [New RUM experience preview](#new-rum-experience) documentation
2187
+ * Added [New RUM experience preview](#real-user-monitoring-rum) documentation
2170
2188
  * Fixed iOS crash reporting by delaying the crash by 200ms on iOS to give the Agent enough time to report it
2171
2189
  * Updated Android (8.327.2.1004) & iOS Agent (8.327.1.1020)
2172
2190
 
@@ -2175,8 +2193,8 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2175
2193
 
2176
2194
  2.325.1
2177
2195
  * Updated Android (8.325.1.1007) & iOS Agent (8.325.1.1012)
2178
- * [New RUM experience preview](#new-rum-experience) ReactNative version now added to RUM on Grail event base data
2179
- * [New RUM experience preview](#new-rum-experience) Added API documentation for RUM on Grail API
2196
+ * [New RUM experience preview](#real-user-monitoring-rum) ReactNative version now added to RUM on Grail event base data
2197
+ * [New RUM experience preview](#real-user-monitoring-rum) Added API documentation for RUM on Grail API
2180
2198
 
2181
2199
  2.323.2
2182
2200
  * Fixed error "Execution failed for task ':app:mergeReleaseAssets'. A problem occured starting process 'command 'npx''" when building for release on Windows.
@@ -2362,7 +2380,7 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2362
2380
  2.247.1
2363
2381
  * Updated Android Agent (8.247.1.1003) & iOS Agent (8.247.1.1007)
2364
2382
  * Minimum supported Android SDK version raised to 21
2365
- * Added [actionNamePrivacy](#plugin-startup) configuration flag
2383
+ * Added [actionNamePrivacy](#manual-oneagent-startup) configuration flag
2366
2384
  * Removed `instrumentDynatrace` from package.json
2367
2385
  * Adding [`npx instrumentDynatrace`](#npx-instrumentdynatrace) and [`npx configDynatrace`](#npx-configdynatrace) command
2368
2386