ENPL Log in Start free
// Docs

Everything on one page.

Install

Add your site in the dashboard, then paste this into the <head> of every page. Replace the domain with yours.

<script defer data-domain="yoursite.com" src="https://annuora.com/v.js"></script>

WordPress: use a "header code" plugin or the theme header.php. Shopify, Webflow, Framer, Wix: the custom code / head field. Google Tag Manager: a Custom HTML tag on all pages.

Subdomains: add the root domain and use the same data-domain on every subdomain.

Single-page apps

React, Vue, Next, Nuxt, Svelte - nothing to do. The script hooks history.pushState and popstate. Hash routing? Add the data-hash attribute.

Events and revenue

visitant("Signup");
visitant("Signup", { props: { plan: "pro", source: "pricing" } });
visitant("Purchase", { revenue: { amount: 49.00, currency: "USD" } });

// calls made before the script loads
window.visitant = window.visitant || function(){ (visitant.q = visitant.q || []).push(arguments) };

Every event shows up immediately under "Goals and events". To get a conversion rate, add it as a goal in site settings. Goals can also be pages such as /thank-you or /blog/*.

No-code events

<a href="/signup" data-v-event="Signup CTA" data-v-prop-position="hero">Start</a>

Tracked automatically

  • Pageviews, entry and exit pages, sources, UTM campaigns, countries (from the time zone, never the IP), devices.
  • Outbound link clicks (Outbound Link: Click) and file downloads (File Download).
  • Engaged time (only while the tab is visible) and scroll depth.
  • Core Web Vitals: LCP, INP, CLS, TTFB.

AI crawlers (server snippet)

Crawlers do not run JavaScript, so you need one of these snippets. Your server key is in Settings - AI crawler tracking. Only requests that look like crawlers are sent - human traffic never leaves your server.

Save as wp-content/mu-plugins/visitant-bots.php. Works with page caching off or on (cached pages still hit PHP only on misses; for full coverage use the Cloudflare or nginx option).

<?php
/* Plugin Name: Visitant AI crawler tracking */
add_action('init', function () {
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
    if (!preg_match('/bot|crawl|spider|GPTBot|ChatGPT-User|OAI-SearchBot|Claude|anthropic|Perplexity|Google-|GoogleOther|Applebot|meta-external|Meta-WebIndexer|Amazonbot|Amzn-|Bytespider|CCBot|MistralAI|DuckAssist|YouBot|xAI|Grok|cohere|Diffbot|Kimi|Qwen|Manus|Firecrawl/i', $ua)) return;
    $body = json_encode(['ua' => $ua, 'path' => $_SERVER['REQUEST_URI'] ?? '/',
        'ip' => $_SERVER['REMOTE_ADDR'] ?? '', 'status' => 200]);
    wp_remote_post('https://annuora.com/api/bot', ['blocking' => false, 'timeout' => 1,
        'headers' => ['Content-Type' => 'application/json', 'X-Visitant-Key' => 'YOUR_SERVER_KEY'], 'body' => $body]);
});

Request format for your own integration:

POST https://annuora.com/api/bot
X-Visitant-Key: sk_...
Content-Type: application/json

[{"ua": "Mozilla/5.0 ... GPTBot/1.4", "path": "/blog/post", "ip": "20.171.0.1", "status": 200, "ts": 1790000000}]

How AI traffic is counted

  • Confirmed: an assistant referrer (chatgpt.com, perplexity.ai, claude.ai, gemini.google.com, copilot.microsoft.com and more), an app referrer (android-app://com.openai.chatgpt), or a utm_source/utm_medium the assistant added.
  • Likely: a text-fragment landing (#:~:text=) with no referrer or from Google - how AI answers and AI Overviews deep-link. Shown separately, never added to the confirmed number.
  • Agents: visits from AI-driven browsers that identify themselves (Signature-Agent header) and automated browsers (navigator.webdriver). Excluded from human numbers by default.

Excluding yourself

In the browser console on your site:

localStorage.visitant_ignore = "1"

Paths such as /admin/* can be excluded in site settings.

API

Generate a key under Account. Pro plan and up.

curl -H "Authorization: Bearer vt_..." \
  "https://annuora.com/api/v1/stats/yoursite.com?period=30d&dimension=source&timeseries=1&ai=1"

period    = day | yesterday | 7d | 30d | 90d | month | 12mo | custom (&from=2026-09-01&to=2026-09-24)
dimension = page | entry | exit | source | channel | referrer | utm_source | utm_medium | utm_campaign
            country | browser | os | device | event | ai_source | prop:<key>
f         = {"channel":"ai","country":"PL"}   (URL-encoded JSON; "!" negates, "~" contains)

Privacy model

No cookies and no identifiers in the browser. A visitor is hash(daily_salt, site, IP, user agent) truncated to 64 bits. The salt rotates daily and is deleted after 48 hours, so visits cannot be linked across days and the IP cannot be recovered. The IP is never stored; the country comes from the browser time zone.