Documentation

Add Analytics to Your Site

Drop-in analytics for any website. No cookies, no consent banners, fully GDPR-compliant. Takes under 2 minutes.

On this page
Installation Methods Configuration Options Tracking Pixel (Emails & No-JS) Verify It's Working Custom Events & Goals FOMO Widget Dashboard Widget Search Console Widget Privacy API Reference Bulk Stats API

Installation Methods

Choose the method that fits your stack. All three give you the same data in your dashboard.

Method 1
Script Tag
One line of HTML. Works everywhere.
Method 2
npm Package
For React, Vue, Next.js, and other JS apps.
Method 3
Tracking Pixel
For emails and no-JavaScript pages.

Basic Script Tag

Add this before the closing </head> or </body> tag. That's it — it auto-detects your domain and tracks pageviews immediately.

HTML
<script
  src="https://analytics.vnoc.com/tracker.js"
  defer
></script>

With Custom Domain Override

If your site serves multiple subdomains and you want all traffic grouped under one domain name, use data-domain:

HTML
<script
  src="https://analytics.vnoc.com/tracker.js"
  data-domain="yourdomain.com"
  defer
></script>

With Explicit Endpoint

If you're self-hosting or using a custom worker URL, set data-endpoint:

HTML
<script
  src="https://analytics.vnoc.com/tracker.js"
  data-endpoint="https://analytics.vnoc.com"
  data-domain="yourdomain.com"
  defer
></script>
What it tracks automatically

Pageviews, SPA route changes (pushState/popstate), referrer, screen size, language, country, device type, and browser. All without cookies.

Install

Shell
npm install vnoc-analytics

Initialize

Call init() once when your app loads. For React, put it in your root component or entry file. For Next.js, use _app.js.

JavaScript
import { init } from 'vnoc-analytics';

init({
  endpoint: 'https://analytics.vnoc.com',
});

With All Options

JavaScript
import { init } from 'vnoc-analytics';

init({
  endpoint:  'https://analytics.vnoc.com',  // Required
  domain:    'yourdomain.com',              // Override auto-detected domain
  autoTrack: true,                          // Track on init (default: true)
  trackSPA:  true,                          // Track route changes (default: true)
  honorDNT:  false,                         // Respect Do Not Track (default: false)
});

Manual Pageview Tracking

If you set autoTrack: false, you can fire pageviews manually:

JavaScript
import { init, trackPageview } from 'vnoc-analytics';

init({ endpoint: 'https://analytics.vnoc.com', autoTrack: false });

// Track when ready
trackPageview();

// Track a custom path
trackPageview({ path: '/virtual/thank-you' });

// Force re-track same path
trackPageview({ force: true });

Framework Examples

React (useEffect)

JSX
import { useEffect } from 'react';
import { init } from 'vnoc-analytics';

export default function App() {
  useEffect(() => {
    init({ endpoint: 'https://analytics.vnoc.com' });
  }, []);

  return <div>...</div>;
}

Next.js (_app.js)

JSX
import { useEffect } from 'react';
import { init } from 'vnoc-analytics';

export default function MyApp({ Component, pageProps }) {
  useEffect(() => {
    init({ endpoint: 'https://analytics.vnoc.com' });
  }, []);

  return <Component {...pageProps} />;
}

Vue 3 (main.js)

JavaScript
import { createApp } from 'vue';
import { init } from 'vnoc-analytics';
import App from './App.vue';

init({ endpoint: 'https://analytics.vnoc.com' });
createApp(App).mount('#app');

Tracking Pixel

For email newsletters, AMP pages, or environments where JavaScript can't run, embed a 1x1 transparent GIF:

HTML
<img
  src="https://analytics.vnoc.com/pixel.gif?d=yourdomain.com&p=/newsletter/may"
  width="1"
  height="1"
  alt=""
/>

Pixel URL Parameters

ParamDescriptionExample
dDomain nameyourdomain.com
pPage path/newsletter/may
rReferrer (optional)email

