|---|---|
| **Select platform:** | [iOS+](https://firebase.google.com/docs/crashlytics/ios/get-started.md.txt) [Android](https://firebase.google.com/docs/crashlytics/android/get-started.md.txt) [Android NDK](https://firebase.google.com/docs/crashlytics/android/get-started-ndk.md.txt) [Web](https://firebase.google.com/docs/crashlytics/web/get-started.md.txt) [Flutter](https://firebase.google.com/docs/crashlytics/flutter/get-started.md.txt) [Unity](https://firebase.google.com/docs/crashlytics/unity/get-started.md.txt) |

<br />

> [!WARNING]
> **Preview:** Crashlytics for web apps is a **preview** release. A preview release is not subject to any SLA or deprecation policy and could change in backwards-incompatible ways.

This guide describes how to get started with Firebase Crashlytics in
your web app.

After you've set up the Firebase Crashlytics SDK in your app, you can get
comprehensive crash reports in the Firebase console. With Crashlytics for
web apps, you get reports for errors.

> [!IMPORTANT]
> **Important:** Crashlytics support for web apps is rolling out over the next few days. If you don't yet see the experience in the Firebase console, check back soon!

## Before you begin

Setting up Crashlytics requires tasks both in the Firebase console and
your IDE (like adding your app's Firebase configuration and the Crashlytics
SDK). To finish setup, you'll need to force a test crash to send your first
crash report to Firebase.

To manually set up Crashlytics in your web app, make sure you have completed
the following prerequisites:

- Create a Firebase project and Firebase app if you don't already have one. If
  you haven't already,
  [add Firebase to your JavaScript project](https://firebase.google.com/docs/web/setup.md.txt).

- Make sure that your account has **Owner** permissions on your project. This
  is required to enable the necessary APIs and IAM roles.

- Make sure that your Firebase project is on the [pay-as-you-go Blaze pricing plan](https://firebase.google.com/pricing.md.txt).
  Crashlytics for web uses Cloud Logging for telemetry storage and
  Cloud Storage for source map storage, which are paid products with a
  no-cost tier. Learn more about
  [Logging pricing](https://cloud.google.com/products/observability/pricing)
  and [Cloud Storage pricing](https://cloud.google.com/storage/pricing).

## **Step 1** : Enable Crashlytics for your web app

Crashlytics for web uses Cloud Logging, Error Reporting, and
Cloud Storage, so you need to enable these APIs and configure permissions for
your project. You can enable Crashlytics for your web app using either the
Firebase console or the Firebase CLI.

### Use the Firebase console

1. In the Firebase console, go to
   **DevOps \& Engagement** \> **[**Crashlytics** dashboard](https://console.firebase.google.com/project/_/crashlytics)**.

2. Select your web app from the drop-down selector at the top of the page.

3. Click **Set up Crashlytics** and follow the on-screen instructions.

### Use the Firebase CLI

> [!IMPORTANT]
> **Important:** While Crashlytics support for web apps is rolling out over the next few days, we recommend using the Firebase console for setup. If you use the Firebase CLI right now to set up Crashlytics, you might not be able to see your crashes in the Crashlytics dashboard until later this week.

If you prefer configuring your project from the terminal or using an AI coding
agent, you can use the Firebase CLI:

1. Make sure that you have **Firebase CLI v15.35.0 or later** installed and
   that you're authenticated (`firebase login`). Learn how to
   [install or update the Firebase CLI](https://firebase.google.com/docs/cli.md.txt).

2. Run the following command to set up Crashlytics for your web app:

   ```bash
   firebase crashlytics:setup \
     --app FIREBASE_APP_ID \
     --project PROJECT_ID
   ```

   This command performs the following setup steps:
   - Verifies that your project is on the pay-as-you-go Blaze pricing plan, and prompts
     you to upgrade if needed.

   - Enables the required Crashlytics and telemetry APIs
     (`firebasetelemetry.googleapis.com`,
     `firebasetelemetryadmin.googleapis.com`,
     `firebasecrashlytics.googleapis.com`, and
     `clienttelemetry.googleapis.com`).

   - If your web app's API key has API restrictions, adds
     `clienttelemetry.googleapis.com` to its allowed APIs.

   - Configures Crashlytics telemetry settings for your web app.

   - When run interactively, prompts you to optionally enable email alerts for
     new and regressed issues.

## **Step 2**: Add and initialize the SDK in your app

1. Install the Crashlytics SDK:

   ```bash
   npm install firebase
   ```
2. Initialize your `FirebaseApp` instance:

   Create a central configuration utility file to use singleton initialization.
   To find your Firebase app configuration values, go to your
   **Project settings** \>
   [**General** page](https://console.firebase.google.com/project/_/settings/general/)
   in the Firebase console, go to the **Your apps** card, and select
   your web app.

   ```typescript
   // src/lib/firebase.ts
   import { initializeApp, getApps, getApp } from '@firebase/app';

   const firebaseConfig = {
     apiKey: "API_KEY",
     authDomain: "AUTH_DOMAIN",
     projectId: "PROJECT_ID",
     storageBucket: "STORAGE_BUCKET",
     messagingSenderId: "MESSAGING_SENDER_ID",
     appId: "FIREBASE_APP_ID"
   };

   // Guarantee singleton initialization across renders or module refreshes
   export const app = getApps().length === 0
     ? initializeApp(firebaseConfig)
     : getApp();
   ```

## **Step 3**: Configure automatic error capturing for your framework

Both automatic framework error receivers and manual trackers use your shared
`FirebaseApp` instance. Select your framework to configure automatic error
capturing:

### Angular

Integrate with the Angular global error-catching runtime and automatic route
tracking by adding `provideCrashlytics(() => app)` to your app's providers
in `src/app/app.config.ts`:

```typescript
// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideCrashlytics } from '@firebase/crashlytics/angular';
import { app } from '../lib/firebase'; // Shared initialization script
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideCrashlytics(() => app)
  ]
};
```

> [!NOTE]
> **Note:** `provideCrashlytics` registers a custom `ErrorHandler` to track uncaught zone crashes (`Zone.js`) and uses internal `Router` instances to build dynamic routes (such as `/dashboard/user/:id`) rather than logging literal URLs, keeping telemetry free of personally identifiable information.

### Next.js

**Next.js 15.3+ (recommended): Client instrumentation
(`instrumentation-client.ts`)**

Next.js 15.3+ includes native client-side instrumentation via
`instrumentation-client.ts` (or `instrumentation-client.js`). Next.js
executes this file in the browser before React hydration begins.

Create `src/instrumentation-client.ts` (or `instrumentation-client.ts` in
your project root if not using a `src/` directory) and initialize
Crashlytics:

```typescript
// src/instrumentation-client.ts
import { getCrashlytics } from '@firebase/crashlytics';
import { app } from './lib/firebase'; // Shared initialization script

getCrashlytics(app);
```

This single file initializes Crashlytics before React hydration and
automatically registers global error listeners (`error` and
`unhandledrejection`) with zero modifications to `src/app/layout.tsx` or any
React component.

**Next.js \< 15.3: Client-side (App Router layout)**

For Next.js versions earlier than 15.3, `layout.tsx` is a Server Component
by default. Because `FirebaseApp` is non-serializable, wrap
`<FirebaseCrashlytics>` (from `@firebase/crashlytics/react` to initialize
Crashlytics and capture uncaught errors) in a Client Component (such as
`src/components/CrashlyticsProvider.tsx`) marked with the `'use client'`
directive:

```tsx
// src/components/CrashlyticsProvider.tsx
'use client';

import React from 'react';
import { FirebaseCrashlytics } from '@firebase/crashlytics/react';
import { app } from '../lib/firebase'; // Shared initialization script

export function CrashlyticsProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <FirebaseCrashlytics firebaseApp={app} />
      {children}
    </>
  );
}
```

Then wrap your root layout with `<CrashlyticsProvider>`:

```tsx
// src/app/layout.tsx
import React from 'react';
import { CrashlyticsProvider } from '../components/CrashlyticsProvider';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <CrashlyticsProvider>
          {children}
        </CrashlyticsProvider>
      </body>
    </html>
  );
}
```

### React (without React Router)

Wrap your root app component (typically `src/App.tsx` or `src/main.tsx`)
with the `<FirebaseCrashlytics>` error boundary component. This acts as the
global receiver, handling unhandled rejections and exceptions from the
browser and React UI. It wraps all child component hierarchies and
automatically captures uncaught exceptions or routing errors:

```tsx
// src/App.tsx
import React from 'react';
import { FirebaseCrashlytics } from '@firebase/crashlytics/react';
import { app } from './lib/firebase'; // Shared initialization script

export default function App({
  children,
}: {
  children?: React.ReactNode;
}) {
  return (
    <FirebaseCrashlytics firebaseApp={app}>
      {children}
    </FirebaseCrashlytics>
  );
}
```

### React Router (v6+)

If you're using React Router v6+, replace React Router's `<Routes>`
container with `<CrashlyticsRoutes>`. This automatically maps error
boundaries across routes and tracks errors using templated path names, such
as `/profile/:userId`:

```typescript
// src/App.tsx
import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import { CrashlyticsRoutes } from '@firebase/crashlytics/react-router';
import { app } from './lib/firebase'; // Shared initialization script
import Home from './pages/Home';
import Profile from './pages/Profile';
import Product from './pages/Product';

export default function App() {
  return (
    <BrowserRouter>
      <CrashlyticsRoutes firebaseApp={app}>
        <Route path="/" element={<Home />} />
        <Route path="/profile/:userId" element={<Profile />} />
        <Route path="/product/:productId/details" element={<Product />} />
      </CrashlyticsRoutes>
    </BrowserRouter>
  );
}
```

### TanStack Router

If your app uses TanStack Router, initialize Crashlytics with
`getCrashlytics(app)` and attach default error recording directly inside
your router instance configuration (`defaultOnCatch`):

```typescript
import { recordError, getCrashlytics } from '@firebase/crashlytics';
import { app } from './lib/firebase'; // Shared initialization script

import { createRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';

const crashlytics = getCrashlytics(app);

const router = createRouter({
  routeTree,
  defaultOnCatch: (error, errorInfo) => {
    recordError(crashlytics, error, errorInfo);
  },
});
```

> [!NOTE]
> **Note:** Calling `getCrashlytics(app)` automatically registers global listeners for uncaught window errors and unhandled promise rejections, while `defaultOnCatch` captures errors caught during routing and component rendering within TanStack Router.

## *(Optional)* **Step 4**: Set up app versioning

Adding a clear version string to your web app builds is highly recommended so
you can isolate regressions to specific deployments. Pass `appVersion` in
`CrashlyticsOptions` when initializing the Crashlytics SDK for your
framework (using a release string or a build-time environment variable, such as
`process.env.NEXT_PUBLIC_APP_VERSION` or `import.meta.env.VITE_APP_VERSION`):

### Angular

Pass a `CrashlyticsOptions` object with `appVersion` as the second argument
to `provideCrashlytics` in `src/app/app.config.ts`:

```typescript
// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideCrashlytics } from '@firebase/crashlytics/angular';
import { app } from '../lib/firebase'; // Shared initialization script
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideCrashlytics(() => app, {
      appVersion: 'APP_VERSION'
    })
  ]
};
```

### Next.js

**Next.js 15.3+ (recommended): Client instrumentation
(`instrumentation-client.ts`)**

Pass a `CrashlyticsOptions` object with `appVersion` as the second argument
to `getCrashlytics` in `src/instrumentation-client.ts`:

```typescript
// src/instrumentation-client.ts
import { getCrashlytics } from '@firebase/crashlytics';
import { app } from './lib/firebase'; // Shared initialization script

getCrashlytics(app, {
  appVersion: 'APP_VERSION'
});
```

**Next.js \< 15.3: Client-side (App Router layout)**

Pass `crashlyticsOptions` with `appVersion` to `<FirebaseCrashlytics>` in
`src/components/CrashlyticsProvider.tsx`:

```tsx
// src/components/CrashlyticsProvider.tsx
'use client';

import React from 'react';
import { FirebaseCrashlytics } from '@firebase/crashlytics/react';
import { app } from '../lib/firebase'; // Shared initialization script

const crashlyticsOptions = {
  appVersion: 'APP_VERSION'
};

export function CrashlyticsProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <FirebaseCrashlytics
        firebaseApp={app}
        crashlyticsOptions={crashlyticsOptions}
      />
      {children}
    </>
  );
}
```

### React (without React Router)

Pass `crashlyticsOptions` with `appVersion` to `<FirebaseCrashlytics>` in
`src/App.tsx`:

```tsx
// src/App.tsx
import React from 'react';
import { FirebaseCrashlytics } from '@firebase/crashlytics/react';
import { app } from './lib/firebase'; // Shared initialization script

const crashlyticsOptions = {
  appVersion: 'APP_VERSION'
};

export default function App({
  children,
}: {
  children?: React.ReactNode;
}) {
  return (
    <FirebaseCrashlytics
      firebaseApp={app}
      crashlyticsOptions={crashlyticsOptions}
    >
      {children}
    </FirebaseCrashlytics>
  );
}
```

### React Router (v6+)

Pass `crashlyticsOptions` with `appVersion` to `<CrashlyticsRoutes>` in
`src/App.tsx`:

```tsx
// src/App.tsx
import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import { CrashlyticsRoutes } from '@firebase/crashlytics/react-router';
import { app } from './lib/firebase'; // Shared initialization script
import Home from './pages/Home';
import Profile from './pages/Profile';
import Product from './pages/Product';

const crashlyticsOptions = {
  appVersion: 'APP_VERSION'
};

export default function App() {
  return (
    <BrowserRouter>
      <CrashlyticsRoutes
        firebaseApp={app}
        crashlyticsOptions={crashlyticsOptions}
      >
        <Route path="/" element={<Home />} />
        <Route path="/profile/:userId" element={<Profile />} />
        <Route path="/product/:productId/details" element={<Product />} />
      </CrashlyticsRoutes>
    </BrowserRouter>
  );
}
```

### TanStack Router

Pass a `CrashlyticsOptions` object with `appVersion` as the second argument
to `getCrashlytics`:

```typescript
import { recordError, getCrashlytics } from '@firebase/crashlytics';
import { app } from './lib/firebase'; // Shared initialization script

import { createRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';

const crashlytics = getCrashlytics(app, {
  appVersion: 'APP_VERSION'
});

const router = createRouter({
  routeTree,
  defaultOnCatch: (error, errorInfo) => {
    recordError(crashlytics, error, errorInfo);
  },
});
```

## **Step 5**: Force a test crash

To finish setting up Crashlytics and see initial data in the
Crashlytics dashboard of the Firebase console, you need to force a
test crash.

1. Add code to your app that you can use to force a test crash.

   Add a test button or route trigger to your React, Next.js, or Angular app
   that throws a runtime error when clicked:

   ```typescript
   // Trigger an unhandled exception on button click or route load
   function handleTestCrash() {
     throw new Error("Crashlytics Web SDK Test Unhandled Error!");
   }
   ```

   If you configured automatic error capturing with `<FirebaseCrashlytics>`
   (React or Next.js), `provideCrashlytics` (Angular), or `<CrashlyticsRoutes>`
   (React Router), throwing this error automatically captures the exception and
   schedules it for upload.
2. Build and run your app, then trigger the test error so that your app sends
   its first crash report to Firebase.

3. In the Firebase console, go to the
   **DevOps \& Engagement** \> **[**Crashlytics** dashboard](https://console.firebase.google.com/project/_/crashlytics)**
   to check for your test crash report:

   1. Select your web app from the drop-down selector at the top of the page.

   2. Refresh the page. Your test exception should appear in the **Issues**
      table within a few minutes.

If you've refreshed the console and you're still not seeing the test crash after
five to ten minutes, see
[Troubleshooting your setup](https://firebase.google.com/docs/crashlytics/web/test-implementation.md.txt#troubleshooting-setup).

<br />

Crashlytics is now monitoring your web app for errors. Visit the
[**Crashlytics** dashboard](https://console.firebase.google.com/project/_/crashlytics) to view and investigate all your
reports and statistics.

## Next steps

- **[Get readable crash reports](https://firebase.google.com/docs/crashlytics/web/get-deobfuscated-reports.md.txt)** : Set up automatic source map (`.js.map`) uploading so your production stack traces display original filenames and line numbers.
- **[Customize crash reports](https://firebase.google.com/docs/crashlytics/web/customize-crash-reports.md.txt)**: Learn how to report handled exceptions, add custom keys, force flush telemetry records, and configure sampling.