# How to Track Screen Views in Firebase Analytics for Web Apps

- Tool: Firebase
- Difficulty: Beginner
- Time required: 10-15 min
- Compatibility: Firebase Analytics (web), firebase/analytics v9+ modular SDK, React Router v6+, Vue Router, any SPA framework
- Last updated: March 2026

## TL;DR

Firebase Analytics tracks page views automatically for traditional websites, but single-page applications need manual screen_view logging because the page does not reload on navigation. Call logEvent(analytics, 'screen_view', { firebase_screen, firebase_screen_class }) on every route change. In React, use a useEffect hook that listens to location changes from React Router. Verify events in the Firebase Console DebugView.

## Screen View Tracking for Single-Page Applications

Firebase Analytics automatically logs a page_view event when the page loads, but in SPAs, client-side routing changes the URL without triggering a full page load. This means Firebase only sees the initial page view, not subsequent navigation. This tutorial shows you how to log screen_view events on every route change so your analytics accurately reflect how users navigate your app.

## Before you start

- A Firebase project with Analytics enabled in the Firebase Console
- Firebase JS SDK initialized with getAnalytics() in your web app
- A single-page application using client-side routing (React Router, Vue Router, etc.)
- The measurementId from your Firebase config (starts with G-)

## Step-by-step guide

### 1. Understand automatic vs manual page view tracking

Firebase Analytics automatically tracks a page_view event on initial page load and when the browser history changes (popstate event). However, many SPA routers use pushState which does not always trigger the automatic event. Additionally, the automatic page_view only captures the URL path, not a meaningful screen name. Manual screen_view events give you full control over what is tracked and how it appears in reports.

```
// Automatic tracking (limited for SPAs):
// Firebase logs page_view on initial load with:
// - page_location: full URL
// - page_referrer: previous URL
// - page_title: document.title

// Manual tracking (recommended for SPAs):
// You log screen_view with custom parameters:
// - firebase_screen: human-readable screen name
// - firebase_screen_class: component or route name

// Disable automatic page_view if you want full manual control:
import { initializeAnalytics } from "firebase/analytics";

const analytics = initializeAnalytics(app, {
  config: {
    send_page_view: false, // Disable automatic page_view
  },
});
```

**Expected result:** You understand the difference between automatic page_view and manual screen_view, and can choose the approach that fits your app.

### 2. Create a screen tracking utility function

Build a reusable function that logs screen_view events with consistent parameters. Include firebase_screen (the human-readable screen name), firebase_screen_class (the component or route group), and optionally update the document title to match. This function will be called from your router integration.

```
import { getAnalytics, logEvent } from "firebase/analytics";

const analytics = getAnalytics();

export function trackScreenView(
  screenName: string,
  screenClass: string = "Page"
) {
  logEvent(analytics, "screen_view", {
    firebase_screen: screenName,
    firebase_screen_class: screenClass,
  });

  // Optionally update the document title for consistency
  document.title = `${screenName} | Your App Name`;
}

// Usage examples:
// trackScreenView("Home", "LandingPage");
// trackScreenView("User Profile", "ProfilePage");
// trackScreenView("Settings", "SettingsPage");
```

**Expected result:** A reusable trackScreenView function is ready to be called from your router on every navigation event.

### 3. Integrate with React Router v6

In React, use the useLocation hook from React Router inside a useEffect to detect route changes and log screen_view events. Create a component that wraps your app's routes and calls the tracking function whenever the pathname changes. Map route paths to human-readable screen names using a lookup object.

```
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { trackScreenView } from "./analytics";

// Map routes to screen names
const SCREEN_NAMES: Record<string, string> = {
  "/": "Home",
  "/dashboard": "Dashboard",
  "/profile": "User Profile",
  "/settings": "Settings",
  "/pricing": "Pricing",
};

function getScreenName(pathname: string): string {
  // Exact match
  if (SCREEN_NAMES[pathname]) return SCREEN_NAMES[pathname];

  // Dynamic routes: /posts/123 -> "Post Detail"
  if (pathname.startsWith("/posts/")) return "Post Detail";
  if (pathname.startsWith("/users/")) return "User Profile";

  return "Unknown Page";
}

export function AnalyticsTracker() {
  const location = useLocation();

  useEffect(() => {
    const screenName = getScreenName(location.pathname);
    trackScreenView(screenName, "WebApp");
  }, [location.pathname]);

  return null; // This component renders nothing
}

// In your App.tsx:
// <BrowserRouter>
//   <AnalyticsTracker />
//   <Routes>...</Routes>
// </BrowserRouter>
```

**Expected result:** Every route change in your React app logs a screen_view event with a descriptive screen name.

### 4. Integrate with Vue Router

For Vue apps, use the router's afterEach navigation guard to track screen views. This fires after every successful navigation, including programmatic navigations and back/forward button usage. Access the route meta or name to determine the screen name.

