# How to Integrate Bolt.new with Google Analytics 4

- Tool: Bolt.new
- Difficulty: Intermediate
- Time required: 15 minutes
- Last updated: April 2026

## TL;DR

To add Google Analytics 4 to your Bolt.new app, get a GA4 Measurement ID (starts with G-) from Google Analytics, then add the gtag.js script tag to your HTML head or install the GA4 npm integration. The script runs in the user's browser and works in both the Bolt WebContainer preview and production. Page view tracking is automatic once installed. Custom events require a single FullStory.gtag() function call.

## Google Analytics 4 in Bolt.new: Free Traffic and Conversion Analytics for Every App

Google Analytics 4 is the most widely used web analytics platform in the world, and it is completely free for standard use with no session or pageview limits. For any Bolt.new app you ship to real users, GA4 should be one of the first integrations you add — it tells you how users find your app (organic search, social, direct), what pages they visit, how long they stay, where they drop off, and whether they complete your key goals (signups, purchases, feature activations).

The integration is simpler than most analytics tools. GA4's core tracking mechanism is a client-side JavaScript snippet (gtag.js) that loads in the user's browser and automatically tracks page views and scroll depth. Because this script runs in the browser — not in Bolt's WebContainer server runtime — it works identically in the Bolt preview and in production. You do not need to deploy your app to start collecting analytics data. A Bolt app with the GA4 tag installed starts sending data to Google Analytics the moment someone visits it, whether they arrived via the preview URL or your production domain.

GA4 uses an event-based data model where every user interaction is an event. Google automatically collects a standard set of events (page_view, scroll, click, session_start) without any configuration. You can extend this with custom events for business-specific actions: signup_completed, checkout_started, subscription_upgraded. GA4's free tier includes unlimited data collection, 14 months of data retention for standard properties (2 months for default user and event data), and BigQuery export on a 360 property for enterprise usage.

## Before you start

- A Google account and a Google Analytics 4 property created at analytics.google.com (free)
- Your GA4 Measurement ID (format: G-XXXXXXXXXX) from Admin → Data Streams → Web Stream Details
- A Bolt.new project — Vite (React) or Next.js both work for the client-side tag
- For the GA4 Data API dashboard: a Next.js Bolt project, a Google Cloud project with Analytics Data API enabled, and a service account with Viewer access to your GA4 property

## Step-by-step guide

### 1. Create a GA4 Property and Get Your Measurement ID

Before adding the tag to your Bolt app, you need a Google Analytics 4 property. If you already have GA4 set up, skip to getting your Measurement ID. If starting fresh: go to analytics.google.com, click Admin (gear icon bottom-left), click 'Create Property', enter your app name, select your timezone and currency, choose your business size and objectives, and click 'Create'.

After creating the property, you need to create a Web data stream. In the Property column, click 'Data Streams', then 'Add stream', then 'Web'. Enter your app's URL (use your Bolt Cloud or Netlify domain — or put a placeholder if you haven't deployed yet) and a stream name. Click 'Create stream'.

You will see your Measurement ID at the top of the stream details page — it starts with 'G-' followed by letters and numbers (example: G-A1B2C3D4E5). Copy this ID. This is the only credential you need for client-side tracking. It is safe to expose in client-side code because it only identifies your analytics property — it cannot be used to write fake data at any significant scale, and it is visible in your website's HTML source code by design.

Note: GA4 data takes 24-48 hours to fully populate standard reports. The 'Realtime' report under Reports → Realtime shows immediate data from the last 30 minutes — use this to verify your tag is working right after installation.

```
<!-- index.html (Vite) — add to <head> -->
<!-- Replace G-XXXXXXXXXX with your Measurement ID -->
<script async src="https://www.googletagmanager.com/gtag/js?id=%VITE_GA_MEASUREMENT_ID%"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', '%VITE_GA_MEASUREMENT_ID%');
</script>

// For Vite: inject env variable into HTML via vite.config.ts
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  // Vite automatically replaces %VITE_*% in index.html
});
```

**Expected result:** The gtag.js script loads in your app's browser console without errors. Open the GA4 Realtime report and visit your Bolt preview URL — you should see yourself appear as an active user within 1-2 minutes.

### 2. Add GA4 to a Next.js Bolt App with Proper Script Loading

For Next.js Bolt projects, the integration approach differs slightly from plain HTML. Next.js manages the document head and provides the next/script component for optimized third-party script loading. Using next/script with strategy='afterInteractive' (or 'lazyOnload') ensures the GA4 script loads after the page becomes interactive, not blocking the first render.

