Menu

Advanced Web Analytics Config with @vercel/analytics

Last updated March 4, 2025

To get started with analytics, follow our Quickstart guide which will walk you through the process of setting up analytics for your project.

Override the automatic environment detection.

pages/_app.tsx
import type { AppProps } from 'next/app';
import { Analytics } from '@vercel/analytics/next';
 
function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Analytics mode="production" />;
    </>
  );
}
 
export default MyApp;
pages/_app.jsx
import { Analytics } from '@vercel/analytics/next';
 
function MyApp({ Component, pageProps }) {
  return (
    <>
      <Component {...pageProps} />
      <Analytics mode="production" />;
    </>
  );
}
 
export default MyApp;
app/layout.tsx
import { Analytics } from '@vercel/analytics/next';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <title>Next.js</title>
      </head>
      <body>
        {children}
        <Analytics mode="production" />;
      </body>
    </html>
  );
}
app/layout.jsx
import { Analytics } from '@vercel/analytics/next';
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <title>Next.js</title>
      </head>
      <body>
        {children}
        <Analytics mode="production" />;
      </body>
    </html>
  );
}
App.tsx
import { Analytics } from '@vercel/analytics/react';
 
export default function App() {
  return (
    <div>
      {/* ... */}
      <Analytics mode="production" />
    </div>
  );
}
App.jsx
import { Analytics } from '@vercel/analytics/react';
 
export default function App() {
  return (
    <div>
      {/* ... */}
      <Analytics mode="production" />
    </div>
  );
}
app/root.tsx
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from '@remix-run/react';
import { Analytics } from '@vercel/analytics/remix';
 
export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Analytics mode="production" />
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}
app/root.jsx
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from '@remix-run/react';
import { Analytics } from '@vercel/analytics/remix';
 
export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Analytics mode="production" />
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}
src/layouts/Base.astro
---
import Analytics from '@vercel/analytics/astro';
{/* ... */}
---
 
<html lang="en">
	<head>
    <meta charset="utf-8" />
    <!-- ... -->
    <Analytics mode="production"/>
	</head>
	<body>
		<slot />
  </body>
</html>
src/layouts/Base.astro
---
import Analytics from '@vercel/analytics/astro';
{/* ... */}
---
 
<html lang="en">
	<head>
    <meta charset="utf-8" />
    <!-- ... -->
    <Analytics mode="production"/>
	</head>
	<body>
		<slot />
  </body>
</html>
app.vue
<script setup lang="ts">
import { Analytics } from '@vercel/analytics/nuxt';
</script>
 
<template>
  <Analytics mode="production"/>
  <NuxtPage />
</template>
app.vue
<script setup>
import { Analytics } from '@vercel/analytics/nuxt';
</script>
 
<template>
  <Analytics mode="production"/>
  <NuxtPage />
</template>
src/App.vue
<script setup lang="ts">
import { Analytics } from '@vercel/analytics/vue';
</script>
 
<template>
  <Analytics mode="production" />
  <!-- your content -->
</template>
src/App.vue
<script setup>
import { Analytics } from '@vercel/analytics/vue';
</script>
 
<template>
  <Analytics mode="production" />
  <!-- your content -->
</template>
src/routes/+layout.ts
import { dev } from '$app/environment';
import { injectAnalytics } from '@vercel/analytics/sveltekit';
 
injectAnalytics({ mode: dev ? 'development' : 'production' });
src/routes/+layout.js
import { dev } from '$app/environment';
import { injectAnalytics } from '@vercel/analytics/sveltekit';
 
injectAnalytics({ mode: dev ? 'development' : 'production' });
main.ts
import { inject } from '@vercel/analytics';
// import some helper that is exposed by your current framework to determine the right mode manually
import { dev } from '$app/environment';
 
inject({
  mode: dev ? 'development' : 'production',
});
main.js
import { inject } from '@vercel/analytics';
// import some helper that is exposed by your current framework to determine the right mode manually
import { dev } from '$app/environment';
 
inject({
  mode: dev ? 'development' : 'production',
});

You can manually disable it to prevent debug messages in your browsers console.

pages/_app.tsx
import type { AppProps } from 'next/app';
import { Analytics } from '@vercel/analytics/next';
 
function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Analytics debug />
    </>
  );
}
 
export default MyApp;
pages/_app.jsx
import { Analytics } from '@vercel/analytics/next';
 
function MyApp({ Component, pageProps }) {
  return (
    <>
      <Component {...pageProps} />
      <Analytics debug />
    </>
  );
}
 
export default MyApp;
app/layout.tsx
import { Analytics } from '@vercel/analytics/next';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <title>Next.js</title>
      </head>
      <body>
        {children}
        <Analytics debug />
      </body>
    </html>
  );
}
app/layout.jsx
import { Analytics } from '@vercel/analytics/next';
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <title>Next.js</title>
      </head>
      <body>
        {children}
        <Analytics debug />
      </body>
    </html>
  );
}
App.tsx
import { Analytics } from '@vercel/analytics/react';
 