Generate Pixel URLs Programmatically

If you're using the npm package, you can generate pixel URLs:

JavaScript
import { init, pixelUrl } from 'vnoc-analytics';

init({ endpoint: 'https://analytics.vnoc.com' });

const url = pixelUrl('yourdomain.com', '/email/welcome');
// → https://analytics.vnoc.com/pixel.gif?d=yourdomain.com&p=%2Femail%2Fwelcome

Configuration Options

All options for the npm package init() function. The script tag only supports data-endpoint and data-domain.

OptionTypeDefaultDescription
endpointstringRequired. Your VNOC analytics worker URL.
domainstringlocation.hostnameOverride the auto-detected domain. Useful for grouping subdomains.
autoTrackbooleantrueAutomatically track a pageview when init() is called.
trackSPAbooleantrueTrack SPA route changes via History API (pushState, replaceState, popstate).
honorDNTbooleanfalseIf true, disables tracking when the browser's Do Not Track flag is set.

Tracking Pixel Details

The /pixel.gif endpoint returns a 1x1 transparent GIF and records a pageview from the query parameters. It works with GET requests, so it can be embedded as an <img> tag anywhere — email clients, AMP pages, RSS readers, or static HTML.

Note

The pixel tracks fewer details than the JavaScript tracker. It records domain, path, referrer, country, and device/browser from the User-Agent, but not screen size or language.

Verify It's Working

  1. 1 Add the tracker to your site using any method above and load a page.
  2. 2 Open your browser's Network tab (DevTools → Network). Look for a request to /collect with a 202 response. That means the hit was recorded.
  3. 3 Visit your dashboard at https://analytics.vnoc.com and sign in. Your domain should appear with at least 1 pageview.
  4. 4 Check real-time stats via the API: GET /api/stats/realtime?domain=yourdomain.com — it should show active_visitors: 1.
Not seeing data?

Make sure there are no ad blockers or content blockers interfering. Some block requests to /collect paths. You can verify by checking the browser console for errors.

Custom Events & Conversion Goals

Beyond pageviews, you can track custom events (signups, purchases, button clicks) and turn any event into a conversion goal — recorded with automatic traffic-source attribution on your dashboard.

Track a Custom Event

Once the tracker loads it exposes a global window.vnoc.track(). Call it whenever something meaningful happens. Signature: track(name, category, value)value is optional (use it for amounts).

JavaScript
window.vnoc.track("signup", "conversion");
window.vnoc.track("purchase", "revenue", "199");   // value = amount
Fire it safely

Guard the call so a tracking hiccup never breaks your flow, and make sure the tracker has loaded first. Fire conversion events at the moment of success (e.g. a purchase on your payment success / thank-you page) — this must run client-side; server-side webhooks can't reach window.vnoc.

JavaScript
try { window.vnoc?.track?.("purchase", "revenue", "199"); } catch (e) {}

Create a Conversion Goal

A goal maps an event (or a pageview path) to a named conversion. Once created, every matching hit is recorded as a conversion and attributed to its traffic source on /stats/yourdomain.com.

cURL
curl -X POST https://analytics.vnoc.com/api/goals   -H "Authorization: Bearer YOUR_API_KEY"   -H "Content-Type: application/json"   -d '{"domain":"yoursite.com","name":"Purchase","goal_type":"event","target":"purchase"}'

Fields: domain, name (label on the dashboard), goal_type"event" (fires on a custom event, target = the event name) or "pageview" (fires on a page visit, target = the path). List with GET /api/goals?domain=yoursite.com; remove with DELETE /api/goals?id=<id>.

Putting it together

1) Fire the event (window.vnoc.track("purchase", "revenue", "199"))  ·  2) Create a goal with target: "purchase"  ·  3) Conversions + source attribution appear on your stats dashboard automatically.

FOMO Widget

Show a floating live-stats badge on your site to build social proof and urgency. Displays active visitors, today's pageviews, and today's unique visitors in real time.

