Skip to main content
Documentation

React Installation Guide

Last researched 2026-08-26

This is the canonical Virent installation guide for React single-page applications, especially Vite-based React apps.

Install with your coding agent

Hand the install to Claude Code, Codex, Cursor or another coding agent. It reads this guide, asks for your keys and keeps the server secret out of client code.

Prompt
Install Virent analytics on my React website.

Read the canonical guide first and follow its code exactly:
https://virent.app/docs/installation/react.md

Install two separate things:
1. Human Analytics (browser): Install the pageview script in the Vite index.html head and optionally add the browser SDK for events.
2. AI Crawler Analytics (server): Add server-side capture to the host or backend in front of the React static build.

Values I will give you (they are in Virent under Settings > Connection):
- Publishable browser key, starts with vha_pk_. Safe in browser code.
- Site ID (VIRENT_SITE_ID) and server secret (VIRENT_INGEST_SECRET, starts with vha_sk_). Server only.
Ask me for them. Never invent a key or use a masked preview such as vha_sk_••••.

Human Analytics best practices:
- Add the browser script to index.html because Vite treats index.html as the app entry point.
- Use a literal publishable key in the script tag or a VITE_ public variable for SDK event code.
- Initialize the npm SDK only once if you also send custom product events.

AI Crawler Analytics best practices:
- Install AI Analytics at the edge, CDN, reverse proxy, or backend that serves the React app because crawler requests do not execute browser JavaScript.
- Keep the server secret in the edge/server runtime environment, not in VITE_ variables.
- Exclude static assets from crawler capture to avoid noisy events.

Rules:
- Keep VIRENT_INGEST_SECRET in server environment variables. Never put it in client code, public env variables (NEXT_PUBLIC_, VITE_, PUBLIC_) or committed files.
- Exclude API routes, static assets, images, favicons, robots.txt and sitemaps from crawler capture.
- If the site sends a Content-Security-Policy, allow https://app.virent.app in script-src and connect-src.
- Do not change unrelated code.

When you finish, list the files you changed and how I verify each path:
- Run a production preview and inspect the rendered head for the Virent script.
- Navigate between routes and confirm pageview requests are sent.
- Refresh Virent installation status after visiting the site.
- Request the deployed app with curl -A "GPTBot" https://your-domain.com/.
- Confirm the edge/backend logs one ingest attempt for the HTML route.
- Refresh Virent installation status and confirm AI Analytics receives crawler events.

Research Notes#

  • Vite treats index.html as source code and as the entry point for React applications.
  • React SPA code runs in the browser, so it cannot capture AI crawler requests that never execute JavaScript.
  • AI Analytics must be installed in the CDN, edge function, reverse proxy, or backend that serves the React build.

Primary references:

Human Analytics#

Add the Virent browser script to the root index.html file.

HTML
<!doctype html><html lang="en">  <head>    <meta charset="UTF-8" />    <script      defer      data-write-key="vha_pk_..."      src="https://app.virent.app/js/script.js"    ></script>  </head>  <body>    <div id="root"></div>    <script type="module" src="/src/main.tsx"></script>  </body></html>

Use the browser SDK for custom events.

SH
pnpm add @virent.app/sdk
TS
import { initVirent, trackEvent } from "@virent.app/sdk/browser"initVirent({ writeKey: import.meta.env.VITE_VIRENT_WRITE_KEY })await trackEvent({  name: "signup_started",  properties: { plan: "pro" },})

Best practices:

  • Put the script in index.html, not inside a React component.
  • Use VITE_ variables only for publishable browser values.
  • Keep custom tracking helpers in one small module and import them from components that need events.
  • Test React Router navigation after installation.

Verification:

  • Run a production build and preview it.
  • Inspect the rendered HTML for the Virent script.
  • Navigate across client routes and confirm pageview requests.
  • Refresh Virent installation status.

Troubleshooting:

  • If the script is missing, confirm the root index.html was edited.
  • If CSP blocks the script, allow the Virent origin in script-src and connect-src.
  • If local test traffic is needed, temporarily add data-allow-localhost="true".