export default function App() {
  return (
    <div>
      {/* ... */}
      <Analytics debug={true} />
    </div>
  );
}
App.jsx
import { Analytics } from '@vercel/analytics/react';
 
export default function App() {
  return (
    <div>
      {/* ... */}
      <Analytics debug={true} />
    </div>
  );
}
app/root.tsx
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from '@remix-run/react';
import { Analytics } from '@vercel/analytics/remix';
 
export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Analytics debug={true} />
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}
app/root.jsx
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from '@remix-run/react';
import { Analytics } from '@vercel/analytics/remix';
 
export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Analytics debug={true} />
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}
src/layouts/Base.astro
---
import Analytics from '@vercel/analytics/astro';
{/* ... */}
---
 
<html lang="en">
	<head>
    <meta charset="utf-8" />
    <!-- ... -->
    <Analytics debug="true"/>
	</head>
	<body>
		<slot />
  </body>
</html>
src/layouts/Base.astro
---
import Analytics from '@vercel/analytics/astro';
{/* ... */}
---
 
<html lang="en">
	<head>
    <meta charset="utf-8" />
    <!-- ... -->
    <Analytics debug={true}/>
	</head>
	<body>
		<slot />
  </body>
</html>
app.vue
<script setup lang="ts">
import { Analytics } from '@vercel/analytics/nuxt';
</script>
 
<template>
  <Analytics debug="true"/>
  <NuxtPage />
</template>
app.vue
<script setup>
import { Analytics } from '@vercel/analytics/nuxt';
</script>
 
<template>
  <Analytics debug="true"/>
  <NuxtPage />
</template>
src/App.vue
<script setup lang="ts">
import { Analytics } from '@vercel/analytics/vue';
</script>
 
<template>
  <Analytics debug="true" />
  <!-- your content -->
</template>
src/App.vue
<script setup>
import { Analytics } from '@vercel/analytics/vue';
</script>
 
<template>
  <Analytics debug="true" />
  <!-- your content -->
</template>
src/routes/+layout.ts
import { injectAnalytics } from '@vercel/analytics/sveltekit';
 
injectAnalytics({ debug: true });
src/routes/+layout.js
import { dev } from '$app/environment';
 
injectAnalytics({ debug: true });
main.ts
import { inject } from '@vercel/analytics';
 
inject({
  debug: true,
});
main.js
import { inject } from '@vercel/analytics';
 
inject({
  debug: true,
});
index.html
<script defer src="https://cdn.vercel-insights.com/v1/script.debug.js"></script>
index.html
<script defer src="https://cdn.vercel-insights.com/v1/script.debug.js"></script>

With the beforeSend option, you can modify the event data before it's sent to Vercel. Below, you will see an example that ignores all events that have a /private inside the URL.

Returning null will ignore the event and no data will be sent. You can also modify the URL and check our docs about redacting sensitive data.

pages/_app.tsx
import type { AppProps } from 'next/app';
import { Analytics, type BeforeSendEvent } from '@vercel/analytics/next';
 
function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Analytics
        beforeSend={(event: BeforeSendEvent) => {
          if (event.url.includes('/private')) {
            return null;
          }
          return event;
        }}
      />
      ;
    </>
  );
}
 
export default MyApp;
pages/_app.jsx
import { Analytics } from '@vercel/analytics/next';
 
function MyApp({ Component, pageProps }) {
  return (
    <>
      <Component {...pageProps} />
      <Analytics
        beforeSend={(event) => {
          if (event.url.includes('/private')) {
            return null;
          }
          return event;
        }}
      />
      ;
    </>
  );
}
 
export default MyApp;
app/layout.tsx
import { Analytics, type BeforeSendEvent } from '@vercel/analytics/next';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <title>Next.js</title>
      </head>
      <body>
        {children}
        <Analytics
          beforeSend={(event: BeforeSendEvent) => {
            if (event.url.includes('/private')) {
              return null;
            }
            return event;
          }}
        />
      </body>
    </html>
  );
}
app/layout.jsx
import { Analytics } from '@vercel/analytics/next';
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <title>Next.js</title>
      </head>
      <body>
        {children}
        <Analytics
          beforeSend={(event) => {
            if (event.url.includes('/private')) {
              return null;
            }
            return event;
          }}
        />
      </body>
    </html>
  );
}
App.tsx
import { Analytics, type BeforeSendEvent } from '@vercel/analytics/react';
 
export default function App() {
  return (
    <div>
      {/* ... */}
      <Analytics
        beforeSend={(event: BeforeSendEvent) => {
          if (event.url.includes('/private')) {
            return null;
          }
          return event;
        }}
      />
    </div>
  );
}
App.jsx
import { Analytics } from '@vercel/analytics/react';
 