```
// router/index.ts
import { createRouter, createWebHistory } from "vue-router";
import { trackScreenView } from "@/analytics";

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: "/",
      name: "Home",
      component: () => import("@/views/Home.vue"),
      meta: { screenName: "Home" },
    },
    {
      path: "/dashboard",
      name: "Dashboard",
      component: () => import("@/views/Dashboard.vue"),
      meta: { screenName: "Dashboard" },
    },
    {
      path: "/settings",
      name: "Settings",
      component: () => import("@/views/Settings.vue"),
      meta: { screenName: "Settings" },
    },
  ],
});

// Track screen views on every navigation
router.afterEach((to) => {
  const screenName = (to.meta.screenName as string) || to.name?.toString() || "Unknown";
  trackScreenView(screenName, "VueApp");
});

export default router;
```

**Expected result:** Every route change in your Vue app logs a screen_view event using the screen name defined in the route's meta field.

### 5. Enable debug mode and verify in DebugView

Firebase Analytics events are batched and sent periodically, which means they do not appear in reports immediately (24-48 hour delay). To see events in real time during development, enable debug mode. Open the Firebase Console, navigate to Analytics > DebugView, and verify that screen_view events appear with the correct parameters as you navigate your app.

```
// Enable debug mode in the browser console:
// Open Chrome DevTools > Console and run:
// firebase.analytics().setAnalyticsCollectionEnabled(true);

// Or add the debug parameter to your URL:
// https://your-app.com/?debug_event=true

// Or install the GA Debugger Chrome extension
// and enable verbose mode

// For programmatic debug mode in development:
import { getAnalytics, setAnalyticsCollectionEnabled } from "firebase/analytics";

const analytics = getAnalytics();

if (process.env.NODE_ENV === "development") {
  // Events still appear in DebugView even in dev mode
  // as long as analytics is initialized
  console.log("Firebase Analytics debug mode active");
}

// Verify in Firebase Console:
// 1. Go to Analytics > DebugView
// 2. Select your debug device from the device list
// 3. Navigate through your app
// 4. screen_view events should appear in the timeline
// 5. Click each event to see firebase_screen parameter
```

**Expected result:** screen_view events appear in DebugView with the correct firebase_screen and firebase_screen_class parameters as you navigate your app.

### 6. View screen view reports in the Firebase Console

After events have been collected for 24-48 hours, view them in the Firebase Console. Navigate to Analytics > Events and find the screen_view event. Click it to see parameter breakdowns including which screens are viewed most. Use the Engagement > Pages and screens report for a dedicated screen-level view. Create custom audiences based on screen views to segment users by the features they use.

```
// Firebase Console reports for screen views:
//
// 1. Events report: Analytics > Events > screen_view
//    Shows total screen_view count over time
//
// 2. Pages and screens: Analytics > Engagement > Pages and screens
//    Groups by firebase_screen parameter
//    Shows: screen views, users, avg engagement time
//
// 3. Custom audience example:
//    Create an audience of users who viewed "Pricing" screen
//    Analytics > Audiences > New audience
//    Condition: screen_view where firebase_screen = "Pricing"
//
// 4. BigQuery export for advanced analysis:
//    Firebase Console > Project Settings > Integrations > BigQuery
//    Enable daily export, then query events_* tables:
//
// SELECT
//   event_params.value.string_value AS screen_name,
//   COUNT(*) AS views
// FROM `project.analytics_123.events_*`,
//   UNNEST(event_params) AS event_params
// WHERE event_name = 'screen_view'
//   AND event_params.key = 'firebase_screen'
// GROUP BY screen_name
// ORDER BY views DESC
```

**Expected result:** You can see which screens are viewed most, how long users spend on each screen, and create audiences based on screen view behavior.

## Complete code example

File: `analytics.ts`