In Next.js App Router (which Bolt uses by default), add the GA4 scripts to your root layout.tsx file. The root layout wraps all pages, so GA4 will initialize on every page load automatically. Use the Script component from next/script instead of plain script tags for better performance.

For page view tracking in a Next.js single-page app, you need to handle client-side navigation manually. The GA4 tag automatically tracks the first page load, but when users navigate between pages in a React app without a full browser reload, GA4 doesn't receive a new page_view event. You need to listen to route changes and fire a page_view event manually. In Next.js App Router, use the usePathname hook inside a client component to detect navigation and trigger GA4 page view events on each route change.

Create a separate GoogleAnalytics client component that handles both initialization and navigation tracking. Add this component to your root layout. This keeps the analytics logic isolated from your page components and makes it easy to disable or replace later.

```
// lib/gtag.ts
export const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID || '';

export function pageview(url: string) {
  if (!GA_MEASUREMENT_ID || typeof window === 'undefined') return;
  window.gtag('config', GA_MEASUREMENT_ID, { page_path: url });
}

export function event(
  action: string,
  params: Record<string, string | number | boolean> = {}
) {
  if (!GA_MEASUREMENT_ID || typeof window === 'undefined') return;
  window.gtag('event', action, params);
}

// Add to global TypeScript types
declare global {
  interface Window {
    gtag: (
      command: 'config' | 'event' | 'js' | 'set',
      targetId: string | Date,
      params?: Record<string, unknown>
    ) => void;
    dataLayer: unknown[];
  }
}

// components/GoogleAnalytics.tsx
'use client';

import Script from 'next/script';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react';
import { GA_MEASUREMENT_ID, pageview } from '@/lib/gtag';

export function GoogleAnalytics() {
  const pathname = usePathname();

  useEffect(() => {
    if (pathname) pageview(pathname);
  }, [pathname]);

  if (!GA_MEASUREMENT_ID) return null;

  return (
    <>
      <Script
        strategy="afterInteractive"
        src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
      />
      <Script
        id="google-analytics"
        strategy="afterInteractive"
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '${GA_MEASUREMENT_ID}', { page_path: window.location.pathname });
          `,
        }}
      />
    </>
  );
}
```

**Expected result:** The GA4 script loads after page interaction. Navigating between pages in your Next.js app fires page_view events for each route. Check GA4 Realtime → Pages to see each page view appear as you navigate.

### 3. Track Custom Events for Business Metrics

GA4's automatically collected events (page_view, scroll, click, first_visit, session_start) give you basic traffic analytics. To measure whether your app achieves its business goals, you need custom events that represent meaningful user actions. GA4's free custom event tracking has no limits — you can define up to 500 distinct event names per property.

GA4's event model uses a flat structure: each event has a name and optional parameters. Event names should be snake_case strings describing the action (sign_up, purchase, level_up, feature_enable). Parameters add context to events — for example, a purchase event includes currency, value, and items. GA4 has a set of recommended event names for common actions (sign_up, login, search, select_item, begin_checkout, purchase) that unlock pre-built reports in the GA4 dashboard. Use these recommended names when they match your action.

For conversion tracking, mark your most important events as 'Key Events' (formerly called Conversions) in GA4 Admin → Events → Key Events. This tells GA4 to track these events in conversion reports, goal completions, and the Conversions summary. Typical key events for a SaaS app: sign_up, purchase, trial_start.

Call window.gtag('event', eventName, params) directly, or use the event() helper from lib/gtag.ts to add TypeScript safety. Always call events from event handlers or useEffect hooks — never from the render function directly, as this would fire on every render.

```
// Usage examples throughout your app:
import { event } from '@/lib/gtag';

// After successful signup:
event('sign_up', { method: 'email' });

// When user clicks a pricing plan:
event('begin_checkout', {
  currency: 'USD',
  value: 29.00,
  coupon: '',
});

// After successful payment:
event('purchase', {
  transaction_id: invoiceId,
  value: 29.00,
  currency: 'USD',
  tax: 0,
  items: JSON.stringify([{ item_name: 'Pro Plan', item_id: 'plan_pro', price: 29.00 }]),
});

// When user searches:
event('search', { search_term: userQuery });

