From dynatrace
Integrates Dynatrace React Native plugin into React Native and Expo projects — dependency setup, dynatrace.config.js, Babel registration, instrumentation, and verification.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dynatrace:dt-obs-react-nativeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- Node.js 16.0+ and npm available on `PATH`
PATHpackage.json at the project rootandroid/ and ios/ platform folders present (Expo managed workflow requires npx expo prebuild first)applicationId and beaconUrl, or to download dynatrace.config.js)Work through the steps below in order, interacting with the user at each decision point. Read actual project files before suggesting changes — do not assume the current state.
dynatrace.config.jsBefore asking the user anything, check whether dynatrace.config.js exists at the project root.
applicationId and beaconUrl, and confirm they match the target environment. If correct, run the userOptIn check below and skip to Step 3 (config is already present — Step 2 is not needed).userOptIn check:
Inspect the file for userOptIn (Android block) and DTXUserOptIn (iOS block).
true, flag Step 9. If false, skip Step 9.true.dynatrace.config.js (only if Step 1 found no file)Ask the user which approach they prefer:
Option A — Download from console (recommended):
dynatrace.config.js and place it at the project root (same level as package.json)Once the file is in place, apply the userOptIn check from Step 1 and flag Step 9 if needed.
Option B — Provide credentials manually:
Read references/config-js.md for the full template and conditional blocks. Collect all required values from the user before creating any files, then apply the userOptIn check and flag Step 9 if needed.
Read package.json first.
npm install @dynatrace/react-native-plugin
dependencies: No change needed.devDependencies: Remove it and run npm install @dynatrace/react-native-plugin. The plugin is required at runtime including in release builds.Note: npm install alphabetically sorts the dependencies object in package.json. Existing entries may appear reordered after this step — this is expected npm behavior, not an error.
If on macOS and targeting iOS, run:
cd ios && pod install && cd ..
Confirm success before continuing. CocoaPods must be installed (gem install cocoapods if missing).
babel.config.jsRead babel.config.js. Append BabelPluginDynatrace to the plugins array, just before react-native-reanimated/plugin if that plugin is present (reanimated must always be last):
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: [
// ... existing plugins ...
'@dynatrace/react-native-plugin/instrumentation/BabelPluginDynatrace',
// react-native-reanimated/plugin goes here if present — must stay last
],
};
'@dynatrace/react-native-plugin/instrumentation/BabelPluginDynatrace': skip this step.useLegacyJscodeshift: true is set in dynatrace.config.js: the Babel plugin is already applied internally — skip this step.metro.config.js with babelTransformerPath: '@dynatrace/react-native-plugin/lib/dynatrace-transformer': that is the legacy Metro transformer approach — auto-instrumentation is already handled; skip this step and Step 6.Common mistakes to flag and correct:
presets instead of pluginsBabelPluginDynatrace after react-native-reanimated/plugin — reanimated must always be the absolute last pluginbabel.config.jsRead babel.config.js and determine which preset the project uses — this controls how the JSX runtime is registered.
babel-preset-expo)If babel-preset-expo appears in presets, set jsxImportSource on the preset itself. Do not add a separate @babel/plugin-transform-react-jsx plugin — Expo's preset already owns the JSX transform, and stacking a second JSX plugin over it breaks the instrumentation.
module.exports = function (api) {
api.cache(true);
return {
presets: [
['babel-preset-expo', {
jsxRuntime: 'automatic',
jsxImportSource: '@dynatrace/react-native-plugin',
}],
],
plugins: [
'@dynatrace/react-native-plugin/instrumentation/BabelPluginDynatrace',
'react-native-reanimated/plugin', // stays last
],
};
};
babel-preset-expo already has jsxImportSource: '@dynatrace/react-native-plugin': no change needed.jsxImportSource is already set: replace it with '@dynatrace/react-native-plugin'.@babel/plugin-transform-react-jsx plugin entry — it must not coexist with the preset-level jsxImportSource on babel-preset-expo.@react-native/babel-preset or metro-react-native-babel-preset)For metro 0.72.0+ (React Native 0.71+), add @babel/plugin-transform-react-jsx with the Dynatrace importSource before BabelPluginDynatrace in the plugins array:
module.exports = {
presets: [
['module:@react-native/babel-preset', { unstable_transformProfile: 'hermes-stable' }],
],
plugins: [
['@babel/plugin-transform-react-jsx', {
runtime: 'automatic',
importSource: '@dynatrace/react-native-plugin',
}],
'@dynatrace/react-native-plugin/instrumentation/BabelPluginDynatrace',
'react-native-reanimated/plugin', // stays last
],
};
The required plugin order is:
@babel/plugin-transform-react-jsx (JSX runtime — first)BabelPluginDynatrace (auto-instrumentation — before reanimated)react-native-reanimated/plugin (must be absolutely last)@babel/plugin-transform-react-jsx with importSource: '@dynatrace/react-native-plugin': no change needed.importSource is set: replace it with '@dynatrace/react-native-plugin'.After any Babel change, reset Metro cache on next build:
npx react-native start --reset-cache
npx instrumentDynatracenpx instrumentDynatrace
This reads dynatrace.config.js and automatically configures Android build.gradle and iOS Info.plist. Must be re-run whenever dynatrace.config.js changes.
Common mistakes to flag and correct:
dynatrace.config.jsreact-native instrument-dynatrace — same effect but deprecated for RN 0.70+build.gradle or Info.plist — not needed, the script handles itIf android/ and ios/ folders exist but automatic plist discovery fails, pass explicit paths:
npx instrumentDynatrace plist=ios/YourApp/Info.plist
Expo only: If android/ and ios/ folders do not yet exist, run npx expo prebuild first, then re-run npx instrumentDynatrace.
autoStart: false)Skip this step if autoStart is true or absent in dynatrace.config.js — the SDK starts automatically.
Check dynatrace.config.js for autoStart: false in the react block. If present, the SDK will not start on its own and no data will be collected until Dynatrace.start() is called explicitly.
Add the startup call at the top level of the app entry file (for example App.tsx or index.js). Any logic that depends on the SDK being ready goes after the await:
import { Dynatrace, ConfigurationBuilder } from '@dynatrace/react-native-plugin';
await Dynatrace.start(
new ConfigurationBuilder('<BEACON_URL>', '<APPLICATION_ID>').buildConfiguration()
);
// SDK is initialized — place any SDK-dependent logic here
Replace <BEACON_URL> and <APPLICATION_ID> with the exact same values from dynatrace.config.js — they must match or the SDK will report to the wrong environment.
Important: Even with autoStart: false, the beaconUrl and applicationId must still be present in dynatrace.config.js (used by npx instrumentDynatrace to configure the native files). The values passed to ConfigurationBuilder at runtime take effect — values in the config file are ignored when manual startup is used.
Tradeoff: Manual startup causes the SDK to miss the native application start event and any interactions that happen before start() is called. Use autoStart: true (the default) unless runtime credential injection is a hard requirement.
Check dynatrace.config.js for the react.navigation block and check package.json for @react-navigation/native.
If @react-navigation/native is present and navigation.enabled is not set to true, add it:
module.exports = {
react: {
navigation: {
enabled: true, // requires @react-navigation/native v5–v7
},
// ...
},
// ...
};
Then re-run npx instrumentDynatrace.
What this does: When enabled, the plugin hooks into React Navigation's NavigationContainer and detects route changes automatically. Each navigation event is reported to Dynatrace as a view change, with the current route represented as a URL-style path (e.g., /Home, /Home/Details). This populates the screen timeline in Dynatrace user sessions and associates all events with the currently active screen. This setting is enabled by default in the plugin's own config template.
If @react-navigation/native is not present: inform the user that automatic view tracking requires @react-navigation/native. They can use Dynatrace.startView("ScreenName") for manual view tracking instead.
userOptIn: true)Skip this step if userOptIn was not set to true during Steps 1 or 2.
Read references/user-opt-in.md for the full guidance on DataCollectionLevel, crashReportingOptedIn, and placement options. Ask the user the questions defined there, then apply the call to the relevant file.
Confirm to the user what is active:
Enabled by default (when userOptIn is false or absent):
When
userOptIn: true, all data collection — including crash reporting — is gated on theapplyUserPrivacyOptions(...)call.
Configured during this setup:
Read references/verification.md and show the user the verification checklist. If no data appears after 5 minutes, work through the troubleshooting steps in that file.
references/config-js.md — Full dynatrace.config.js template with Grail and userOptIn conditional blocksreferences/user-opt-in.md — applyUserPrivacyOptions guidance, DataCollectionLevel options, placement optionsreferences/verification.md — Post-setup verification checklist and troubleshootingnpx claudepluginhub dynatrace/dynatrace-for-ai --plugin dynatraceAutomates Dynatrace iOS SDK setup via SPM: adds dependency, creates plist, imports, privacy opt-in, and builds. Useful for integrating Dynatrace monitoring in iOS apps.
Guides bitdrift Capture SDK integration for iOS, Android, and React Native: new installs and extending with screen tracking, network monitoring, logs, fields, and spans.
Optimizes React Native app performance: FPS, TTI, bundle size, memory leaks, re-renders, and animations. Includes Hermes, FlashList, native modules, and jank debugging.