Skip to main content
Documentation

Vue Installation Guide

Last researched 2026-08-26

This is the canonical Virent installation guide for Vue single-page applications, especially Vue apps scaffolded with Vite.

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 Vue website.

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

Install two separate things:
1. Human Analytics (browser): Install pageview tracking in the Vite document and optionally add a Vue composable for events.
2. AI Crawler Analytics (server): Add crawler capture to the server, edge function, or reverse proxy in front of the Vue app.

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 script to the root index.html file used by Vite.
- Keep custom event helpers in a small composable or utility imported by components that need tracking.
- Use Vue Router navigation tests to verify route-change pageviews.

AI Crawler Analytics best practices:
- Capture AI crawler requests at the edge, CDN, reverse proxy, or backend that serves the Vue bundle.
- Never expose VIRENT_INGEST_SECRET through VITE_ variables or client-side Vue code.
- Skip static assets and only track document/page requests unless you intentionally need asset-level bot telemetry.

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 pnpm build and preview the built app.
- Open DevTools Network and verify /js/script.js loads.
- Refresh Human Analytics status after visiting the site.
- Request a Vue route with a crawler-like user agent.
- Confirm the edge/server layer posts to Virent once for the HTML route.
- Refresh AI Analytics installation status.

Research Notes#

  • The official Vue SPA setup uses Vite and a root index.html entry point.
  • Vue client code cannot capture AI crawlers that do not execute browser JavaScript.
  • AI Analytics belongs in Nuxt, a backend, CDN worker, edge function, or reverse proxy when using plain Vue.

Primary references:

Human Analytics#

Add the Virent browser script to index.html.

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="app"></div>    <script type="module" src="/src/main.ts"></script>  </body></html>

Optional event helper:

SH
pnpm add @virent.app/sdk
TS
import { initVirent, trackGoal } from "@virent.app/sdk/browser"initVirent({ writeKey: import.meta.env.VITE_VIRENT_WRITE_KEY })export function trackSignupCompleted(orderId: string) {  return trackGoal({    name: "signup_completed",    idempotencyKey: orderId,  })}

Best practices:

  • Keep the pageview script in index.html.
  • Put event helpers in a composable or utility module.
  • Use only publishable keys in VITE_ variables.
  • Test Vue Router navigation after install.

Verification:

  • Build and preview the Vue app.
  • Inspect the document head for the Virent script.
  • Confirm pageview requests appear after route navigation.
  • Refresh Human Analytics status.

Troubleshooting:

  • If the script is absent, verify the correct index.html was edited.
  • If CSP blocks the script, allow the Virent origin.
  • If route changes are missed, confirm the Virent script loaded before testing navigation.

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#

Install AI Analytics outside the Vue browser bundle, in the host or backend layer.

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

Use the same edge/server pattern as React:

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:

  • Use Nuxt if you want framework-native server middleware.
  • Keep VIRENT_INGEST_SECRET out of Vue code.
  • Skip static files and only capture document/page requests by default.

Verification:

SH
curl -A "GPTBot" https://your-domain.com/
  • Confirm the edge/backend layer runs for the route.
  • Refresh AI Analytics status.

Troubleshooting:

  • If the app is static-only, install tracking in the host platform instead of Vue components.
  • If the secret leaks into the bundle, rotate it and remove all public references.
  • If events include built assets, add file extension exclusions.