Why GA4 × Antigravity?
After launching an app or web service, understanding where users drop off and which features they use most is essential for product growth. Google Analytics 4 (GA4) provides that insight — but implementing it correctly takes real effort.
With Antigravity (Google's AI IDE), you can dramatically accelerate GA4 implementation. This guide walks through everything from basic Next.js setup to custom event design, conversion tracking, and Firebase Analytics integration for mobile apps.
What you'll learn:
- Setting up GA4 with Antigravity in a Next.js project
- Designing custom events and building a type-safe analytics utility
- Automating conversion tracking
- Integrating Firebase Analytics for mobile apps
GA4 Fundamentals: What Changed from Universal Analytics
GA4 uses an event-based data model, which differs fundamentally from the session-and-pageview model of Universal Analytics (UA). Every interaction — clicks, scrolls, purchases — is recorded as an event.
Key changes:
- Event-based: All user interactions are treated uniformly as events
- Cross-platform: Manage web, iOS, and Android data in a single property
- BigQuery integration: Free export to BigQuery for advanced analysis
- Machine learning: Built-in predictive metrics (churn probability, revenue prediction)
Step 1: Provide GA4 Project Context to Antigravity
Before writing any code, set up project context so Antigravity generates the right implementation. Add this to your AGENTS.md (or .antigravity/rules.md):
## Analytics Requirements
- GA4 Measurement ID: G-XXXXXXXXXX
- Framework: Next.js 15 (App Router)
- Events to track:
- page_view (auto)
- button_click (custom)
- form_submit (custom)
- purchase (enhanced ecommerce)
- Conversion goals:
- form_submit → Lead
- purchase → RevenueThis context helps Antigravity generate code that fits your project's specific needs.
Step 2: Basic GA4 Setup for Next.js
Prompt Antigravity in chat:
Implement Google Analytics 4 in a Next.js 15 App Router project.
Measurement ID is G-XXXXXXXXXX.
- Create src/components/GoogleAnalytics.tsx
- Integrate it into layout.tsx
- Load using next/script with afterInteractive strategy
- Disable in development environment
Example of what Antigravity generates:
// src/components/GoogleAnalytics.tsx
import Script from "next/script";
interface GoogleAnalyticsProps {
measurementId: string;
}
export const GoogleAnalytics = ({ measurementId }: GoogleAnalyticsProps) => {
// Disable in development to avoid polluting analytics data
if (process.env.NODE_ENV !== "production") {
return null;
}
return (
<>
<Script
strategy="afterInteractive"
src={`https://www.googletagmanager.com/gtag/js?id=${measurementId}`}
/>
<Script
id="google-analytics"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${measurementId}', {
page_path: window.location.pathname,
send_page_view: false
});
`,
}}
/>
</>
);
};// src/app/layout.tsx (excerpt)
import { GoogleAnalytics } from "@/components/GoogleAnalytics";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<GoogleAnalytics measurementId={process.env.NEXT_PUBLIC_GA_ID!} />
</body>
</html>
);
}Environment variable: Add
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXXto.env.local. In production, configure this as an environment variable in Vercel, Cloudflare Workers, or your hosting platform.
Step 3: Auto-Generate a Type-Safe Analytics Utility
Ask Antigravity to build a reusable analytics utility:
Create a GA4 custom event utility in TypeScript:
- trackEvent(eventName, params): generic event sender
- trackButtonClick(buttonName, location): button click tracking
- trackFormSubmit(formName, success): form submission tracking
- trackPurchase(transactionId, value, currency): purchase event
- Ensure full type safety with GA4 standard parameter types
Generated utility:
// src/lib/analytics.ts
type GA4EventParams = {
[key: string]: string | number | boolean | undefined;
};
// Check if gtag exists before sending
const gtag = (...args: unknown[]) => {
if (typeof window !== "undefined" && "gtag" in window) {
(window as Window & { gtag: (...a: unknown[]) => void }).gtag(...args);
}
};
/** Generic event sender */
export const trackEvent = (eventName: string, params?: GA4EventParams) => {
gtag("event", eventName, params);
};
/**
* Track button clicks
* @param buttonName e.g. "sign_up_button"
* @param location e.g. "hero", "navbar"
*/
export const trackButtonClick = (buttonName: string, location: string) => {
trackEvent("button_click", {
button_name: buttonName,
button_location: location,
});
};
/**
* Track form submissions
* @param formName form identifier
* @param success whether submission succeeded
*/
export const trackFormSubmit = (formName: string, success: boolean) => {
trackEvent("form_submit", {
form_name: formName,
success: success,
});
};
/**
* Track purchase events (conversion measurement)
* @param transactionId order ID
* @param value purchase amount
* @param currency currency code, e.g. "USD"
*/
export const trackPurchase = (
transactionId: string,
value: number,
currency: string = "USD"
) => {
trackEvent("purchase", {
transaction_id: transactionId,
value: value,
currency: currency,
});
};Step 4: Page View Tracking for App Router
In Next.js App Router, you need to handle client-side navigation manually. Prompt Antigravity:
Implement GA4 page_view event tracking for Next.js App Router.
Create a custom hook using usePathname and useSearchParams.
// src/hooks/usePageView.ts
"use client";
import { usePathname, useSearchParams } from "next/navigation";
import { useEffect } from "react";
import { trackEvent } from "@/lib/analytics";
export const usePageView = () => {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
const url = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
trackEvent("page_view", {
page_path: url,
page_title: document.title,
});
}, [pathname, searchParams]);
};Wrap it in a Client Component with Suspense:
// src/components/PageViewTracker.tsx
"use client";
import { Suspense } from "react";
import { usePageView } from "@/hooks/usePageView";
const PageViewTrackerInner = () => {
usePageView();
return null;
};
// useSearchParams requires Suspense boundary
export const PageViewTracker = () => (
<Suspense fallback={null}>
<PageViewTrackerInner />
</Suspense>
);Step 5: Firebase Analytics for Mobile Apps
For iOS and Android apps, Firebase Analytics (GA4's mobile counterpart) is the standard solution. Ask Antigravity to help:
Integrate Firebase Analytics into a React Native app.
- Use @react-native-firebase/analytics
- Create shared event-sending utilities
- Support both iOS and Android
Firebase Analytics and GA4 share the same management interface, so you can unify web and mobile data in one property. For more on Firebase integration, check out Antigravity × Firebase Auto-Provisioning Guide.
Step 6: Automated Tests for Analytics Functions
Once implemented, verify your analytics work correctly. Ask Antigravity to write tests:
Write Vitest unit tests for the analytics.ts utility.
Include mocking for window.gtag.
// src/lib/__tests__/analytics.test.ts
import { describe, it, expect, vi, beforeEach } from "vitest";
import { trackEvent, trackButtonClick, trackPurchase } from "../analytics";
describe("GA4 Analytics Utils", () => {
let gtagMock: ReturnType<typeof vi.fn>;
beforeEach(() => {
gtagMock = vi.fn();
Object.defineProperty(window, "gtag", {
value: gtagMock,
writable: true,
});
});
it("trackEvent calls gtag with correct parameters", () => {
trackEvent("button_click", { button_name: "signup" });
expect(gtagMock).toHaveBeenCalledWith("event", "button_click", {
button_name: "signup",
});
});
it("trackButtonClick sends correct event", () => {
trackButtonClick("signup_button", "hero");
expect(gtagMock).toHaveBeenCalledWith("event", "button_click", {
button_name: "signup_button",
button_location: "hero",
});
});
it("trackPurchase sends purchase event", () => {
trackPurchase("order_123", 9.99, "USD");
expect(gtagMock).toHaveBeenCalledWith("event", "purchase", {
transaction_id: "order_123",
value: 9.99,
currency: "USD",
});
});
it("does not throw when gtag is unavailable", () => {
// @ts-expect-error delete window.gtag
delete window.gtag;
expect(() => trackEvent("test_event")).not.toThrow();
});
});Run it:
npx vitest run src/lib/__tests__/analytics.test.tsExpected output:
✓ src/lib/__tests__/analytics.test.ts (4)
✓ trackEvent calls gtag with correct parameters
✓ trackButtonClick sends correct event
✓ trackPurchase sends purchase event
✓ does not throw when gtag is unavailable
Test Files 1 passed (1)
Tests 4 passed (4)
Step 7: BigQuery Integration for Advanced Analysis
One of GA4's most powerful features is free BigQuery export. Antigravity can generate SQL queries for your analysis:
Write BigQuery SQL to analyze GA4 export data:
- Conversion rate by page over the last 30 days
- Average session duration by device type
- Funnel analysis: top_page → form_view → form_submit
Sample query generated by Antigravity:
-- Conversion rate by page (last 30 days)
SELECT
page_path,
COUNT(DISTINCT user_pseudo_id) AS total_users,
COUNTIF(event_name = 'form_submit') AS conversions,
ROUND(
COUNTIF(event_name = 'form_submit') * 100.0 / COUNT(DISTINCT user_pseudo_id),
2
) AS conversion_rate_pct
FROM
`your-project.analytics_XXXXXXX.events_*`
WHERE
_TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY))
AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())
GROUP BY page_path
ORDER BY total_users DESC
LIMIT 20;Looking back
Here's what we covered for Antigravity-powered GA4 integration:
Implementation flow: Add project context to AGENTS.md → Generate the GoogleAnalytics component → Build a type-safe event utility → Implement the page view tracking hook → Auto-generate test coverage.
Where Antigravity shines: Generating type-safe TypeScript code, automating test writing, and producing BigQuery analysis queries. The time savings are most significant when setting up a complete analytics stack from scratch.
Once your GA4 implementation is live, the real work begins — using the data to continuously improve your product. Data-driven iteration is one of the most valuable habits any developer can build, whether working solo or on a team.
If you want to pair GA4 with error monitoring for a complete observability stack, check out Antigravity × Sentry Error Monitoring Guide.