Ad blockers and privacy tools often block third-party analytics hosts, which silently drops visits. Relay the script and events through your own domain under /_vr, and load the script with data-api="/_vr" so events go to your domain too. The relay must forward the visitor's IP and country in x-virent-forwarded-for and x-virent-forwarded-country, with your website's secret key (vha_sk_…) in x-virent-proxy-key; without the key Virent ignores the forwarded headers and sees your server's network instead of your visitors'. Relay only /_vr/js/script.js and /_vr/v1/*, and never forward cookies or authorization headers. See First-party analytics for how Virent trusts these headers.

With nginx, add these locations to the site's server block:

TXT
location = /_vr/js/script.js {  proxy_pass https://app.virent.app/js/script.js;  proxy_set_header Host app.virent.app;  proxy_ssl_server_name on;  proxy_set_header Cookie "";}location /_vr/v1/ {  proxy_pass https://app.virent.app/v1/;  proxy_set_header Host app.virent.app;  proxy_ssl_server_name on;  proxy_set_header Cookie "";  proxy_set_header Authorization "";  proxy_set_header X-Virent-Forwarded-For $remote_addr;  # Your website's secret key: Virent trusts the forwarded IP only with it.  proxy_set_header X-Virent-Proxy-Key "vha_sk_...";}

On Cloudflare, deploy a Worker on the example.com/_vr/* route that copies only accept-language, content-type, origin and user-agent, sets x-virent-forwarded-for from cf-connecting-ip, x-virent-forwarded-country from request.cf.country and x-virent-proxy-key from a Worker secret holding your website's secret key, and fetches the same path without /_vr from https://app.virent.app. The dashboard install panel has the full Worker.

Then load the script from your domain:

HTML
<script  defer  data-api="/_vr"  data-write-key="vha_pk_..."  src="/_vr/js/script.js"></script>

AI Analytics#

React itself is not the AI Analytics install point. Install crawler capture in the layer that serves the static React app.

ENV
VIRENT_SITE_ID=site_...VIRENT_INGEST_SECRET=vha_sk_...VIRENT_INGEST_ENDPOINT=https://app.virent.app/v1/ingest/bot

Generic edge/server example:

TS
const staticAssetPattern = /\.(?:png|jpg|jpeg|gif|svg|ico|webp|css|js|map|txt|xml)$/iconst aiCrawlerPattern = /GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|claudebot|Claude-Web|Claude-User|Claude-SearchBot|PerplexityBot|PerplexityBot\/|Perplexity-User|Perplexity-User\/|Google-CloudVertexBot|DeepSeekBot|DeepSeekSpider|CCBot|Bytespider|meta-externalagent|meta-webindexer|meta-externalfetcher|Amazonbot|DuckAssistBot|YouBot/iexport async function trackVirentCrawler(  request: Request,  response: Response,  waitUntil?: (promise: Promise<unknown>) => void) {  const url = new URL(request.url)  const userAgent = request.headers.get("user-agent") ?? ""  if (staticAssetPattern.test(url.pathname) || !aiCrawlerPattern.test(userAgent)) {    return  }  const report = fetch(process.env.VIRENT_INGEST_ENDPOINT!, {    method: "POST",    headers: {      "Content-Type": "application/json",      "x-api-key": process.env.VIRENT_INGEST_SECRET!,    },    body: JSON.stringify({      siteId: process.env.VIRENT_SITE_ID!,      url: url.toString(),      host: url.host,      path: url.pathname,      method: request.method,      referer: request.headers.get("referer"),      userAgent,      statusCode: response.status,      requestId: crypto.randomUUID(),      timestamp: new Date().toISOString(),    }),  })  if (waitUntil) {    waitUntil(report.catch(() => {}))    return  }  await report}

Best practices:

  • Prefer the provider-native guide in Virent's Connect your site dialog. If your host requires custom code, call this helper after it produces a Response and pass its waitUntil callback when available.
  • Do not expose VIRENT_INGEST_SECRET through VITE_ variables.
  • Exclude static assets to avoid noisy crawler events.

Verification:

SH
curl -A "GPTBot" https://your-domain.com/
  • Confirm the edge/backend layer posts to Virent once for the HTML route.
  • Refresh AI Analytics installation status.

Troubleshooting:

  • If no crawler events arrive, confirm the request actually reaches the server layer where tracking was installed.
  • If the secret appears in built assets, rotate the key and remove it from public env variables.
  • If asset events are counted, add extension exclusions.