@repo/3p-vercel
Complete Vercel Analytics and Speed Insights integration. Web vitals, custom events, performance monitoring. Zero-config on Vercel deployments. Client, server, and React component support.
Quick Start
Add Vercel Analytics in 2 minutes:
pnpm add @repo/3p-vercelZero-config on Vercel, web vitals, custom events included. Skip to Quick Start →
Why @repo/3p-vercel?
Web vitals manually tracked with custom code. Performance monitoring duplicated across pages. Custom analytics setup for each project. No unified dashboard for Core Web Vitals. Speed Insights implemented differently per app.
@repo/3p-vercel solves this with zero-config analytics on Vercel, automatic web vitals tracking, and unified performance monitoring.
Production-ready with web vitals (LCP, FID, CLS, FCP, TTFB, INP), Speed Insights, custom events, and zero-config on Vercel deployments.
Use cases
- Web vitals tracking — Automatic LCP, FID, CLS, FCP, TTFB, INP monitoring
- Speed Insights — Script execution, React rendering, network timings
- Custom events — User actions, purchases, feature usage tracking
- Performance monitoring — Real user monitoring with Core Web Vitals dashboard
- E-commerce analytics — Product views, cart adds, purchases
How it works
@repo/3p-vercel provides React components for analytics:
// app/layout.tsx
import { Analytics } from "@repo/3p-vercel/analytics";
import { SpeedInsights } from "@repo/3p-vercel/speed-insights";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}
// Track custom events
import { reportEvent } from "@repo/3p-vercel/react";
function Button() {
const handleClick = () => {
reportEvent("button_clicked", { location: "header" });
};
return <button onClick={handleClick}>Click Me</button>;
}Uses @vercel/analytics for web analytics, @vercel/speed-insights for performance, and automatic data collection on Vercel deployments.
Key features
Zero-config — Works automatically on Vercel deployments
Web Vitals — LCP, FID, CLS, FCP, TTFB, INP tracking
Speed Insights — Script execution, React rendering timings
Custom events — Track user actions, purchases, features
Real user monitoring — Performance data from actual users
Dashboard — Unified view of all metrics in Vercel
Quick Start
1. Install the package
pnpm add @repo/3p-vercel2. Add Analytics components
import { Analytics } from "@repo/3p-vercel/analytics";
import { SpeedInsights } from "@repo/3p-vercel/speed-insights";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}3. Track custom events
"use client";
import { reportEvent } from "@repo/3p-vercel/react";
export function ProductCard({ product }) {
const handleView = () => {
reportEvent("product_viewed", {
product_id: product.id,
name: product.name,
price: product.price,
});
};
return <div onMouseEnter={handleView}>{product.name};
}4. Monitor web vitals
"use client";
import { useReportWebVitals } from "next/web-vitals";
import { reportEvent } from "@repo/3p-vercel/react";
export function WebVitalsMonitor() {
useReportWebVitals((metric) => {
const thresholds = { LCP: 2500, FID: 100, CLS: 0.1 };
if (metric.value > (thresholds[metric.name] || Infinity)) {
reportEvent("web_vital_exceeded", {
metric: metric.name,
value: metric.value
});
}
});
return null;
}That's it! View metrics in your Vercel Dashboard → Project → Analytics.
Production-only metrics
Some web vitals metrics only appear in production builds. Deploy to Vercel to see full data.
Technical Details
For Developers: Technical implementation details
Overview
| Property | Value |
|---|---|
| Location | packages/3p-vercel |
| Dependencies | @vercel/analytics, @vercel/speed-insights |
| Features | Web Vitals, Speed Insights, Custom Events, Page Analytics |
| Runtimes | Browser, Edge, Next.js |
| Setup | Zero-config (Vercel), minimal config (other hosts) |
Export Paths
| Path | Description |
|---|---|
@repo/3p-vercel | Main exports & utilities |
@repo/3p-vercel/adapter | Vercel adapter class |
@repo/3p-vercel/analytics | Web Analytics |
@repo/3p-vercel/speed-insights | Speed Insights |
@repo/3p-vercel/react | React components |
Web Vitals Tracking
Automatic Web Vitals
// Web Vitals automatically tracked:
// - LCP (Largest Contentful Paint)
// - FID (First Input Delay)
// - CLS (Cumulative Layout Shift)
// - FCP (First Contentful Paint)
// - TTFB (Time to First Byte)
// - INP (Interaction to Next Paint)
// View in Vercel Analytics Dashboard:
// Deployments → Analytics → Web VitalsMonitor Web Vitals Threshold
"use client";
import { useReportWebVitals } from "next/web-vitals";
import { reportEvent } from "@repo/3p-vercel/react";
export function WebVitalsMonitor() {
useReportWebVitals((metric) => {
// Highlight metrics that exceed thresholds
const thresholds = {
LCP: 2500, // 2.5 seconds
FID: 100, // 100 milliseconds
CLS: 0.1 // 0.1 score
};
if (metric.value > (thresholds[metric.name] || Infinity)) {
console.warn(`⚠️ ${metric.name} exceeded threshold:`, metric.value);
// Report to analytics
reportEvent("web_vital_exceeded", {
metric: metric.name,
value: metric.value,
threshold: thresholds[metric.name],
rating: metric.rating
});
}
});
return null;
}Speed Insights
Enable Speed Insights
// app/layout.tsx
import { SpeedInsights } from "@repo/3p-vercel/speed-insights";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
{/* Speed Insights tracks:
- Script execution times
- React rendering times
- Network request timings */}
<SpeedInsights />
</body>
</html>
);
}Custom Performance Marks
"use client";
export function PerformanceMonitor() {
const trackPerformance = (name, callback) => {
performance.mark(`${name}-start`);
const result = callback();
performance.mark(`${name}-end`);
performance.measure(name, `${name}-start`, `${name}-end`);
const measure = performance.getEntriesByName(name)[0];
console.log(`${name}: ${measure.duration.toFixed(2)}ms`);
return result;
};
const result = trackPerformance("expensive-calculation", () => {
return expensiveOperation();
});
return <div>{ result };
}Custom Events
Track User Actions
"use client";
import { reportEvent } from "@repo/3p-vercel/react";
export function EventTracking() {
const handleClick = () => {
// highlight-start
reportEvent("Button Clicked", {
button_id: "cta-primary",
location: "header",
timestamp: Date.now(),
});
// highlight-end
};
const handleFormSubmit = (e) => {
e.preventDefault();
reportEvent("Form Submitted", {
form_id: "newsletter-signup",
fields_count: 2,
validation_errors: 0,
});
};
const handlePageScroll = () => {
const scrollPercent = (window.scrollY / document.body.scrollHeight) * 100;
if (scrollPercent % 25 === 0) {
reportEvent("Page Scrolled", {
scroll_percent: scrollPercent,
page_url: window.location.href,
});
}
};
return (
<>
<button onClick={handleClick}>Click me</button>
<form onSubmit={handleFormSubmit}>
<input name="email" type="email" />
<button type="submit">Subscribe</button>
</form>
</>
);
}E-commerce Events
import { reportEvent } from "@repo/3p-vercel/react";
// Product viewed
reportEvent("Product Viewed", {
product_id: "prod_123",
product_name: "Premium Headphones",
category: "Electronics",
price: 199.99
});
// Added to cart
reportEvent("Add to Cart", {
product_id: "prod_123",
quantity: 1,
price: 199.99,
cart_total: 199.99
});
// Completed purchase
reportEvent("Purchase Completed", {
order_id: "ord_123",
total: 199.99,
items_count: 1,
payment_method: "credit_card"
});User Engagement
import { reportEvent } from "@repo/3p-vercel/react";
// Session started
reportEvent("Session Started", {
session_id: sessionId,
user_id: userId,
referrer: document.referrer
});
// Time on page
reportEvent("Page Time", {
page_url: pathname,
time_seconds: timeSpent,
engagement_level: timeSpent > 30 ? "high" : "low"
});
// Feature used
reportEvent("Feature Used", {
feature_name: "advanced_search",
duration_seconds: 45,
success: true
});Page Analytics
Track Page Views
"use client";
import { reportEvent } from "@repo/3p-vercel/react";
import { useEffect } from "react";
import { usePathname } from "next/navigation";
export function PageViewTracker() {
const pathname = usePathname();
useEffect(() => {
// highlight-start
reportEvent("Page View", {
page_path: pathname,
page_title: document.title,
referrer: document.referrer,
timestamp: Date.now()
});
// highlight-end
}, [pathname]);
return null;
}Track Dynamic Content
reportEvent("Content Loaded", {
content_type: "article",
content_id: "art_123",
load_time_ms: 1234,
image_count: 5
});Configuration
Environment Variables
# Vercel Analytics (auto-enabled on Vercel)
# No configuration needed!
# For non-Vercel deployments:
NEXT_PUBLIC_VERCEL_ANALYTICS_ID=xxxxxxxxxxxxxAdvanced Setup
// app/layout.tsx
import { Analytics } from "@repo/3p-vercel/analytics";
import { SpeedInsights } from "@repo/3p-vercel/speed-insights";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
{/* Vercel Analytics */}
<Analytics
id={process.env.NEXT_PUBLIC_VERCEL_ANALYTICS_ID}
debug={process.env.NODE_ENV === "development"}
/>
{/* Speed Insights */}
<SpeedInsights />
</body>
</html>
);
}Performance Dashboard
Viewing Metrics
Navigate to:
- Vercel Dashboard → Project → Analytics
- View Web Vitals over time
- Track custom events
- Filter by page, device, browser
Key Metrics Dashboard
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | ≤2.5s | 2.5-4s | >4s |
| FID | ≤100ms | 100-300ms | >300ms |
| CLS | ≤0.1 | 0.1-0.25 | >0.25 |
| FCP | ≤1.8s | 1.8-3s | >3s |
| TTFB | ≤800ms | 800-1800ms | >1800ms |
Testing
Mock Vercel Analytics in Tests
import { vi } from "vitest";
vi.mock("@repo/3p-vercel/react", () => ({
reportEvent: vi.fn(),
}));
describe("Analytics", () => {
it("tracks events", () => {
const { reportEvent } = require("@repo/3p-vercel/react");
render(<Component />);
userEvent.click(screen.getByRole("button"));
expect(reportEvent).toHaveBeenCalled();
});
});Troubleshooting
Metrics Not Appearing
# 1. Check if on Vercel
# Go to vercel.com and check deployment
# 2. Verify Analytics component in layout
# Should be at root app/layout.tsx
# 3. Wait for data collection
# Analytics may take 5-10 minutes to appear
# 4. Check browser console for errorsWeb Vitals Not Tracking
// 1. Verify next/web-vitals is available
import { useReportWebVitals } from "next/web-vitals";
// 2. Check if page is interactive
// Web Vitals only tracked after user interaction
// 3. Test in production
// Some metrics only appear in production buildsCustom Events Not Showing
// 1. Verify reportEvent is imported correctly
import { reportEvent } from "@repo/3p-vercel/react";
// 2. Check event naming (use snake_case)
reportEvent("User Signed Up", {
/* ... */
}); // ❌
reportEvent("user_signed_up", {
/* ... */
}); // ✅
// 3. Verify events have properties
reportEvent("event_name", { property: "value" });Performance Optimization Tips
Improve Core Web Vitals
// 1. Optimize LCP
// - Use next/image for images
// - Preload critical resources
// - Minimize JavaScript
// 2. Improve FID
// - Break long tasks
// - Use requestIdleCallback for non-critical work
// - Optimize event handlers
// 3. Reduce CLS
// - Set dimensions on images
// - Avoid inserting content above existing content
// - Use font-display: swap for fontsMonitor Performance Regressions
useReportWebVitals((metric) => {
// Log poor performance
if (metric.rating === "poor") {
console.error(`Poor ${metric.name}: ${metric.value}ms`);
reportEvent("performance_issue", {
metric: metric.name,
value: metric.value
});
}
});Related Documentation
- @repo/3p-core - Core utilities and orchestration
- @repo/3p-posthog - PostHog integration
- @repo/3p-segment - Segment integration
- Integrations Overview - Complete integration guide