```typescript
// Firebase Analytics — Screen View Tracking for SPAs
import { initializeApp } from "firebase/app";
import {
  initializeAnalytics,
  logEvent,
  getAnalytics,
} from "firebase/analytics";

const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "your-project.firebaseapp.com",
  projectId: "your-project",
  storageBucket: "your-project.appspot.com",
  messagingSenderId: "123456789",
  appId: "1:123456789:web:abc123",
  measurementId: "G-XXXXXXXXXX",
};

const app = initializeApp(firebaseConfig);

// Initialize with automatic page_view disabled (manual tracking)
const analytics = initializeAnalytics(app, {
  config: {
    send_page_view: false,
  },
});

// Track a screen view
export function trackScreenView(
  screenName: string,
  screenClass: string = "Page"
) {
  logEvent(analytics, "screen_view", {
    firebase_screen: screenName,
    firebase_screen_class: screenClass,
  });
  document.title = `${screenName} | YourApp`;
}

// Track a custom event alongside screen view
export function trackEvent(
  eventName: string,
  params: Record<string, string | number> = {}
) {
  logEvent(analytics, eventName, params);
}

// Route-to-screen-name mapping
const SCREEN_MAP: Record<string, string> = {
  "/": "Home",
  "/dashboard": "Dashboard",
  "/profile": "User Profile",
  "/settings": "Settings",
  "/pricing": "Pricing",
  "/login": "Login",
  "/signup": "Sign Up",
};

// Dynamic route matching
function matchDynamicRoute(path: string): string | null {
  if (/^\/posts\/[\w-]+$/.test(path)) return "Post Detail";
  if (/^\/users\/[\w-]+$/.test(path)) return "User Profile";
  if (/^\/projects\/[\w-]+$/.test(path)) return "Project Detail";
  return null;
}

// Get screen name from any path
export function getScreenName(pathname: string): string {
  return SCREEN_MAP[pathname]
    || matchDynamicRoute(pathname)
    || "Unknown Page";
}

// React integration component (separate file recommended)
// import { useEffect } from "react";
// import { useLocation } from "react-router-dom";
//
// export function AnalyticsTracker() {
//   const location = useLocation();
//   useEffect(() => {
//     const name = getScreenName(location.pathname);
//     trackScreenView(name, "WebApp");
//   }, [location.pathname]);
//   return null;
// }
```

## Common mistakes

- **Relying on automatic page_view tracking for SPAs, which only captures the initial page load and misses client-side route changes** — undefined Fix: Manually log screen_view events on every route change using your router's navigation hooks or a useEffect that watches the location.
- **Using URL paths as screen names, resulting in thousands of unique screen names from dynamic routes like /posts/abc123** — undefined Fix: Map URL patterns to descriptive screen names: /posts/:id becomes 'Post Detail', not '/posts/abc123'. Use a lookup table and regex matching for dynamic routes.
- **Expecting screen_view events to appear in Firebase Console reports immediately after logging them** — undefined Fix: Firebase Analytics has a 24-48 hour reporting delay. Use DebugView for real-time verification during development.
- **Logging screen_view inside a component that renders multiple times, causing duplicate events for the same navigation** — undefined Fix: Track screen views in a single location — a dedicated tracker component or router guard — not inside individual page components.

## Best practices

- Disable automatic page_view tracking (send_page_view: false) and use manual screen_view for full control in SPAs
- Use descriptive, human-readable screen names like 'User Profile' instead of raw URL paths
- Create a centralized route-to-screen-name mapping for consistency across your app
- Track screen views in one place (router hook or tracker component) to avoid duplicate events
- Use firebase_screen_class to group screens by type (e.g., 'Settings', 'Dashboard', 'Auth')
- Update document.title alongside screen_view events for consistent analytics and browser history
- Test with DebugView during development before relying on delayed reports
- Export to BigQuery for advanced screen flow analysis and custom funnel reports

## Frequently asked questions

### Does Firebase Analytics track page views automatically in SPAs?

Firebase Analytics tracks a page_view event on initial page load and sometimes on history.pushState changes. However, this is unreliable for SPAs. Manual screen_view tracking on every route change is the recommended approach.

### What is the difference between page_view and screen_view in Firebase Analytics?

page_view is automatically tracked and uses URL-based parameters (page_location, page_title). screen_view is manually tracked and uses firebase_screen and firebase_screen_class parameters that you define. For SPAs, screen_view gives you better control over naming.

### Why do my screen_view events not appear in Firebase Console reports?

Firebase Analytics has a 24-48 hour reporting delay. Use DebugView (Analytics > DebugView) for real-time verification during development. Install the Google Analytics Debugger Chrome extension for immediate event visibility.

### Can I track screen views without disabling automatic page_view?

Yes. Both can coexist. Automatic page_view events and manual screen_view events appear as separate events in your reports. Some teams keep both for redundancy.

### How do I track screen views in a Next.js app?

In Next.js App Router, create a client component that uses the usePathname hook from next/navigation inside a useEffect. Log the screen_view event when the pathname changes. Place the component inside your root layout.

### Is there a cost for logging screen_view events?

Firebase Analytics is free and has no per-event charges. You can log unlimited screen_view events. However, custom parameters are limited to 25 per event and 50 custom event-scoped dimensions per project.

### Can RapidDev help set up analytics tracking for my SPA?

Yes. RapidDev can implement a complete screen view tracking solution for your SPA, including router integration, screen name mapping, custom event tracking, DebugView verification, and BigQuery export for advanced analytics.

---

Source: https://www.rapidevelopers.com/firebase-tutorial/how-to-track-screen-views-in-firebase-for-web
© RapidDev — https://www.rapidevelopers.com/firebase-tutorial/how-to-track-screen-views-in-firebase-for-web
