OneApp Docs
PackagesIntegrations

@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-vercel

Zero-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-vercel

2. Add Analytics components

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>
  );
}

3. Track custom events

app/components/ProductCard.tsx
"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

app/components/WebVitalsMonitor.tsx
"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

PropertyValue
Locationpackages/3p-vercel
Dependencies@vercel/analytics, @vercel/speed-insights
FeaturesWeb Vitals, Speed Insights, Custom Events, Page Analytics
RuntimesBrowser, Edge, Next.js
SetupZero-config (Vercel), minimal config (other hosts)

Export Paths

PathDescription
@repo/3p-vercelMain exports & utilities
@repo/3p-vercel/adapterVercel adapter class
@repo/3p-vercel/analyticsWeb Analytics
@repo/3p-vercel/speed-insightsSpeed Insights
@repo/3p-vercel/reactReact 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 Vitals

Monitor 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=xxxxxxxxxxxxx

Advanced 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:

  1. Vercel Dashboard → Project → Analytics
  2. View Web Vitals over time
  3. Track custom events
  4. Filter by page, device, browser

Key Metrics Dashboard

MetricGoodNeeds ImprovementPoor
LCP≤2.5s2.5-4s>4s
FID≤100ms100-300ms>300ms
CLS≤0.10.1-0.25>0.25
FCP≤1.8s1.8-3s>3s
TTFB≤800ms800-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 errors

Web 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 builds

Custom 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 fonts

Monitor 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
    });
  }
});

External Resources

On this page