Included Instrumentation
@sentry/react-native
provides a ReactNativeTracing
integration to add instrumentation for monitoring the performance of React Native applications.
What Instrumentation Provides
The ReactNativeTracing
integration creates a child span for every XMLHttpRequest
or fetch
request on the Javascript layer that occurs while those transactions are open. Learn more about traces, transactions, and spans.
Configuration Options
You can pass many different options to the ReactNativeTracing
integration (as an object of the form {optionName: value}
), but it comes with sensible defaults out of the box. For all possible options, see ReactNativeTracingOptions.
beforeNavigate
You can use beforeNavigate
to modify the transaction from routing instrumentation before the transaction is created. If you prefer not sending the transaction, set sampled = false
.
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
new Sentry.ReactNativeTracing({
routingInstrumentation,
beforeNavigate: context => {
// Decide to not send a transaction by setting sampled = false
if (context.data.route.name === "Do Not Send") {
context.sampled = false;
}
// Modify the transaction context
context.name = context.name.toUpperCase();
context.tags = {
...context.tags,
customTag: "value",
};
return context;
},
}),
],
});
If you use our routing instrumentation for React Navigation, the route data is set on the transaction context passed to beforeNavigate
. This has the type:
type ReactNavigationTransactionContext = {
// ...
data: {
route: {
name: string;
key: string;
params: {
[key: string]: any;
};
/** Will be true if this is not the first time this screen with this key has been seen before. */
hasBeenSeen: boolean;
};
previousRoute: {
name: string;
key: string;
params: {
[key: string]: any;
};
} | null;
};
};
If you use Typescript, you can type your beforeNavigate
function with Sentry.ReactNavigationTransactionContext
.
tracingOrigins
The default value of tracingOrigins
is ['localhost', /^\//]
. The React Native SDK will attach the sentry-trace
header to all outgoing XHR/fetch requests whose destination contains a string in the list or matches a regex in the list. If your frontend is making requests to a different domain, you will need to add the domain there to propagate the sentry-trace
header to the backend services, which is required to link transactions together as part of a single trace. The tracingOrigins
option matches against the entire request URL, not just the domain. Using stricter regex to match certain parts of the URL ensures that requests do not unnecessarily have the sentry-trace
header attached.
For example:
- A frontend application is served from
example.com
- A backend service is served from
api.example.com
- The frontend application makes API calls to the backend
- Therefore, the option needs to be configured like this:
new Sentry.ReactNativeTracing({tracingOrigins: ['api.example.com']})
- Now outgoing XHR/fetch requests to
api.example.com
will get thesentry-trace
header attached
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
new Sentry.ReactNativeTracing({
tracingOrigins: ["localhost", "my-site-url.com"],
}),
],
// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate: 1.0,
});
You will need to configure your web server CORS to allow the sentry-trace
header. The configuration might look like "Access-Control-Allow-Headers: sentry-trace"
, but the configuration depends on your setup. If you do not allow the sentry-trace
header, the request might be blocked.
shouldCreateSpanForRequest
This function can be used to filter out unwanted spans, such as XHR's running health checks or something similar. By default shouldCreateSpanForRequest
already filters out everything except what was defined in tracingOrigins
.
import * as Sentry from "@sentry/browser";
import { Integrations } from "@sentry/tracing";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
new Integrations.BrowserTracing({
shouldCreateSpanForRequest: url => {
// Do not create spans for outgoing requests to a `/health/` endpoint
return !url.match(/\/health\/?$/);
},
}),
],
// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate: 1.0,
});
Enable Routing Instrumentation
We currently provide two routing instrumentations out of the box to instrument route changes for React Navigation V5 and V4. In the future, we will add support for other libraries such as react-native-navigation. Otherwise, if you have a custom routing instrumentation, or use a routing library we don't yet support, you can use the bare bones routing instrumentation or create your own by extending it.
React Navigation V5
Note that this routing instrumentation will create a transaction on every route change including goBack
navigations.
import * as Sentry from "@sentry/react-native";
// Construct a new instrumentation instance. This is needed to communicate between the integration and React
const routingInstrumentation = new Sentry.ReactNavigationV5Instrumentation();
Sentry.init({
...
integrations: [
new Sentry.ReactNativeTracing({
// Pass instrumentation to be used as `routingInstrumentation`
routingInstrumentation,
// ...
}),
],
})
// Functional Component Example
const App = () => {
// Create a ref for the navigation container
const navigation = React.createRef();
// Register the navigation container with the instrumentation
React.useEffect(() => {
routingInstrumentation.registerNavigationContainer(navigation);
}, []);
return (
// Connect the ref to the navigation container
<NavigationContainer ref={navigation}>
...
</NavigationContainer>
);
};
// Class Component Example
class App extends React.Component {
// Create a ref for the navigation container
navigation = React.createRef();
componentDidMount() {
// Register the navigation container with the instrumentation
routingInstrumentation.registerNavigationContainer(navigation);
}
render() {
return (
// Connect the ref to the navigation container
<NavigationContainer ref={this.navigation}>
...
</NavigationContainer>
)
}
}
React Navigation V4
Note that this routing instrumentation will create a transaction on every route change including goBack
navigations.
// Construct a new instrumentation instance. This is needed to communicate between the integration and React
const routingInstrumentation = new Sentry.ReactNavigationV4Instrumentation();
Sentry.init({
...
integrations: [
new Sentry.ReactNativeTracing({
// Pass instrumentation to be used as `routingInstrumentation`
routingInstrumentation,
...
}),
],
})
// Functional Component Example
const App = () => {
// Create a ref for the navigation container
const appContainer = React.createRef();
// Register the navigation container with the instrumentation
React.useEffect(() => {
routingInstrumentation.registerAppContainer(appContainer);
}, []);
return (
// Connect the ref to the navigation container
<AppContainer ref={appContainer} />
);
};
// Class Component Example
class App extends React.Component {
// Create a ref for the navigation container
appContainer = React.createRef();
componentDidMount() {
// Register the navigation container with the instrumentation
routingInstrumentation.registerAppContainer(appContainer);
}
render() {
return (
// Connect the ref to the navigation container
<AppContainer ref={appContainer} />
)
}
}
Other Routing Libraries or Custom Routing Implementations
If you use another routing library that we don't yet support, or have a custom routing solution, you can use the basic RoutingInstrumentation
we provide, or extend it to create your own instrumentation.
Every routing instrumentation revoles around one method:
onRouteWillChange
(context: TransactionContext): Transaction | undefined
You need to ensure that this method is called before the route change occurs, and an IdleTransaction
is created and set on the scope.
Bare Bones
// Construct a new instrumentation instance. This is needed to communicate between the integration and React
const routingInstrumentation = new Sentry.RoutingInstrumentation();
Sentry.init({
...
integrations: [
new Sentry.ReactNativeTracing({
// Pass instrumentation to be used as `routingInstrumentation`
routingInstrumentation,
...
}),
],
})
const App = () => {
<SomeNavigationLibrary
onRouteWillChange={(newRoute) => {
// Call this before the route changes
routingInstrumentation.onRouteWillChange({
name: newRoute.name,
op: 'navigation'
})
}}
/>
};
Custom Instrumentation
To create a custom routing instrumentation, look at how the RoutingInstrumentation
class is implemented. If you need an example of how to implement routing instrumentation, review the code of the existing official instrumentation such as the one for React Navigation V4
class CustomInstrumentation extends RoutingInstrumentation {
constructor(navigator) {
super();
this.navigator.registerRouteChangeListener(this.routeListener.bind(this));
}
routeListener(newRoute) {
// Again, ensure this is called BEFORE the route changes and BEFORE the route is mounted.
this.onRouteWillChange({
name: newRoute.name,
op: "navigation",
});
}
}
Recipes
Currently, by default, the React Native SDK will only create child spans for fetch/XHR transactions out of the box. This means once you are done setting up your routing instrumentation, you will either see just a few fetch/XHR child spans or no children at all. To find out how to customize instrumentation your app, review our Custom Instrumentation.
React Profiler
We export the React Profiler from our React Native SDK as well, you can read more at React Profiler.
After you instrument your app's routing, if you wrap a component that renders on one of the routes with withProfiler
, you will be able to track the component's lifecycle as a child span of the route transaction.
import * as Sentry from "@sentry/react-native";
const SomeComponent = () => {
// ...
};
export default Sentry.withProfiler(SomeComponent);
- Package:
- npm:@sentry/react-native
- Version:
- 2.2.1
- Repository:
- https://github.com/getsentry/sentry-react-native