Astro Installation Guide
Last researched 2026-08-26
This is the canonical Virent installation guide for Astro sites and applications.
Research Notes#
- Astro layouts are the preferred global HTML location for browser scripts.
- Astro middleware can intercept requests and responses for SSR or on-demand rendering.
- Fully static Astro output has no request-time middleware; AI Analytics must run at the hosting edge or reverse proxy in that case.
Primary references:
- https://docs.astro.build/en/guides/client-side-scripts/
- https://docs.astro.build/en/guides/middleware/
Human Analytics#
Add the Virent browser script to the shared layout that wraps all public pages.
TXT
---// src/layouts/BaseLayout.astro---<html lang="en"> <head> <script is:inline defer data-write-key="vha_pk_..." src="https://app.virent.app/js/script.js" ></script> </head> <body> <slot /> </body></html>Best practices:
- Use plain external script markup for the hosted Virent script.
- Do not wrap pageview tracking in a hydrated island.
- Confirm every public route uses the layout.
- Use client-side code only for optional custom event tracking.
Verification:
- Build and preview the Astro site.
- Inspect the rendered head and Network requests.
- Refresh Human Analytics status.
Troubleshooting:
- If the script is absent, confirm all routes use the edited layout.
- If CSP blocks the script, allow Virent in
script-srcandconnect-src. - If custom events do not fire, confirm event code runs in a client-side script or hydrated component.
AI Analytics#
For SSR or on-demand Astro deployments, use src/middleware.ts.
ENV
VIRENT_SITE_ID=site_...VIRENT_INGEST_SECRET=vha_sk_...VIRENT_INGEST_ENDPOINT=https://app.virent.app/v1/ingest/botTS
// src/middleware.tsimport type { MiddlewareHandler } from "astro"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 const onRequest: MiddlewareHandler = async (context, next) => { const response = await next() const userAgent = context.request.headers.get("user-agent") ?? "" if (!staticAssetPattern.test(context.url.pathname) && aiCrawlerPattern.test(userAgent)) { await fetch(import.meta.env.VIRENT_INGEST_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": import.meta.env.VIRENT_INGEST_SECRET, }, body: JSON.stringify({ siteId: import.meta.env.VIRENT_SITE_ID, url: context.url.toString(), host: context.url.host, path: context.url.pathname, method: context.request.method, referer: context.request.headers.get("referer"), userAgent, statusCode: response.status, requestId: crypto.randomUUID(), timestamp: new Date().toISOString(), }), }) } return response}Best practices:
- Use middleware only when the deployment has request-time rendering.
- Keep secrets in the server runtime, never in client islands.
- Await
next()before sending telemetry so the final status code is available.
Verification:
SH
curl -A "GPTBot" https://your-domain.com/- Confirm middleware runs in production.
- Refresh AI Analytics status.
Troubleshooting:
- If no crawler events arrive, verify the route is not fully prerendered static output.
- For static builds, move the same REST call to the hosting edge layer.
- If status codes are missing, ensure the middleware awaits
next().