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.
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.htmlas 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.
<!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.
pnpm add @virent.app/sdkimport { 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.htmlwas edited. - If CSP blocks the script, allow the Virent origin in
script-srcandconnect-src. - If local test traffic is needed, temporarily add
data-allow-localhost="true".
First-party (recommended)#
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:
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:
<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.
VIRENT_SITE_ID=site_...VIRENT_INGEST_SECRET=vha_sk_...VIRENT_INGEST_ENDPOINT=https://app.virent.app/v1/ingest/botGeneric edge/server example:
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
Responseand pass itswaitUntilcallback when available. - Do not expose
VIRENT_INGEST_SECRETthroughVITE_variables. - Exclude static assets to avoid noisy crawler events.
Verification:
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.