export default function App() {
  return (
    <div>
      {/* ... */}
      <Analytics
        beforeSend={(event) => {
          if (event.url.includes('/private')) {
            return null;
          }
          return event;
        }}
      />
    </div>
  );
}
app/root.tsx
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from '@remix-run/react';
import { Analytics, type BeforeSendEvent } from '@vercel/analytics/remix';
 
export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Analytics
          beforeSend={(event: BeforeSendEvent) => {
            if (event.url.includes('/private')) {
              return null;
            }
            return event;
          }}
        />
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}
app/root.jsx
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from '@remix-run/react';
import { Analytics } from '@vercel/analytics/remix';
 
export default function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Analytics
          beforeSend={(event: BeforeSendEvent) => {
            if (event.url.includes('/private')) {
              return null;
            }
            return event;
          }}
        />
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}
src/layouts/Base.astro
---
import Analytics from '@vercel/analytics/astro';
{/* ... */}
---
 
<script is:inline>
  function webAnalyticsBeforeSend(event){
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  }
</script>
 
<html lang="en">
	<head>
    <meta charset="utf-8" />
    <!-- ... -->
    <Analytics />
	</head>
	<body>
		<slot />
  </body>
</html>
src/layouts/Base.astro
---
import Analytics from '@vercel/analytics/astro';
{/* ... */}
---
 
<script is:inline>
  function webAnalyticsBeforeSend(event){
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  }
</script>
 
<html lang="en">
	<head>
    <meta charset="utf-8" />
    <!-- ... -->
    <Analytics />
	</head>
	<body>
		<slot />
  </body>
</html>
app.vue
<script setup lang="ts">
import { Analytics, type BeforeSendEvent } from '@vercel/analytics/nuxt';
 
const beforeSend = (event: BeforeSendEvent) => {
  if (event.url.includes('/private')) {
    return null;
  }
  return event
};
</script>
 
<template>
  <Analytics :before-send="beforeSend"/>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>
app.vue
<script setup>
import { Analytics } from '@vercel/analytics/nuxt';
 
const beforeSend = (event) => {
  if (event.url.includes('/private')) {
    return null;
  }
  return event
};
</script>
 
<template>
  <Analytics :before-send="beforeSend"/>
  <NuxtPage />
</template>
src/App.vue
<script setup lang="ts">
import { Analytics, type BeforeSendEvent } from '@vercel/analytics/nuxt';
 
const beforeSend = (event: BeforeSendEvent) => {
  if (event.url.includes('/private')) {
    return null;
  }
  return event
};
</script>
 
<template>
  <Analytics :before-send="beforeSend"/>
  <!-- your content -->
</template>
src/App.vue
<script setup>
import { Analytics } from '@vercel/analytics/nuxt';
 
const beforeSend = (event) => {
  if (event.url.includes('/private')) {
    return null;
  }
  return event
};
</script>
 
<template>
  <Analytics :before-send="beforeSend"/>
  <!-- your content -->
</template>
src/routes/+layout.ts
import {
  injectAnalytics,
  type BeforeSendEvent,
} from '@vercel/analytics/sveltekit';
 
injectAnalytics({
  beforeSend(event: BeforeSendEvent) {
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  },
});
src/routes/+layout.js
import { injectAnalytics } from '@vercel/analytics/sveltekit';
 
injectAnalytics({
  beforeSend(event) {
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  },
});
main.ts
import { inject, type BeforeSendEvent } from '@vercel/analytics';
 
inject({
  beforeSend: (event: BeforeSendEvent) => {
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  },
});
main.js
import { inject } from '@vercel/analytics';
 
inject({
  beforeSend: (event) => {
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  },
});
index.html
<script>
  window.va = function () {
    (window.vaq = window.vaq || []).push(arguments);
  };
  window.va('beforeSend', (event) => {
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  });
</script>
index.html
<script>
  window.va = function () {
    (window.vaq = window.vaq || []).push(arguments);
  };
  window.va('beforeSend', (event) => {
    if (event.url.includes('/private')) {
      return null;
    }
    return event;
  });
</script>

The endpoint option allows you to report the collected analytics to a different url than the default: https://yourdomain.com/_vercel/insights.

This is useful when deploying several projects under the same domain, as it allows you to keep each application isolated.

For example, when yourdomain.com is managed outside of Vercel:

  1. "alice-app" is deployed under yourdomain.com/alice/*, vercel alias is alice-app.vercel.sh
  2. "bob-app" is deployed under yourdomain.com/bob/*, vercel alias is bob-app.vercel.sh
  3. yourdomain.com/_vercel/* is routed to alice-app.vercel.sh

Both applications are sending their analytics to alice-app.vercel.sh. To restore the isolation, "bob-app" should use:

<Analytics endpoint="https://bob-app.vercel.sh/_vercel/insights" />

The scriptSrc option allows you to load the Web Analytics script from a different URL than the default one.

<Analytics scriptSrc="https://bob-app.vercel.sh/_vercel/insights/script.js" />

Was this helpful?

supported.