Live Preview

This is a live widget pulling real data from the analytics API right now. Try changing the settings below.

yourdomain.com
Your website preview

Quick Start

Add one script tag — the widget handles everything else:

HTML
<script
  src="https://analytics.vnoc.com/widget.js"
  data-domain="yourdomain.com"
  defer
></script>

Configuration Attributes

AttributeDefaultDescription
data-domainlocation.hostnameDomain to show stats for
data-positionbottom-leftbottom-left, bottom-right, top-left, or top-right
data-themedarkdark or light
data-labelonline nowCustom label text after the active count
data-endpointhttps://analytics.vnoc.comOverride if self-hosting

Placement Examples

HTML — Bottom-right, light theme
<script
  src="https://analytics.vnoc.com/widget.js"
  data-domain="yourdomain.com"
  data-position="bottom-right"
  data-theme="light"
  defer
></script>
HTML — Custom label
<script
  src="https://analytics.vnoc.com/widget.js"
  data-domain="yourdomain.com"
  data-label="browsing right now"
  defer
></script>
No auth required

The widget auto-refreshes every 30 seconds using the public /api/widget?domain=... endpoint — no API key needed.

Dashboard Widget

Embed a comprehensive analytics dashboard for any domain — or your entire portfolio. Includes KPI cards, traffic trends, top pages, referrers, countries, device/browser breakdown, and Cloudflare stats.

Live Example — linkagent.com

This is a live dashboard pulling real analytics data for linkagent.com right now:

Embed on Your Site

Single domain:

HTML
<iframe
  src="https://analytics.vnoc.com/embed/dashboard?domain=yourdomain.com"
  width="100%"
  height="900"
  frameborder="0"
></iframe>

Full portfolio overview (all domains):

HTML
<iframe
  src="https://analytics.vnoc.com/embed/dashboard"
  width="100%"
  height="1200"
  frameborder="0"
></iframe>

Options

ParameterDefaultDescription
domainFilter to a single domain. Omit for full portfolio.
themedarkdark or light
Auto-refresh

The dashboard widget refreshes every 60 seconds. No authentication needed — it uses the public /api/widget/overview endpoint.

Search Console Widget

Embed a Google Search Console dashboard for any verified domain. Shows clicks, impressions, CTR, average position, top search queries, top pages, and countries — all pulled from the GSC API automatically.

Live Example — agentmanager.com

This is a live widget pulling real GSC data for agentmanager.com:

Embed on Your Site

HTML
<iframe
  src="https://analytics.vnoc.com/embed/gsc?domain=yourdomain.com"
  width="100%"
  height="600"
  frameborder="0"
></iframe>

Options

ParameterDefaultDescription
domainRequired. The domain to show GSC data for.
themedarkdark or light

Light Theme

HTML
<iframe
  src="https://analytics.vnoc.com/embed/gsc?domain=yourdomain.com&theme=light"
  width="100%"
  height="600"
  frameborder="0"
></iframe>

Public API Endpoint

Fetch GSC data directly via the public API (no auth required):

Request
GET /api/widget/gsc?domain=yourdomain.com
Response
{
  "domain": "yourdomain.com",
  "clicks": 47,
  "impressions": 1250,
  "ctr": 3.76,
  "position": 18.4,
  "top_queries": [
    { "query": "your brand", "clicks": 12, "impressions": 340, "ctr": 3.5, "position": 8.2 }
  ],
  "top_pages": [
    { "page": "https://yourdomain.com/", "clicks": 30, "impressions": 800, "ctr": 3.8, "position": 12.1 }
  ],
  "top_countries": [
    { "country": "usa", "clicks": 25, "impressions": 600 }
  ],
  "period": "2026-05-25 to 2026-06-24",
  "updated_at": 1719200000
}
Auto-refresh

GSC data is refreshed daily via the Worker cron job. The widget caches responses for 5 minutes. No authentication needed for the public widget endpoint.

Privacy

