Skip to main content
Virent

Express Installation Guide

Last researched 2026-08-26

This is the canonical Virent installation guide for Express applications.

Research Notes#

  • Express middleware is registered with app.use() and runs in registration order.
  • Middleware should call next() unless it intentionally ends the request-response cycle.
  • Express has no fixed template system; Human Analytics belongs in the shared template or HTML partial used by the app.

Primary references:

  • https://expressjs.com/en/5x/guide/writing-middleware/

Human Analytics#

Add the script to your shared template.

HTML
<!-- views/layout.ejs, views/partials/head.ejs, or your shared template --><head>  <meta charset="utf-8" />  <script    defer    data-write-key="vha_pk_..."    src="https://app.virent.app/js/script.js"  ></script></head>

Best practices:

  • Add the script to the common layout used by all public pages.
  • If Express serves a React/Vue bundle, edit the static app index.html instead.
  • Use the npm SDK only in browser assets for custom events.
  • Update Helmet or reverse proxy CSP headers if present.

Verification:

  • Render a page and view source for the Virent script.
  • Open the page in a browser and check Network requests.
  • Refresh Human Analytics status.

Troubleshooting:

  • If only some pages track, identify additional layouts.
  • If CSP blocks Virent, update Helmet or proxy headers.
  • If custom event code runs on the server, move it into browser assets.

AI Analytics#

Set server environment values:

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

Register middleware before page routes.

TS
import type { NextFunction, Request, Response } from "express"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|Applebot|Bytespider|meta-externalagent|meta-webindexer|meta-externalfetcher|Amazonbot|DuckAssistBot|PetalBot|YouBot/iexport function virentCrawlerAnalytics(req: Request, res: Response, next: NextFunction) {  res.on("finish", () => {    const userAgent = req.get("user-agent") ?? ""    if (staticAssetPattern.test(req.path) || !aiCrawlerPattern.test(userAgent)) {      return    }    void 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: `${req.protocol}://${req.get("host")}${req.originalUrl}`,        host: req.get("host"),        path: req.path,        method: req.method,        referer: req.get("referer") ?? null,        userAgent,        statusCode: res.statusCode,        requestId: crypto.randomUUID(),        timestamp: new Date().toISOString(),      }),    }).catch((error) => {      console.error("Virent crawler analytics failed", error)    })  })  next()}app.use(virentCrawlerAnalytics)

Best practices:

  • Register before route handlers.
  • Send after finish so the final response status is available.
  • Skip static assets and health checks.
  • Node 18+ includes fetch; older runtimes need an HTTP client.

Verification:

SH
curl -A "GPTBot" https://your-domain.com/
  • Confirm Express logs the request and posts to Virent.
  • Refresh AI Analytics status.

Troubleshooting:

  • If no events arrive, confirm app.use(virentCrawlerAnalytics) runs before routes.
  • If static files are counted, add extension exclusions.
  • If fetch is undefined, upgrade Node or use the app's existing HTTP client.