---
title: Phone Number Verification
description: Installation and getting started with Phone Number Verification.
icon: //static.invertase.io/assets/social/firebase-logo.png
next: /vertexai/usage
previous: /perf/usage
---

# Installation

This module requires that the `@react-native-firebase/app` module is already setup and installed. To install the "app" module, view the
[Getting Started](/) documentation.

```bash
# Install & setup the app module
yarn add @react-native-firebase/app

# Install the phone-number-verification module
yarn add @react-native-firebase/phone-number-verification
```

> **Android only** - This module is only available on Android. The Firebase Phone Number Verification SDK does not support iOS or web platforms. Calling any method on a non-Android platform will throw an error.

# What does it do

Firebase Phone Number Verification (PNV) provides carrier-level phone number verification on Android devices without requiring SMS codes. It verifies the user's phone number directly through the device's SIM card and carrier network, providing a seamless and secure verification experience.

To learn more, visit the [Firebase Phone Number Verification documentation](https://firebase.google.com/docs/phone-number-verification).

Key capabilities:

- **Carrier-level verification**: Verifies phone numbers directly with the mobile carrier, without SMS.
- **Support detection**: Check whether the device and carrier support phone number verification before attempting it. This does not require user consent.
- **Verified phone number**: Retrieve the device's verified phone number as a JWT token containing the phone number, timestamps, nonce, and claims. This will present a consent dialog to the user.
- **Digital Credential API**: Supports the Android Digital Credential API for custom verification flows.

## Region & carrier limitations

PNV depends on carrier cooperation. Not all carriers or regions are supported. Before relying on PNV, always call `getVerificationSupportInfo()` to check support. If a SIM slot returns `reason: 'INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED'`, that carrier does not participate in PNV and you should fall back to another verification method (e.g. Firebase Auth SMS).

Common reasons verification may be unsupported:

| Reason                                 | Meaning                                          |
| -------------------------------------- | ------------------------------------------------ |
| `CAPABLE`                              | The SIM's carrier supports PNV.                  |
| `INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED` | The carrier does not participate in PNV.         |
| `INCAPABLE_DUE_TO_ANDROID_VERSION`     | The device's Android version is too old.         |
| `INCAPABLE_DUE_TO_SIM_STATE`           | No SIM inserted, or SIM is in an unusable state. |
| `CAPABILITY_STATUS_UNSPECIFIED`        | The SDK could not determine the status.          |

# Usage

## Check verification support

Before attempting verification, check if the device's SIM card(s) support phone number verification. This call does not require user consent and can be called freely:

```js
import { getVerificationSupportInfo } from '@react-native-firebase/phone-number-verification';

const supportInfo = await getVerificationSupportInfo();

for (const info of supportInfo) {
  console.log(`SIM slot ${info.simSlot}:`);
  console.log('  Supported:', info.isSupported);
  console.log('  Carrier ID:', info.carrierId);
  console.log('  Reason:', info.reason);
}
```

The method returns an array with one entry per SIM slot. Each entry includes:

- `isSupported` — whether PNV is available for this SIM.
- `simSlot` — the SIM slot index (0-based).
- `carrierId` — the carrier identifier string.
- `reason` — a `VerificationSupportStatus` string explaining why the SIM is or isn't supported.

### Query a specific SIM slot

On dual-SIM devices, you can query a specific SIM slot by passing the slot index:

```js
import { getVerificationSupportInfo } from '@react-native-firebase/phone-number-verification';

const supportInfo = await getVerificationSupportInfo(0); // SIM slot 0
```

### Fallback when unsupported

If PNV is not supported, fall back to an alternative verification method:

```js
import { Platform } from 'react-native';
import {
  getVerificationSupportInfo,
  getVerifiedPhoneNumber,
} from '@react-native-firebase/phone-number-verification';

async function verifyPhoneNumber() {
  if (Platform.OS !== 'android') {
    // Use SMS-based verification on non-Android platforms
    return verifySms();
  }

  const supportInfo = await getVerificationSupportInfo();
  const supported = supportInfo.some(info => info.isSupported);

  if (supported) {
    try {
      return await getVerifiedPhoneNumber();
    } catch (error) {
      // Fall back to SMS on failure
      return verifySms();
    }
  }

  // Carrier or device doesn't support PNV
  return verifySms();
}
```

## Verify a phone number

To initiate the full verification flow, call `getVerifiedPhoneNumber()`. This will present a consent dialog to the user asking permission to share their phone number. Your app should prepare the user for this consent screen before calling the method — for example, by explaining why their phone number is needed.

For guidance on handling user consent, see the [Firebase PNV getting started guide](https://firebase.google.com/docs/phone-number-verification/android/get-started).

```js
import { getVerifiedPhoneNumber } from '@react-native-firebase/phone-number-verification';

try {
  const result = await getVerifiedPhoneNumber();
  console.log('Phone number:', result.phoneNumber);
  console.log('Token:', result.token);
  console.log('Expires at:', new Date(result.expirationTimestamp * 1000));
  console.log('Issued at:', new Date(result.issuedAtTimestamp * 1000));
  console.log('Nonce:', result.nonce);
  console.log('Claims:', result.claims);
} catch (error) {
  console.error('Verification failed:', error.code, error.message);
}
```

The returned result includes:

- `phoneNumber` — the verified phone number in E.164 format.
- `token` — the raw JWT token string for server-side validation.
- `expirationTimestamp` — token expiration as Unix epoch seconds.
- `issuedAtTimestamp` — token issued-at time as Unix epoch seconds.
- `nonce` — the nonce from the JWT payload, or `null`.
- `claims` — all JWT claims as a key-value map, or `null`.

## Custom verification with Digital Credentials

For advanced use cases, you can use the Digital Credential API flow:

```js
import {
  getDigitalCredentialPayload,
  exchangeCredentialResponseForPhoneNumber,
} from '@react-native-firebase/phone-number-verification';

// Step 1: Get the credential payload
const payload = await getDigitalCredentialPayload('your-unique-nonce');

// Step 2: Use the payload with Android Credential Manager
// ... (pass payload to CredentialManager API)

// Step 3: Exchange the response for a verified phone number
const result = await exchangeCredentialResponseForPhoneNumber(credentialResponse);
console.log('Phone number:', result.phoneNumber);
console.log('Expires at:', new Date(result.expirationTimestamp * 1000));
```

## Error handling

All methods reject with structured error codes from the Firebase PNV SDK. The `error.code` property contains one of these values:

| Error Code                                | Meaning                                                         |
| ----------------------------------------- | --------------------------------------------------------------- |
| `pnv/carrier-not-supported`               | The SIM's carrier does not support PNV.                         |
| `pnv/invalid-digital-credential-response` | The Digital Credential API response was invalid.                |
| `pnv/integrity-check-failed`              | Device integrity check failed.                                  |
| `pnv/preflight-check-failed`              | Server-side preflight check failed.                             |
| `pnv/unsupported-operation`               | The API call is not supported with the given parameters.        |
| `pnv/credential-manager-error`            | Android Credential Manager failed unexpectedly.                 |
| `pnv/invalid-test-number-id`              | Test number IDs are empty, expired, or duplicated.              |
| `pnv/test-session-already-enabled`        | `enableTestSession` was called more than once.                  |
| `pnv/activity-context-required`           | An Activity context is required (app may be in the background). |

```ts
import {
  getVerifiedPhoneNumber,
  PnvErrorCode,
  type PnvError,
} from '@react-native-firebase/phone-number-verification';

try {
  const result = await getVerifiedPhoneNumber();
} catch (error) {
  const pnvError = error as PnvError;

  switch (pnvError.code) {
    case PnvErrorCode.CARRIER_NOT_SUPPORTED:
      // Fall back to SMS verification
      break;
    case PnvErrorCode.ACTIVITY_CONTEXT_REQUIRED:
      // Retry when app is in foreground
      break;
    default:
      console.error('PNV error:', pnvError.code, pnvError.message);
  }
}
```

## Testing

To test without a real SIM card and carrier, use Firebase's test mode. This requires setup in the Firebase Console:

1. **Generate a test token**: In the Firebase Console, navigate to Phone Number Verification and generate a test token. Test tokens have a 7-day TTL.
2. **IAM permissions**: Ensure the service account has the required `firebasepnv.testSessions.create` permission.
3. **Google system services beta**: On the test device, enroll the Google system services app into the beta channel via Google Play.
4. **Call `enableTestSession` once**: Pass the token before any verification calls. This must be called only once per app instance — calling it again will reject with `pnv/test-session-already-enabled`.

```js
import {
  enableTestSession,
  getVerifiedPhoneNumber,
} from '@react-native-firebase/phone-number-verification';

// Call once at app startup for testing
await enableTestSession('your-test-token-from-firebase-console');

// Now verification calls return test data
// Phone numbers in test mode follow the format: valid country code + all zeros
const result = await getVerifiedPhoneNumber();
console.log('Test phone number:', result.phoneNumber);
```

## Platform handling

This module is Android-only. On non-Android platforms, all methods throw an error with the message "Firebase Phone Number Verification is only supported on Android." You can guard against this using `Platform.OS`:

```js
import { Platform } from 'react-native';
import { getVerificationSupportInfo } from '@react-native-firebase/phone-number-verification';

if (Platform.OS === 'android') {
  const supportInfo = await getVerificationSupportInfo();
  // ...
}
```