// When user enables a feature:
event('select_content', {
  content_type: 'feature',
  item_id: featureName,
});
```

**Expected result:** Custom events appear in GA4 Reports → Engagement → Events within a few hours. The Realtime report shows events as they fire during testing. Marked key events appear in Conversions reports.

### 4. Deploy and Verify GA4 in Production

GA4 works in the Bolt WebContainer preview for basic testing, but there are important differences between the preview environment and production that affect analytics accuracy. The Bolt preview URL (a browser-based WebContainer URL) may be sampled or filtered differently by GA4. More importantly, you want GA4 capturing data from your real deployed domain — the URL your actual users will visit.

Deploy your Bolt app to Netlify or Bolt Cloud to get a production URL. After deploying, add your production domain to the GA4 property's Web data stream: go to GA4 Admin → Data Streams → click your web stream → scroll to 'Enhance measurement' → verify the stream URL matches your deployed domain.

Set environment variables on your hosting platform before deploying. In Netlify: Site Settings → Environment Variables → add NEXT_PUBLIC_GA_MEASUREMENT_ID (for Next.js) or VITE_GA_MEASUREMENT_ID (for Vite) with your G- measurement ID. Trigger a redeploy after adding variables. Vite bakes environment variables into the bundle at build time — the variable must be set before the build runs.

Verify the integration using the GA4 DebugView. In GA4 Reports → Configure → DebugView, enable debug mode by adding ?debug_mode=1 to your app URL or by installing the Google Analytics Debugger Chrome extension. DebugView shows events in real-time with full parameter details, making it easy to confirm every event fires correctly before relying on the standard 24-hour reporting delay.

Note: Bolt's WebContainer has no mechanism to receive incoming requests from external services, so GA4 Measurement Protocol (server-to-server event sending) cannot be used in the WebContainer preview. It works fine after deploying to a standard Node.js environment where you can send server-side events via API routes.

```
// netlify.toml (for Next.js Bolt app)
[build]
  command = "npm run build"
  publish = ".next"

[build.environment]
  NODE_VERSION = "20"

[[plugins]]
  package = "@netlify/plugin-nextjs"

# Set these in Netlify Dashboard → Environment Variables:
# NEXT_PUBLIC_GA_MEASUREMENT_ID = G-XXXXXXXXXX

// netlify.toml (for Vite Bolt app)
[build]
  command = "npm run build"
  publish = "dist"

[build.environment]
  NODE_VERSION = "20"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200
```

**Expected result:** Your deployed app reports page views to GA4 on every navigation. GA4 Realtime shows users from your deployed domain. The DebugView shows custom events with correct parameters. Google Analytics begins populating standard reports within 24 hours.

### 5. Build a Custom Analytics Dashboard with the GA4 Data API

GA4's Data API (part of Google Analytics Data API v1) lets you run analytics queries programmatically and display the results in your own UI. This is useful for building internal analytics dashboards that show aggregated data without requiring team members to log into GA4, or for creating public 'transparency pages' showing your app's growth metrics.

The GA4 Data API uses Google Cloud service account authentication. You need a Google Cloud project with the Analytics Data API enabled, and a service account with at least Viewer access to your GA4 property. This authentication involves a JSON key file that must never reach the browser — call this API exclusively from a Next.js server-side API route.

The API accepts a request body specifying dimensions (what to group by: pagePath, deviceCategory, country, date) and metrics (what to measure: sessions, totalUsers, screenPageViews, conversions). The API returns rows of data matching your query. This data is suitable for rendering charts, tables, or summary cards in your admin dashboard.

An important architectural note: the GA4 Data API works fine after deploying to Netlify or Bolt Cloud because the API route runs server-side in a real Node.js environment. During Bolt WebContainer development, API routes that use the Google Cloud client SDK may encounter WebContainer's lack of TCP support — the googleapis npm package uses gRPC under the hood for some calls. If you encounter connection issues in the preview, use the HTTP-based REST approach (direct fetch to https://analyticsdata.googleapis.com) instead of the googleapis npm package, or test via a quick deploy to Netlify.

```
// app/api/analytics/overview/route.ts
import { NextResponse } from 'next/server';
import { BetaAnalyticsDataClient } from '@google-analytics/data';

