---
title: "Firebase App Check in a Capacitor App"
description: Set up Firebase App Check in a Capacitor app to attest requests and protect your backend with Play Integrity, App Attest, reCAPTCHA, and App Check tokens.
date:
  created: 2026-08-30
  updated: 2026-08-30
authors:
  - djabif
categories:
  - Capacitor
  - Firebase
  - Guides
  - SDKs
links:
  - Capacitor Firebase App Check: sdks/capacitor/firebase/app-check.md
faq: true
---

# Firebase App Check in a Capacitor App

Your backend has no easy way to tell your real app apart from a script replaying its API calls. That's the gap [Firebase App Check](https://firebase.google.com/docs/app-check){:target="_blank"} closes: it attests that a request genuinely comes from your untampered app on a real device, and blocks the ones that don't. The [Capacitor Firebase App Check plugin](../../sdks/capacitor/firebase/app-check.md) brings that attestation to Capacitor apps using each platform's native provider — Play Integrity on Android, App Attest or DeviceCheck on iOS, and reCAPTCHA on the web.

This guide sets it up end to end: registering the providers in the Firebase console, the native configuration each one needs, initializing App Check in your app, sending tokens to your own backend, and testing on an emulator with the debug provider.

<!-- 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

- App Check attests requests with a **native provider per platform**: Play Integrity (Android), App Attest on iOS 14+ or DeviceCheck on iOS 13 (iOS), and reCAPTCHA v3 (Web).
- [`initialize(...)`](../../sdks/capacitor/firebase/app-check.md#initialize) activates App Check and runs **once per app** — on the web you pass a `ReCaptchaV3Provider`; native platforms use their built-in providers.
- [`getToken(...)`](../../sdks/capacitor/firebase/app-check.md#gettoken) returns a token to send to your own backend, which **verifies it server-side** before trusting the request.
- `setTokenAutoRefreshEnabled(...)` keeps tokens fresh; the `tokenChanged` listener notifies you when one rotates.
- Use the **debug provider** to test on emulators and simulators, which can't produce real attestations.
- Turn on **enforcement** in the console only after you confirm legitimate traffic is sending valid tokens, or you'll lock out your own users.

## How to Set Up Firebase App Check in a Capacitor App

Setting up Firebase App Check in a Capacitor app takes four steps:

1. **Register App Check** in your Firebase project and enable a provider for each platform.
2. **Install** `@capacitor-firebase/app-check` and sync the native projects.
3. **Configure the native providers** — Play Integrity on Android, App Attest/DeviceCheck on iOS, reCAPTCHA on the web.
4. **Initialize App Check** at startup, then attach its token to requests to your backend.

The sections below walk through each step, then cover the debug provider, best practices, and troubleshooting.

## What Is Firebase App Check?

[Firebase App Check](https://firebase.google.com/docs/app-check){:target="_blank"} is Google's app-attestation service. It works with a platform *attestation provider* to prove that a request originates from your genuine, untampered app, then issues a short-lived App Check token you can require on Firebase services (Firestore, Cloud Functions, Cloud Storage) and your own backend. The [Capacitor Firebase App Check plugin](../../sdks/capacitor/firebase/app-check.md) exposes the native Android and iOS App Check SDKs, plus the Firebase JS SDK on web, behind one shared TypeScript API.

The provider differs by platform, and this matters for setup:

- **Android** uses [Play Integrity](https://firebase.google.com/docs/app-check/android/play-integrity-provider){:target="_blank"}.
- **iOS** uses [App Attest](https://firebase.google.com/docs/app-check/ios/app-attest-provider){:target="_blank"} on iOS 14 and later, and [DeviceCheck](https://firebase.google.com/docs/app-check/ios/devicecheck-provider){:target="_blank"} on iOS 13.
- **Web** uses [reCAPTCHA v3](https://firebase.google.com/docs/app-check/web/recaptcha-provider){:target="_blank"}.

## Why Use App Check in a Capacitor App?

In practice, App Check earns its place in four ways:

- **Protecting Firebase resources.** Require a valid App Check token before your app can reach Cloud Firestore, Cloud Functions, or Cloud Storage.
- **Securing custom backends.** Retrieve a token with [`getToken(...)`](../../sdks/capacitor/firebase/app-check.md#gettoken) and send it with requests to your own API for server-side verification.
- **Automatic token refresh.** Keep tokens current with `setTokenAutoRefreshEnabled(...)` and react to rotations via the `tokenChanged` listener.
- **Local development.** Use the debug provider so emulators and simulators, which can't attest, still work during development.

## Before You Start

Before diving in, make sure you have a Capacitor app with the `android` and/or `ios` platforms in place, plus a Firebase project — creating one takes a minute in the [Firebase console](https://console.firebase.google.com/){:target="_blank"}.

## Step 1: Register App Check in the Firebase Console

1. In the [Firebase console](https://console.firebase.google.com/){:target="_blank"}, open **Build → App Check**.
2. Under the **Apps** tab, select each app and register its provider — **Play Integrity** for Android, **App Attest** (or DeviceCheck) for iOS, and **reCAPTCHA** for a web app. Registering a provider is what lets Firebase validate the attestations your app will send.
3. For the web app, create a reCAPTCHA v3 site key when prompted and keep it handy — you'll pass it to `initialize(...)`.
4. Leave **enforcement** off for now. You enable it per service (Firestore, Functions, and so on) later, once you've confirmed real traffic is sending valid tokens.

## Step 2: 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/app-check firebase
npx cap sync
```

## Step 3: Configure Firebase and the Native Providers

Add the Firebase config files first ([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/`. Then each provider has its own requirement:

- **Android (Play Integrity)** — follow Firebase's [project setup for Play Integrity](https://firebase.google.com/docs/app-check/android/play-integrity-provider#project-setup){:target="_blank"} to link your app. No provider code is needed in the app; the native provider is used automatically.
- **iOS (App Attest / DeviceCheck)** — follow the [App Attest](https://firebase.google.com/docs/app-check/ios/app-attest-provider#project-setup){:target="_blank"} setup for iOS 14+, or [DeviceCheck](https://firebase.google.com/docs/app-check/ios/devicecheck-provider#project-setup){:target="_blank"} for iOS 13. The private key (`.p8`) you upload to Firebase must have **DeviceCheck** selected as a service. With Swift Package Manager, you'll also want the `symlink` package option in your `capacitor.config.ts`, which works around a SwiftPM package identity collision (Capacitor CLI 8.4.0 or newer).
- **Web (reCAPTCHA v3)** — no native step; you pass the reCAPTCHA site key from Step 1 to `initialize(...)`, shown next.

## Initializing App Check

Activate App Check once, as early as possible in your app's startup, before you use any Firebase service you plan to protect. On the web you pass a `ReCaptchaV3Provider` with your site key; on Android and iOS the native provider is used automatically, so you leave the provider undefined:

```typescript
import { FirebaseAppCheck, ReCaptchaV3Provider } from '@capacitor-firebase/app-check';
import { Capacitor } from '@capacitor/core';

const initializeAppCheck = async () => {
  await FirebaseAppCheck.initialize({
    provider:
      Capacitor.getPlatform() === 'web'
        ? new ReCaptchaV3Provider('your-recaptcha-site-key')
        : undefined,
  });
};
```

Call this from your app's bootstrap (an `APP_INITIALIZER` in Angular, the entry module in React, or `main.ts` in Vue) — anywhere that runs once, before your first protected request.

## Using App Check Tokens

For your own backend, retrieve the current token with [`getToken(...)`](../../sdks/capacitor/firebase/app-check.md#gettoken) and send it as a header. Set `forceRefresh` to `true` only when you specifically need a fresh token rather than the cached one:

```typescript
import { FirebaseAppCheck } from '@capacitor-firebase/app-check';

const callProtectedApi = async () => {
  const { token } = await FirebaseAppCheck.getToken({ forceRefresh: false });
  await fetch('https://api.example.com/orders', {
    headers: { 'X-Firebase-AppCheck': token },
  });
};
```

Your server then verifies that token with the [Firebase Admin SDK](https://firebase.google.com/docs/app-check/custom-resource-backend){:target="_blank"} before trusting the request. For Firebase services like Firestore and Cloud Functions, no header is needed — once enforcement is on, the SDKs attach the token for you.

Keep tokens fresh and react to rotations:

```typescript
import { FirebaseAppCheck } from '@capacitor-firebase/app-check';

const trackTokens = async () => {
  await FirebaseAppCheck.setTokenAutoRefreshEnabled({ enabled: true });
  await FirebaseAppCheck.addListener('tokenChanged', event => {
    console.log('App Check token changed', event);
  });
};
```

## Testing with the Debug Provider

Emulators and simulators can't produce a real Play Integrity or App Attest attestation, so App Check would reject them. The debug provider is the way around this in development: run the app, copy the debug token the SDK prints to the native log, and register it under **App Check → your app → Manage debug tokens** in the Firebase console. That token then attests your debug builds until you revoke it. Never ship a debug token in a production build — anyone with it can bypass attestation.

## Run on a Device and Verify

Build and launch the app on a device or emulator:

```bash
npx cap sync
npx cap run android   # or: npx cap run ios
```

Then confirm attestation is flowing:

1. Call `getToken(...)` and check that it resolves with a non-empty token rather than throwing.
2. In the Firebase console, open **App Check** — the **Requests** metrics for your app should start showing verified requests within a few minutes.

Once verified requests appear and your own users are covered, you can safely turn on enforcement per service.

## App Check Best Practices

### Verify Tokens on Your Server

An App Check token is only meaningful if your backend checks it. Verify the token's signature and validity with the Firebase Admin SDK before serving a protected request — a token that merely arrives proves nothing until it verifies.

### Turn On Enforcement Gradually

Enforcement is what actually blocks unattested requests, and it's also what locks out any legitimate client that isn't sending a valid token yet. Watch the App Check metrics until verified requests dominate, then enable enforcement one service at a time rather than all at once.

### Initialize Before Your First Protected Call

`initialize(...)` has to run before any request you expect App Check to cover. Initialize it in your app's bootstrap, not lazily on a screen the user might reach after an earlier request has already gone out unattested.

### Keep Debug Tokens Out of Production

Debug tokens bypass attestation by design. Register them only for development builds, keep them out of source control, and revoke any that leak.

## Common Errors and Troubleshooting

- **Requests fail with a 403 / "unauthorized" after enabling enforcement.** Legitimate clients aren't sending valid tokens yet. Confirm `initialize(...)` runs at startup and that verified requests show in the App Check metrics before enforcing.
- **App Check rejects your emulator or simulator.** These can't attest — register a debug token (above) for development builds.
- **iOS attestation fails.** The `.p8` private key uploaded to Firebase must have **DeviceCheck** selected as a service, and App Attest requires iOS 14+. Re-check the iOS provider setup in Step 3.
- **`initialize(...)` throws "already initialized".** It can only run once per app. Make sure it isn't called from more than one place.
- **The web build never attests.** You didn't pass a `ReCaptchaV3Provider`, or the site key is wrong. Confirm the reCAPTCHA key from Step 1 is passed on the web platform.
- **`removeAllListeners()` does nothing on native.** It's Web only — manage listener lifecycles yourself on Android and iOS.

## FAQ

### What is Firebase App Check used for in a Capacitor app?

App Check verifies that requests to your Firebase services or your own backend come from your genuine, untampered app rather than a bot, script, or repackaged clone. In a Capacitor app it attests with the platform's native provider — Play Integrity on Android, App Attest/DeviceCheck on iOS, reCAPTCHA on the web — and issues a token your backend can require.

### How do I test App Check on an emulator?

Use the debug provider. Run the app, copy the debug token from the native log, and register it under **App Check → Manage debug tokens** in the Firebase console. Emulators and simulators can't produce real attestations, so this is the supported way to develop against App Check.

### Does App Check work on the web with Capacitor?

Yes. On the web platform the plugin uses reCAPTCHA v3 through the Firebase JS SDK — pass a `ReCaptchaV3Provider` with your site key to `initialize(...)`. Android and iOS use their native providers instead.

### Will turning on App Check break my app for existing users?

It can, if you enforce too early. App Check only blocks requests once you enable **enforcement** per service — and it blocks any client that isn't sending a valid token yet, including older app versions still in the wild. Watch the App Check metrics until verified requests dominate, then enforce one service at a time so you don't lock out real users on versions that predate your App Check rollout.

### Do I still need App Check if I already use Firebase Authentication?

Yes — they protect different things. Authentication verifies *who the user is*; App Check verifies *that the request comes from your genuine app*. A signed-in user's credentials can still be used from a script or a repackaged clone, which is exactly what App Check blocks. Most apps that care about abuse use both together.

### Does App Check work offline?

App Check needs a network connection to attest and fetch a token, but tokens are cached and valid for a window (about an hour by default), so brief offline periods are covered by a previously issued token. A device that's offline long enough for the token to expire won't be able to refresh until it reconnects.

### Is Firebase App Check free to use?

App Check itself has a free tier, and Play Integrity, App Attest, and DeviceCheck are provided by the platforms at no charge for typical usage. Very high request volumes can incur costs on some providers, so check the current [Firebase pricing page](https://firebase.google.com/pricing){:target="_blank"} before relying on it at large scale.

## Keep App Check Working Across Every Build

App Check attestation is tied to your app's signing identity — Play Integrity to your Play signing key, App Attest to your bundle ID and Apple team. [Capawesome Cloud](https://capawesome.io/){:target="_blank"} builds and signs your iOS and Android apps in the cloud, so the signing that App Check depends on stays consistent across every release, and its live updates let you adjust how your app requests and sends tokens without cutting a new native build for every tweak.

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

## Conclusion

App Check gives your app a way to prove it's the real thing, and the plugin wires that into Capacitor with each platform's native attestation provider. The setup is front-loaded — registering providers, configuring Play Integrity and App Attest, and passing a reCAPTCHA key on the web — but once `initialize(...)` runs at startup, tokens flow automatically to your Firebase services and are one `getToken(...)` call away for your own backend. The two things to get right: verify tokens server-side, and roll out enforcement gradually so you don't lock out real users.

If you want to go deeper from here:

- [Capacitor Firestore: Real-Time Data & Offline Sync](./capacitor-firebase-cloud-firestore-guide.md) — one of the Firebase services App Check protects once enforcement is on.
- [Firebase Authentication in Capacitor: Setup & Best Practices](./capacitor-firebase-authentication-guide.md) — App Check verifies the app; Authentication verifies the user. They solve different halves of the same problem.
- [Crash Reporting in a Capacitor App with Crashlytics](./capacitor-firebase-crashlytics-guide.md) — once your backend is protected, crash reporting is the other half of shipping with confidence.

If a provider won't attest or enforcement is behaving oddly, the [Capawesome Discord server](https://discord.gg/VCXxSVjefW){:target="_blank"} is the fastest place to get help — and the [Capawesome newsletter](https://capawesome.io/newsletter/){:target="_blank"} keeps guides like this one coming to your inbox.