VNOC Analytics is built to be privacy-friendly by default. No consent banner required.

FeatureDetails
CookiesNone. Zero cookies are set.
Visitor IDSHA-256 hash of IP + User-Agent + date + salt. Rotates daily — no cross-day tracking.
PIINo personal data is stored. IP addresses are never saved.
CountryDetected via Cloudflare's CF-IPCountry header. No GeoIP database.
GDPRCompliant. No consent banner needed since no personal data is collected or stored.

API Reference

Query analytics data programmatically for your dashboards, reports, or integrations.

Authentication

All API requests require a Bearer token in the Authorization header:

HTTP Header
Authorization: Bearer YOUR_API_KEY

Contact your administrator to get an API key, or use the same key you use to access the dashboard.

Base URL

URL
https://analytics.vnoc.com

Available Periods

PeriodDescription
24hLast 24 hours (hourly timeseries)
7dLast 7 days (daily timeseries)
30dLast 30 days (daily timeseries)
90dLast 90 days (daily timeseries)

Endpoints

GET /api/stats/realtime

Get active visitors in the last 5 minutes.

Request
GET /api/stats/realtime?domain=example.com
Response
{
  "domain": "example.com",
  "active_visitors": 12
}

GET /api/stats

Get overview stats with timeseries data for a domain.

Request
GET /api/stats?domain=example.com&period=7d
Response
{
  "domain": "example.com",
  "period": "7d",
  "pageviews": 1523,
  "unique_visitors": 487,
  "unique_pages": 15,
  "cf_requests": 8234,
  "source": "tracker",
  "timeseries": [
    { "date": "2026-06-03T00:00:00.000Z", "pageviews": 201, "unique_visitors": 65 },
    { "date": "2026-06-04T00:00:00.000Z", "pageviews": 245, "unique_visitors": 78 }
  ]
}

source indicates data origin: tracker (tracking script), cloudflare (CF zone analytics), or domain_meta (cached stats).

GET /api/stats/pages

Get top pages by pageviews.

Request
GET /api/stats/pages?domain=example.com&period=7d
Response
{
  "domain": "example.com",
  "pages": [
    { "path": "/", "pageviews": 523, "unique_visitors": 201 },
    { "path": "/pricing", "pageviews": 187, "unique_visitors": 142 }
  ]
}

GET /api/stats/referrers

Get top referrers by visits.

Request
GET /api/stats/referrers?domain=example.com&period=7d
Response
{
  "domain": "example.com",
  "referrers": [
    { "referrer": "google.com/search", "visits": 234 },
    { "referrer": "twitter.com", "visits": 87 }
  ]
}

GET /api/stats/countries

Get visitor breakdown by country.

Request
GET /api/stats/countries?domain=example.com&period=7d
Response
{
  "domain": "example.com",
  "countries": [
    { "country": "US", "visits": 412, "unique_visitors": 156 },
    { "country": "GB", "visits": 89, "unique_visitors": 34 }
  ]
}

GET /api/stats/devices

Get visitor breakdown by device type.

Request
GET /api/stats/devices?domain=example.com&period=7d
Response
{
  "domain": "example.com",
  "devices": [
    { "device": "desktop", "visits": 789 },
    { "device": "mobile", "visits": 234 },
    { "device": "tablet", "visits": 45 }
  ]
}

GET /api/stats/browsers

Get visitor breakdown by browser.

Request
GET /api/stats/browsers?domain=example.com&period=7d
Response
{
  "domain": "example.com",
  "browsers": [
    { "browser": "Chrome", "visits": 567 },
    { "browser": "Safari", "visits": 234 },
    { "browser": "Firefox", "visits": 89 }
  ]
}

Example: Fetch Stats (JavaScript)

JavaScript
const API_KEY = 'your-api-key';
const BASE_URL = 'https://analytics.vnoc.com';

async function fetchStats(domain, period = '30d') {
  const res = await fetch(
    `${BASE_URL}/api/stats?domain=${domain}&period=${period}`,
    { headers: { 'Authorization': `Bearer ${API_KEY}` } }
  );
  return res.json();
}

