Implement comprehensive analytics in Google Antigravity with custom events and conversion tracking.
# Analytics and Tracking for Google Antigravity
Implement comprehensive analytics with custom events, page views, and conversion tracking.
## Analytics Provider
```typescript
// lib/analytics.ts
type EventProperties = Record<string, string | number | boolean>;
class Analytics {
private userId: string | null = null;
identify(userId: string, traits?: Record<string, unknown>) {
this.userId = userId;
if (typeof window !== "undefined" && (window as any).gtag) {
(window as any).gtag("set", "user_properties", { user_id: userId, ...traits });
}
}
track(event: string, properties?: EventProperties) {
if (typeof window === "undefined") return;
// Google Analytics
if ((window as any).gtag) {
(window as any).gtag("event", event, properties);
}
// Custom analytics endpoint
fetch("/api/analytics/track", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ event, properties, userId: this.userId, timestamp: Date.now() }),
}).catch(() => {});
}
page(name: string, properties?: EventProperties) {
this.track("page_view", { page_name: name, ...properties });
}
}
export const analytics = new Analytics();
```
## Analytics Hook
```typescript
// hooks/useAnalytics.ts
"use client";
import { useEffect } from "react";
import { usePathname, useSearchParams } from "next/navigation";
import { analytics } from "@/lib/analytics";
export function usePageTracking() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
analytics.page(pathname, { search: searchParams.toString() });
}, [pathname, searchParams]);
}
export function useTrackEvent() {
return (event: string, properties?: Record<string, string | number | boolean>) => {
analytics.track(event, properties);
};
}
```
## Event Database Schema
```sql
CREATE TABLE public.analytics_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
session_id TEXT,
event TEXT NOT NULL,
properties JSONB DEFAULT '{}'::jsonb,
page_url TEXT,
referrer TEXT,
user_agent TEXT,
ip_address INET,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_events_user ON public.analytics_events(user_id, created_at DESC);
CREATE INDEX idx_events_event ON public.analytics_events(event, created_at DESC);
CREATE INDEX idx_events_time ON public.analytics_events(created_at DESC);
```
## Analytics API Route
```typescript
// app/api/analytics/track/route.ts
import { NextRequest, NextResponse } from "next/server";
import { createClient } from "@/lib/supabase/server";
export async function POST(request: NextRequest) {
const { event, properties, userId } = await request.json();
const supabase = createClient();
await supabase.from("analytics_events").insert({
user_id: userId,
event,
properties,
page_url: request.headers.get("referer"),
user_agent: request.headers.get("user-agent"),
ip_address: request.ip,
});
return NextResponse.json({ success: true });
}
```
## Analytics Dashboard
```typescript
// app/admin/analytics/page.tsx
import { createClient } from "@/lib/supabase/server";
export default async function AnalyticsDashboard() {
const supabase = createClient();
const [pageViews, events, users] = await Promise.all([
supabase.from("analytics_events").select("*", { count: "exact", head: true }).eq("event", "page_view").gte("created_at", new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()),
supabase.from("analytics_events").select("event").gte("created_at", new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()),
supabase.from("analytics_events").select("user_id").gte("created_at", new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()).not("user_id", "is", null),
]);
const uniqueUsers = new Set(users.data?.map((u) => u.user_id)).size;
const eventCounts = events.data?.reduce((acc, e) => { acc[e.event] = (acc[e.event] || 0) + 1; return acc; }, {} as Record<string, number>);
return (
<div className="analytics-dashboard">
<h1>Analytics (Last 7 Days)</h1>
<div className="stats-grid">
<div className="stat-card"><h3>Page Views</h3><p>{pageViews.count}</p></div>
<div className="stat-card"><h3>Unique Users</h3><p>{uniqueUsers}</p></div>
<div className="stat-card"><h3>Total Events</h3><p>{events.data?.length}</p></div>
</div>
<h2>Top Events</h2>
<table>
<thead><tr><th>Event</th><th>Count</th></tr></thead>
<tbody>
{Object.entries(eventCounts || {}).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([event, count]) => (
<tr key={event}><td>{event}</td><td>{count}</td></tr>
))}
</tbody>
</table>
</div>
);
}
```
## Conversion Tracking
```typescript
// lib/conversions.ts
import { analytics } from "./analytics";
export const conversions = {
signUp: (method: string) => analytics.track("sign_up", { method }),
purchase: (value: number, currency = "USD", items: string[]) => analytics.track("purchase", { value, currency, items: items.join(",") }),
addToCart: (itemId: string, price: number) => analytics.track("add_to_cart", { item_id: itemId, price }),
subscribe: (plan: string, value: number) => analytics.track("subscribe", { plan, value }),
download: (fileName: string) => analytics.track("download", { file_name: fileName }),
share: (platform: string, contentId: string) => analytics.track("share", { platform, content_id: contentId }),
};
```
## A/B Testing Integration
```typescript
// lib/experiments.ts
import { analytics } from "./analytics";
export function getVariant(experimentId: string, userId: string): "control" | "treatment" {
const hash = hashString(`${experimentId}:${userId}`);
const variant = hash % 2 === 0 ? "control" : "treatment";
analytics.track("experiment_viewed", { experiment_id: experimentId, variant });
return variant;
}
function hashString(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash = hash & hash; }
return Math.abs(hash);
}
```
## Best Practices
1. **Privacy**: Respect user privacy and consent
2. **Batching**: Batch events to reduce API calls
3. **Sampling**: Sample high-volume events
4. **Retention**: Set data retention policies
5. **Anonymization**: Anonymize sensitive dataThis analytics prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their analytics implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For analytics projects, consider mentioning your framework version, coding style, and any specific libraries you're using.