export async function GET() {
  try {
    const credentials = JSON.parse(
      process.env.GOOGLE_SERVICE_ACCOUNT_JSON || '{}'
    );
    const propertyId = process.env.GA4_PROPERTY_ID;

    if (!propertyId || !credentials.client_email) {
      return NextResponse.json(
        { error: 'GA4 credentials not configured' },
        { status: 500 }
      );
    }

    const analyticsClient = new BetaAnalyticsDataClient({ credentials });

    const [response] = await analyticsClient.runReport({
      property: `properties/${propertyId}`,
      dateRanges: [{ startDate: '30daysAgo', endDate: 'today' }],
      dimensions: [{ name: 'pagePath' }],
      metrics: [
        { name: 'sessions' },
        { name: 'totalUsers' },
        { name: 'screenPageViews' },
      ],
      orderBys: [{ metric: { metricName: 'sessions' }, desc: true }],
      limit: 10,
    });

    const rows = response.rows?.map((row) => ({
      page: row.dimensionValues?.[0]?.value,
      sessions: row.metricValues?.[0]?.value,
      users: row.metricValues?.[1]?.value,
      views: row.metricValues?.[2]?.value,
    }));

    return NextResponse.json({ rows });
  } catch (error: unknown) {
    const e = error as { message: string };
    return NextResponse.json({ error: e.message }, { status: 500 });
  }
}
```

**Expected result:** After deploying to Netlify with GOOGLE_SERVICE_ACCOUNT_JSON and GA4_PROPERTY_ID set, GET /api/analytics/overview returns the last 30 days of top pages data. The analytics dashboard component displays session counts and user numbers from your real GA4 property.

## Best practices

- Use NEXT_PUBLIC_GA_MEASUREMENT_ID or VITE_GA_MEASUREMENT_ID for your Measurement ID — it is safe to expose client-side since it is visible in your HTML source by design
- Load the gtag.js script with strategy='afterInteractive' in Next.js to avoid blocking First Contentful Paint and Core Web Vitals scores
- Track route changes manually in Next.js App Router using usePathname — GA4 only auto-tracks the initial page load in SPAs
- Mark your key business events (sign_up, purchase, trial_start) as Key Events in GA4 Admin → Events to unlock conversion reports
- Keep service account credentials (GOOGLE_SERVICE_ACCOUNT_JSON) server-side only — never use NEXT_PUBLIC_ prefix on sensitive Google Cloud credentials
- Use GA4's DebugView (visit your app with ?debug_mode=1) to verify events fire correctly during testing before waiting for 24-hour standard reporting
- Use GA4's recommended event names (sign_up, purchase, search, begin_checkout) rather than custom names when they fit — they unlock pre-built reports automatically

## Use cases

### Track Page Views and Traffic Sources for a New Bolt App

You just launched a Bolt app and want to understand how many people are visiting, where they come from (Google search, direct link, social media), and which pages they view most. Add the GA4 tag and start collecting traffic data immediately. GA4's Acquisition report shows traffic sources; the Pages report shows most-viewed content.

Prompt example:

```
Add Google Analytics 4 to my Bolt.new Vite React app. Create a lib/analytics.ts file that exports a pageview function and an event function using window.gtag. Add the GA4 script tags to my index.html head section using the Measurement ID from VITE_GA_MEASUREMENT_ID environment variable. The gtag.js script should load from https://www.googletagmanager.com/gtag/js?id= followed by the measurement ID. Add a .env entry with VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX as a placeholder.
```

### Track Conversion Events for a SaaS App

You have a Bolt SaaS app with a signup flow, a pricing page, and a checkout step. Track custom events at each funnel stage to measure conversion rates: how many visitors sign up, how many reach the pricing page, how many start checkout. Use GA4's Funnel Exploration report to visualize drop-off and identify where to improve the UX.

Prompt example:

```
Add custom GA4 event tracking to my React app's key conversion moments. I already have GA4 initialized with gtag. When a user completes signup, call gtag('event', 'sign_up', { method: authMethod }). When they view the pricing page, call gtag('event', 'view_item_list', { item_list_name: 'Pricing Plans' }). When they click a plan to start checkout, call gtag('event', 'begin_checkout', { currency: 'USD', value: price, items: [{ item_name: planName }] }). Add these calls in the appropriate React components and event handlers.
```

### Build a Custom Analytics Dashboard Using the GA4 Data API

Build an admin dashboard page inside your Bolt app that pulls live analytics data from GA4: total sessions this week, top pages by views, and new user count. This requires the GA4 Data API and a Google Cloud service account, called through a Next.js API route to keep credentials server-side.

Prompt example:

```
Create a Next.js API route at app/api/analytics/report/route.ts that fetches the last 7 days of data from the GA4 Data API. Use GOOGLE_APPLICATION_CREDENTIALS_JSON (a service account JSON as a string) and GA4_PROPERTY_ID environment variables. Return total sessions, total users, and top 5 pages by sessions. Create an AdminAnalytics React component that calls this endpoint and displays the data in a simple table.
```

## Troubleshooting

### GA4 Realtime shows no active users even after adding the script tag

Cause: The Measurement ID may be incorrect or missing from the script tag, the gtag.js script may have a loading error, or an ad blocker in the browser is blocking the Google Analytics request.

Solution: Open browser DevTools → Console and check for script errors. Check Network tab for requests to www.googletagmanager.com — if blocked (red), an extension is interfering. Temporarily disable browser extensions and reload. Verify the Measurement ID (G-XXXXXXXXXX) is exactly correct in your .env file. In GA4 Admin → Data Streams, confirm the stream is set to the correct website URL.

### Vite app: window.gtag is not a function / TypeError at runtime

Cause: The gtag script tag uses %VITE_GA_MEASUREMENT_ID% template syntax in index.html, but the variable is not being replaced because the app is running outside of Vite's build context, or the VITE_ prefix is missing from the environment variable name.

Solution: Ensure the environment variable name starts with VITE_ exactly: VITE_GA_MEASUREMENT_ID. Variables without the VITE_ prefix are not exposed to client-side Vite code. Check index.html for the correct %VITE_GA_MEASUREMENT_ID% placeholder syntax (percent signs, not ${}). Restart the Bolt dev server after editing .env.

```
# .env — correct:
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX

