---
title: "Monitor App Performance in Capacitor with Firebase"
description: Monitor app performance in a Capacitor app with Firebase — automatic app-start, screen, and network traces plus custom code traces, metrics, and attributes.
date:
  created: 2026-09-12
  updated: 2026-09-12
authors:
  - djabif
categories:
  - Capacitor
  - Firebase
  - Guides
  - SDKs
links:
  - Capacitor Firebase Performance Monitoring: sdks/capacitor/firebase/performance-monitoring.md
faq: true
---

# Monitor App Performance in Capacitor with Firebase

"The app feels slow" is impossible to fix without numbers. [Firebase Performance Monitoring](https://firebase.google.com/docs/perf-mon){:target="_blank"} gives you those numbers from real devices in the field: how long your app takes to start, how screens render, and how long the operations you care about run for your users. The [Capacitor Firebase Performance Monitoring plugin](../../sdks/capacitor/firebase/performance-monitoring.md) brings it to Capacitor apps through the native Android and iOS SDKs.

This guide covers it end to end: what Performance Monitoring measures for free, the native setup, writing custom traces for the operations that matter to you, and the two things that confuse newcomers most (where your WebView's network requests go, and why data takes a while to show up).

<!-- more -->

<div class="capawesome-z29o10a">
  <a href="/" target="_blank">
    <img alt="Build and deploy your Capacitor app with Capawesome Cloud" src="https://capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1" />
  </a>
</div>

## Key Takeaways

- Performance Monitoring collects app-start time, screen rendering, and native network requests automatically, without a line of code from you.
- Measure your own operations with a custom trace: [`startTrace(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#starttrace) and [`stopTrace(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#stoptrace).
- Count events inside a trace with [`incrementMetric(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#incrementmetric), and segment with `putAttribute(...)`.
- **`fetch`/XHR calls from your web layer aren't captured automatically.** Wrap the important ones in a custom trace to measure them.
- Performance data is batched: it can take up to ~12 hours to appear in the console, so don't expect instant feedback.
- `setEnabled(...)` toggles collection (applies on the next app start), the hook for a consent flow.

## How to Monitor App Performance in a Capacitor App

Adding Firebase Performance Monitoring to a Capacitor app takes three steps:

1. **Install** `@capacitor-firebase/performance` and sync the native projects.
2. **Add the native config**: the Firebase config files plus the Performance Monitoring Gradle plugin on Android.
3. **Measure**: automatic traces start immediately; wrap your own operations in `startTrace()` / `stopTrace()`.

The remaining sections dig into what's measured automatically, custom traces, metrics, attributes, and troubleshooting.

## What Is Firebase Performance Monitoring?

[Firebase Performance Monitoring](https://firebase.google.com/docs/perf-mon){:target="_blank"} measures your app's real-world performance and reports it in the Firebase console, broken down by device, OS version, country, and app version. The [Capacitor Firebase Performance Monitoring plugin](../../sdks/capacitor/firebase/performance-monitoring.md) exposes the native Android and iOS Performance SDKs, plus the Firebase JS SDK on web, behind one shared TypeScript API.

## What Gets Measured Automatically (and What Doesn't)

Once the SDK is in your app, it collects a set of traces with no code from you:

- **App start time**: how long from launch to the app being interactive.
- **Screen rendering**: slow and frozen frames per screen.
- **Native network requests**: the duration and success rate of HTTP/S requests made through the native networking stack.

Network requests you make with `fetch` or `XHR` from your web layer run inside the WebView, and the native automatic network monitoring generally doesn't see them. To measure your API calls, wrap the important ones in a custom trace yourself, covered below, rather than assuming they show up in the automatic network view.

## Why Use Performance Monitoring in a Capacitor App?

The plugin pays off in four situations:

- **Custom code traces.** Measure how long a specific task takes: loading a screen's data, processing an image, running a sync.
- **Custom metrics.** Count performance-related events inside a trace, like cache hits or retries.
- **Performance segmentation.** Add attributes (a user tier, a feature flag state) to slice your data.
- **Privacy compliance.** Turn monitoring on or off at runtime based on the user's consent.

## Before You Start

The starting point is a Capacitor app with the `android` and/or `ios` platforms added and a Firebase project (create one in the [Firebase console](https://console.firebase.google.com/){:target="_blank"} if needed). Performance Monitoring turns on as soon as the SDK is wired up. There's no separate "enable" switch in the console.

## Step 1: Install the Plugin

Install the plugin and the `firebase` package (used on the web layer), then sync the native projects:

```bash
npm install @capacitor-firebase/performance firebase
npx cap sync
```

## Step 2: Add Firebase and the Performance Gradle Plugin

Add the native config files Firebase generates ([full reference](https://github.com/capawesome-team/capacitor-firebase/blob/main/docs/firebase-setup.md){:target="_blank"}): `google-services.json` in `android/app/`, and `GoogleService-Info.plist` added to the Xcode project in `ios/App/App/`.

On Android, add the Performance Monitoring Gradle plugin so build-time instrumentation (automatic network and rendering traces) is included. Follow Firebase's [Add the Performance Monitoring plugin](https://firebase.google.com/docs/perf-mon/get-started-android#add-perfmon-plugin){:target="_blank"} steps. On iOS with Swift Package Manager, add the `symlink` package option to `capacitor.config.ts` (Capacitor CLI 8.4.0+); it prevents a SwiftPM package identity collision:

```json
{
  "experimental": {
    "ios": {
      "spm": {
        "packageOptions": {
          "@capacitor-firebase/performance": { "symlink": true }
        }
      }
    }
  }
}
```

## Measuring a Task With a Custom Trace

A custom trace measures the time between two points you choose. Start it before the work and stop it after. Performance Monitoring records the duration and reports it in the console under that trace name:

```typescript
import { FirebasePerformance } from '@capacitor-firebase/performance';

const loadDashboard = async () => {
  await FirebasePerformance.startTrace({ traceName: 'load_dashboard' });
  try {
    await fetchDashboardData();
  } finally {
    await FirebasePerformance.stopTrace({ traceName: 'load_dashboard' });
  }
};
```

Wrapping the work in `try/finally` means the trace is stopped even if the operation throws, so a failed run doesn't leave a trace open forever. This is also the reliable way to measure the WebView `fetch` calls the automatic network view misses.

## Recording Custom Metrics

Inside a trace, count events that explain its duration: a cache hit, a retry, the number of items processed. Set a value with [`putMetric(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#putmetric) or add to it atomically with [`incrementMetric(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#incrementmetric). Metric values are floored to the nearest integer:

```typescript
import { FirebasePerformance } from '@capacitor-firebase/performance';

const trackCacheHit = async () => {
  await FirebasePerformance.incrementMetric({
    traceName: 'load_dashboard',
    metricName: 'cache_hits',
    incrementBy: 1,
  });
};
```

## Segmenting With Custom Attributes

Attributes let you slice a trace's data in the console. Compare load times for free vs. paid users, or with a feature flag on vs. off. Add one with [`putAttribute(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#putattribute):

```typescript
import { FirebasePerformance } from '@capacitor-firebase/performance';

const tagTrace = async () => {
  await FirebasePerformance.putAttribute({
    traceName: 'load_dashboard',
    attribute: 'user_tier',
    value: 'pro',
  });
};
```

Keep attribute values to a small set of known categories (`free`/`pro`, `on`/`off`) rather than high-cardinality data like a raw user ID. The console segments by attribute value, and unbounded values make the breakdown useless.

## Controlling Collection

Performance Monitoring collects data automatically by default. To gate it behind consent, disable it and enable it only once the user agrees. Note that [`setEnabled(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#setenabled) applies on the *next* app start:

```typescript
import { FirebasePerformance } from '@capacitor-firebase/performance';

const setMonitoringEnabled = async (enabled: boolean) => {
  await FirebasePerformance.setEnabled({ enabled });
};
```

## Performance Monitoring Best Practices

### Trace the Operations Users Actually Feel

Don't trace everything. Trace the moments users judge your app by: the first screen's data load, a search, a checkout, an image export. A handful of well-named traces beats a hundred noisy ones.

### Wrap Web-Layer Network Calls Yourself

Because automatic network monitoring misses WebView `fetch`/XHR, your most important API calls won't appear unless you trace them. Put a custom trace around the calls whose latency you care about, so they show up alongside the automatic data.

### Stop Every Trace, Even on Failure

A trace that's started but never stopped is lost. Use `try/finally` so the trace stops whether the work succeeds or throws.

### Keep Attributes Low-Cardinality

Attributes are for segmenting into buckets. Use bounded categories, not per-user values. Otherwise the console can't group anything meaningfully.

## Common Errors and Troubleshooting

- **No data in the console.** Performance data is batched and can take up to ~12 hours (sometimes longer for a brand-new app) to appear. It's almost never broken, only delayed.
- **My API calls don't show in the network view.** Requests made with `fetch`/XHR from the web layer run in the WebView and aren't captured automatically. Wrap them in a custom trace.
- **Android shows no automatic traces.** The Performance Monitoring Gradle plugin isn't applied. Follow the Android setup in Step 2. Automatic network and rendering instrumentation depends on it.
- **`setEnabled(false)` didn't stop collection immediately.** It applies on the next app start, not the current session.
- **A custom trace never appears.** It was started but not stopped (or stopped under a different `traceName`). Stop every trace in a `finally` block, matching the exact name.
- **App crashes on launch.** The `google-services.json` / `GoogleService-Info.plist` file is missing or misplaced (Step 2).

## FAQ

### What does Firebase Performance Monitoring measure automatically in a Capacitor app?

App start time, screen rendering (slow and frozen frames), and native HTTP/S network requests, all without code. What it does *not* capture automatically is network requests made with `fetch`/XHR from your web layer, since those run inside the WebView; wrap those in a custom trace.

### Why don't my `fetch` requests appear in Performance Monitoring?

Automatic network monitoring instruments the native networking stack, but a Capacitor app makes most requests from JavaScript inside the WebView, which the native SDK generally doesn't see. Measure those calls with a custom [`startTrace(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#starttrace) / [`stopTrace(...)`](../../sdks/capacitor/firebase/performance-monitoring.md#stoptrace) around the request.

### Why don't I see any performance data yet?

Performance Monitoring processes data in batches, so it can take up to about 12 hours to show in the console, and the first data for a new app can take longer. If traces still don't appear after that, check that the Android Gradle plugin is applied and that monitoring isn't disabled.

### Is Firebase Performance Monitoring free to use?

Yes. Performance Monitoring has no usage-based billing, so you can trace as much as you need without a cost consideration. Check the current [Firebase pricing page](https://firebase.google.com/pricing){:target="_blank"} for the latest details.

## Ship Performance Fixes the Same Day You Spot Them

Performance Monitoring tells you which screen or operation is slow; the fix usually lives in your web layer. [Capawesome Cloud](https://capawesome.io/){:target="_blank"} builds your iOS and Android apps in the cloud and ships web-layer changes over the air with live updates, so a slow-render fix or a smarter data-load can reach users the same day you find the regression, without an app store review. It also automates store submission when a native release is needed.

[Try Capawesome Cloud Free](https://capawesome.io){ .md-button .md-button--primary }

## Conclusion

If you're adding Performance Monitoring today, install the plugin and the native config first and let the automatic traces collect before you write any measurement code of your own. Then add custom traces one at a time, starting with the screen users complain about, and put a trace around the `fetch` calls behind it, because the automatic network view won't report them. Add the next trace only once the first one has told you something.

If you want to go deeper from here:

- [Crash Reporting in a Capacitor App with Crashlytics](./capacitor-firebase-crashlytics-guide.md). Stability and performance are the two halves of app health; teams usually add both.
- [Track App Events with Firebase Analytics in Capacitor](./capacitor-firebase-analytics-guide.md). Pair *how fast* with *what users do* for the full picture.
- [Capacitor Firestore: Real-Time Data & Offline Sync](./capacitor-firebase-cloud-firestore-guide.md). A common source of the data loads worth wrapping in a trace.

Found a trace you can't explain, or a number that looks off? The [Capawesome Discord server](https://discord.gg/VCXxSVjefW){:target="_blank"} is a good place to compare notes, and the [Capawesome newsletter](https://capawesome.io/newsletter/){:target="_blank"} brings the next deep-dive to your inbox.