async function fetchRealtime(domain) {
  const res = await fetch(
    `${BASE_URL}/api/stats/realtime?domain=${domain}`,
    { headers: { 'Authorization': `Bearer ${API_KEY}` } }
  );
  return res.json();
}

// Usage
fetchStats('example.com', '7d').then(console.log);
fetchRealtime('example.com').then(console.log);

Example: Fetch Multiple Domains

JavaScript
const domains = ['site1.com', 'site2.com', 'site3.com'];

async function fetchAllStats() {
  const results = await Promise.all(
    domains.map(async (domain) => {
      const [stats, realtime] = await Promise.all([
        fetchStats(domain, '30d'),
        fetchRealtime(domain),
      ]);
      return { domain, ...stats, active: realtime.active_visitors };
    })
  );
  return results;
}

fetchAllStats().then(console.log);

Bulk Stats Endpoint

Fetch stats for up to 500 domains in a single request. Ideal for portfolio dashboards or domain list pages.

POST /api/bulk-stats

Returns 30-day pageviews, visitors, realtime counts, and Cloudflare data for multiple domains at once. Aggregates www and root domain stats automatically.

Request (POST)
POST /api/bulk-stats
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "domains": ["appserver.com", "partneragent.com", "betanetwork.com"]
}
Response
{
  "ts": 1718700000,
  "count": 3,
  "results": {
    "appserver.com": {
      "domain": "appserver.com",
      "status": "active",
      "zone_id": "abc123...",
      "realtime": 2,
      "today_pageviews": 156,
      "today_visitors": 43,
      "pageviews_30d": 1270,
      "visitors_30d": 266,
      "tracker_pageviews_30d": 45,
      "tracker_visitors_30d": 12,
      "cf_requests_30d": 99687,
      "cf_pageviews_30d": 1270,
      "cf_visitors_30d": 266,
      "dashboard_url": "https://analytics.vnoc.com/stats/appserver.com"
    }
  }
}

You can also use GET with comma-separated domains:

Request (GET)
GET /api/bulk-stats?domains=site1.com,site2.com,site3.com&key=YOUR_API_KEY

Response Fields

FieldDescription
statusCloudflare zone status (active, moved, unknown)
realtimeActive visitors in last 5 minutes
today_pageviewsPageviews today (tracker data)
today_visitorsUnique visitors today (tracker data)
pageviews_30dBest of tracker vs Cloudflare pageviews (30 days)
visitors_30dBest of tracker vs Cloudflare visitors (30 days)
tracker_pageviews_30dPageviews from tracking script only
tracker_visitors_30dVisitors from tracking script only
cf_requests_30dTotal Cloudflare requests (30 days)
cf_pageviews_30dCloudflare pageviews (30 days)
cf_visitors_30dCloudflare unique visitors (30 days)
dashboard_urlDirect link to the full analytics dashboard

Example: Load Domain List Page

For large domain lists (e.g. 34K domains), paginate with 500 domains per request:

JavaScript
const API_KEY = 'your-api-key';
const BATCH_SIZE = 500;

async function loadBulkStats(allDomains) {
  const results = {};
  for (let i = 0; i < allDomains.length; i += BATCH_SIZE) {
    const batch = allDomains.slice(i, i + BATCH_SIZE);
    const res = await fetch('https://analytics.vnoc.com/api/bulk-stats', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ domains: batch }),
    });
    const data = await res.json();
    Object.assign(results, data.results);
  }
  return results;
}

// 34K domains → 68 requests (~500ms each)
loadBulkStats(myDomainList).then(stats => {
  // Populate your table with stats[domain].pageviews_30d, etc.
});
Rate Limits

The API has no strict rate limits, but please be reasonable. For dashboards refreshing frequently, cache responses for at least 30 seconds. The bulk endpoint is designed for large domain lists — use it instead of individual requests.

Access Dashboard