# index.html — correct syntax for Vite HTML template:
# <script async src="https://www.googletagmanager.com/gtag/js?id=%VITE_GA_MEASUREMENT_ID%"></script>
```

### GA4 Data API returns 403 Forbidden from the API route after deployment

Cause: The service account does not have Viewer access to the GA4 property, or the Analytics Data API is not enabled in the Google Cloud project associated with the service account.

Solution: In GA4 Admin → Property Access Management, click + Add Users and add your service account's email address (from the service account JSON, the client_email field) with the Viewer role. In Google Cloud Console → APIs & Services → Enabled APIs, ensure 'Google Analytics Data API' is enabled for your project.

### Page views in Next.js app only track the first page, not subsequent navigations

Cause: GA4's automatic page_view event fires on initial page load, but Next.js App Router uses client-side navigation (no full browser reload between pages), so GA4 doesn't detect subsequent page changes.

Solution: Add the usePathname-based navigation listener to your GoogleAnalytics component as shown in Step 2. This detects route changes and fires a pageview event manually. Verify the component is mounted at the root layout level so it persists across all pages.

```
// In your GoogleAnalytics component:
const pathname = usePathname();
useEffect(() => {
  if (pathname) {
    window.gtag('config', GA_MEASUREMENT_ID, { page_path: pathname });
  }
}, [pathname]);
```

## Frequently asked questions

### Does Google Analytics 4 work in Bolt.new's WebContainer preview?

Yes. GA4's gtag.js script loads from Google's CDN and runs entirely in the user's browser — it does not depend on Bolt's WebContainer server runtime. The script fires analytics events over HTTPS directly to Google's servers. You can verify initialization works in the Bolt preview using the browser console and GA4 Realtime report.

### Is GA4 free? Are there any limits?

Google Analytics 4 standard is completely free with no pageview or session limits. The free tier retains event data for 2 months by default and up to 14 months if configured in Admin → Data Settings → Data Retention. GA4 360 (enterprise tier starting at around $150,000/year) adds BigQuery exports, higher sampling thresholds, and SLAs — not relevant for most Bolt apps.

### Does GA4 track events from the Bolt.new preview URL?

Yes, GA4 will receive events from the preview URL, but Bolt's WebContainer URLs are dynamic and change between sessions. For accurate production analytics, deploy to Bolt Cloud or Netlify and verify your production domain matches the Web data stream URL in GA4 Admin. Use GA4's DebugView to test events during development without polluting production data.

### Can I use Google Tag Manager instead of adding gtag.js directly?

Yes. Google Tag Manager (GTM) is an alternative container tag that manages GA4 (and other scripts) through the GTM dashboard without code changes. Add the GTM container snippet to your Bolt app once, then manage all GA4 configuration in the GTM interface. GTM is recommended if you need multiple analytics and marketing tags — it centralizes tag management. For a simple GA4-only setup, direct gtag.js is simpler.

### How long does it take for GA4 data to appear in reports?

The GA4 Realtime report (Reports → Realtime) shows data within a few seconds of events firing, making it useful for testing. Standard reports (Acquisition, Engagement, Retention) process data with a 24-48 hour delay. BigQuery exports (GA4 360 only) have near-real-time streaming. For testing your integration, always use Realtime or DebugView — don't wait 24 hours to confirm your events are working.

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/google-analytics
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/google-analytics
