| Select platform: | iOS+ Android Android NDK Web Flutter Unity |
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.
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.
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. 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 and Cloud 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
In the Firebase console, go to DevOps & Engagement > Crashlytics dashboard.
Select your web app from the drop-down selector at the top of the page.
Click Set up Crashlytics and follow the on-screen instructions.
Use the Firebase CLI
If you prefer configuring your project from the terminal or using an AI coding agent, you can use the Firebase CLI:
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.Run the following command to set up Crashlytics for your web app:
firebase crashlytics:setup \ --app FIREBASE_APP_ID \ --project PROJECT_IDThis 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, andclienttelemetry.googleapis.com).If your web app's API key has API restrictions, adds
clienttelemetry.googleapis.comto 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
Install the Crashlytics SDK:
npm install firebaseInitialize your
FirebaseAppinstance:Create a central configuration utility file to use singleton initialization. To find your Firebase app configuration values, go to your
Project settings > General page in the Firebase console, go to the Your apps card, and select your web app.// 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:
// 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)
]
};
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:
// 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:
// 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>:
// 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:
// 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:
// 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):
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);
},
});
(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:
// 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:
// 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:
// 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:
// 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:
// 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:
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.
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:
// 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.Build and run your app, then trigger the test error so that your app sends its first crash report to Firebase.
In the Firebase console, go to the DevOps & Engagement > Crashlytics dashboard to check for your test crash report:
Select your web app from the drop-down selector at the top of the page.
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.
Crashlytics is now monitoring your web app for errors. Visit the Crashlytics dashboard to view and investigate all your reports and statistics.
Next steps
- Get readable crash reports:
Set up automatic source map (
.js.map) uploading so your production stack traces display original filenames and line numbers. - Customize crash reports: Learn how to report handled exceptions, add custom keys, force flush telemetry records, and configure sampling.