# Fix React Native Performance in a Slow Checkout Flow

> Use Sentry tracing to instrument a React Native checkout flow with a Python backend, identify slow HTTP requests, and set up alerts and dashboards.

**URL:** https://sentry.io/cookbook/track-checkout-performance-react-native/

---

Instrument tracing across a React Native app and Python backend to pinpoint the slow HTTP requests in your checkout flow, fix them, and set up alerts and dashboards that catch the next regression.

**Time:** 20-30 minutes | **Difficulty:** Intermediate

## What You'll Learn

- Instrumented tracing across React Native and Python

- Tracked time to initial display and time to full display for mobile screens

- Created custom spans for critical checkout operations

- Found slow HTTP requests using Mobile Insights and Trace Explorer

- Set up alerts and dashboard widgets for checkout performance

**Topics:** Tracing, Alerts, Dashboards

**SDKs:** React Native, Python

## Before you start

**SDKs required**

- [@sentry/react-native](https://docs.sentry.io/platforms/react-native/) installed in your mobile app

- [sentry-sdk](https://docs.sentry.io/platforms/python/) installed in your Python backend

**Accounts & access**

- [Sentry account](https://sentry.io/signup/) with a React Native project

- Python backend project in the same [Sentry organization](https://docs.sentry.io/organization/)

- Access to deploy code to both frontend and backend

**Knowledge**

- Basic familiarity with [React Native development](https://reactnative.dev/docs/getting-started) and React Navigation

- Understanding of REST APIs and async data fetching

## Steps

### 1. Enable tracing and set trace propagation targets

In your React Native app, initialize the Sentry SDK with `tracesSampleRate` set to a value greater than zero. Set `tracePropagationTargets` to include your Python backend URL so that Sentry propagates trace headers across services. This connects your frontend and backend into a single distributed trace.

```javascript
import * as Sentry from "@sentry/react-native";

const navigationIntegration = Sentry.reactNavigationIntegration({
  enableTimeToInitialDisplay: true,
});

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [navigationIntegration],
  // Set to 1.0 for testing, lower in production
  tracesSampleRate: 1.0,
  // Include your Python backend so trace headers propagate
  tracePropagationTargets: ["localhost", "https://your-api.example.com"],
});
```

[React Native tracing setup](https://docs.sentry.io/platforms/react-native/tracing/)

### 2. Add time to full display on your checkout screen

Time to Initial Display (TTID) is tracked automatically when you enable the React Navigation integration. Time to Full Display (TTFD) requires you to tell Sentry when the screen is fully loaded. Use the `Sentry.TimeToFullDisplay` component and pass a boolean that flips to `true` once all content (like products on your checkout screen) has loaded.

```javascript
import * as Sentry from "@sentry/react-native";
import { useState, useEffect } from "react";

function CheckoutScreen() {
  const [products, setProducts] = useState(null);
  const allLoaded = products !== null;

  useEffect(() => {
    fetchProducts().then(setProducts);
  }, []);

  return (
    <View>
      <Sentry.TimeToFullDisplay record={allLoaded} />
      {allLoaded
        ? products.map((p) => <ProductItem key={p.id} product={p} />)
        : <LoadingSpinner />}
    </View>
  );
}
```

[Performance metrics](https://docs.sentry.io/platforms/react-native/tracing/instrumentation/performance-metrics/)

### 3. Create custom spans for checkout operations

Use `Sentry.startSpan` to wrap the operations you care about — like the initial catalog load and the checkout process itself. Pass attributes that you can search and filter by later in the Trace Explorer.

```javascript
async function loadCatalog() {
  return Sentry.startSpan(
    {
      op: "checkout.catalog_load",
      name: "Initial Catalog Load",
    },
    async () => {
      const response = await fetch("https://your-api.example.com/api/v1/products");
      return response.json();
    }
  );
}

async function processCheckout(cart) {
  return Sentry.startSpan(
    {
      op: "checkout.process",
      name: "Process Checkout",
      attributes: {
        "cart.item_count": cart.items.length,
        "cart.total": cart.total,
      },
    },
    async () => {
      const response = await fetch("https://your-api.example.com/api/v1/checkout", {
        method: "POST",
        body: JSON.stringify(cart),
      });
      return response.json();
    }
  );
}
```

[Automatic and custom instrumentation](https://docs.sentry.io/platforms/react-native/tracing/instrumentation/automatic-instrumentation/)

### 4. Review checkout performance in Mobile Insights

Open [Mobile Insights](https://sentry.io/orgredirect/organizations/:orgslug/insights/mobile/) in Sentry. Here you can see average time to display, cold start times, and transaction durations. Check the transaction list for your checkout screen. The [Mobile Vitals](https://docs.sentry.io/product/dashboards/sentry-dashboards/mobile/mobile-vitals/) screen shows TTID, TTFD, and screen loads across all your screens.

[Mobile vitals](https://docs.sentry.io/product/dashboards/sentry-dashboards/mobile/)

### 5. Drill into a slow checkout transaction

From the transaction list, filter by slowest transactions and click into one. The Transaction Summary shows a waterfall of all operations — HTTP requests, UI loads, and your custom spans. Look for the operations taking the most time. In the example scenario, a slow HTTP GET and POST to the backend were the main bottlenecks.

[Insights overview](https://docs.sentry.io/product/dashboards/sentry-dashboards/)

### 6. Explore spans in the Trace Explorer

Go to [Trace Explorer](https://sentry.io/orgredirect/organizations/:orgslug/explore/traces/) and search for your navigation spans (for example, filter by `span.op:navigation`). Click into a specific trace to see the full waterfall, including the time spent in your backend. You can group by attributes, compare P50 and P95 durations, and identify where time is being spent.

[Trace Explorer](https://docs.sentry.io/product/trace-explorer/)

### 7. Fix the slow backend endpoints and verify

Once you have identified the slow backend requests, optimize them (caching, query optimization, payload reduction — whatever applies). Redeploy and repeat the checkout flow. Go back to the Trace Explorer, search for recent checkout spans, and compare the new durations against the old ones. In the Trace Explorer, switch to the Visualize tab and chart the average span duration to see the improvement over time.

### 8. Create an alert for slow checkouts

From the Trace Explorer, with your checkout span filter active, click **Save As** and select **Alert**. Set a critical threshold (for example, average span duration over 1 second) and configure an action — like emailing your team or sending to Slack. Give the alert a descriptive name like "Checkout processing is slow." The alert will fire when performance degrades and resolve itself when things improve.

[Set up alerts](https://docs.sentry.io/product/monitors-and-alerts/alerts/)

### 9. Add a dashboard widget for checkout processing time

Go to [Dashboards](https://sentry.io/orgredirect/organizations/:orgslug/dashboards/) and open (or create) a performance dashboard. Click **Add Widget** and configure it:

- Set the dataset to **Spans**

- Set the Y-axis to **avg(span.duration)**

- Add a filter for `span.op:checkout.process`

- Name the widget something like "Checkout processing time" and save it

[Dashboard widget builder](https://docs.sentry.io/product/dashboards/widget-builder/)

## Summary

**Your checkout is instrumented.**

Slow transactions will surface as performance issues in Sentry, with spans showing exactly where the delay happened.

## Pro Tips

- Add meaningful attributes to your custom spans (like cart value, item count, or API version) so you can filter and group by them in the Trace Explorer.

- Use the Visualize tab in the Trace Explorer to chart span durations over time, then save those charts directly as alerts or dashboard widgets.

- Set `tracePropagationTargets` carefully — include only your own backend domains to avoid sending Sentry headers to third-party services.

- Start with `tracesSampleRate: 1.0` during development, then lower it in production to control costs. Consider using `tracesSampler` for finer control.

## Common Pitfalls

- If you forget to set `tracePropagationTargets` to include your backend URL, your frontend and backend traces won't be connected.

- TTFD won't be recorded if you never flip the `record` prop to `true` on `Sentry.TimeToFullDisplay`. Make sure your loading state resolves.

- Custom spans created with `Sentry.startSpan` need an active parent span to attach to. If tracing isn't enabled or the sample rate is zero, spans won't be captured.

- Don't set `tracesSampleRate` to 0 thinking it disables tracing — it still enables the tracing pipeline but drops everything. Remove the option entirely to disable tracing.

## FAQ

**What is the difference between TTID and TTFD?**

Time to Initial Display (TTID) measures how long it takes for the first frame of a screen to appear. Time to Full Display (TTFD) measures how long it takes for all content to load and become interactive. TTID is tracked automatically by the React Navigation integration. TTFD requires you to use the Sentry.TimeToFullDisplay component to signal when the screen is fully loaded.

**Do I need Sentry on both my React Native app and Python backend for distributed tracing?**

Yes. Both services need the Sentry SDK installed and tracing enabled. Sentry propagates trace context via HTTP headers (sentry-trace and baggage), which connect spans from your frontend to your backend into a single trace.

**What are spans and how do they relate to traces?**

A span is the smallest unit of work in a trace — like an HTTP request, a database query, or a UI component load. A trace is a collection of spans that together represent a full operation, like a user completing a checkout. Custom spans let you measure specific operations that matter to your app.

**Can I create alerts directly from the Trace Explorer?**

Yes. After filtering and visualizing span data in the Trace Explorer, click 'Save As' to create an alert or a dashboard widget using the same query and filters.

## Next Steps

- [Track component performance](https://docs.sentry.io/platforms/react-native/integrations/component-tracking/): Use the withProfiler higher-order component to monitor mount times and re-renders of individual React components in your app.

- [Set up profiling](https://sentry.io/product/profiling/): Identify the exact functions causing performance bottlenecks by collecting CPU profiles from real user sessions.

- [Monitor mobile vitals](https://docs.sentry.io/product/dashboards/sentry-dashboards/mobile/): Track app start times, slow and frozen frames, and screen load performance across all of your mobile screens.

---

*Source: [sentry.io/cookbook/track-checkout-performance-react-native/](https://sentry.io/cookbook/track-checkout-performance-react-native/)*
