Skip to main content
Pro Plan10 minutesIntermediate

Real-Time Data Access

Build live dashboards on top of Zenovay - polling strategies, the External API, and where real-time data comes from.

apirealtimestreamingdeveloper
Last updated:

Pull analytics data from Zenovay to build your own dashboards and monitoring tools.

Zenovay doesn't expose a public WebSocket stream. The dashboard renders live visitor activity internally, but for your own integrations the supported pattern is polling the External API. This guide shows how to do that efficiently.

Info

The External API is a paid feature. It's available on Pro, Scale, and Enterprise plans — Free-tier keys are rejected with a 403 API_PAID_PLAN_REQUIRED. See Getting an API key.

Where real-time data lives

Use CaseBest Approach
Watch live visitors yourselfThe Live View tab in your dashboard (updates in real time)
Custom dashboardPoll the External API
Historical dataExternal API with a range filter
Embed a live visitor counter on your siteThe Widgets feature (a self-contained HTML widget)

For watching who's on your site right now, open your website's dashboard and select the Live View tab — it refreshes automatically. The sections below cover building your own external integration on top of the API.

External API Polling

For analytics data, use the External API with your API key. The base URL is:

https://api.zenovay.com/api/external/v1

Authenticate with either header:

X-API-Key: zv_YOUR_API_KEY
Authorization: Bearer zv_YOUR_API_KEY

Recent Analytics

The analytics summary endpoint accepts a range query parameter (24h, 7d, 30d, 90d, 1y — default 7d):

const API_KEY = process.env.ZENOVAY_API_KEY;
const WEBSITE_ID = 'your-website-id';

async function getRecentAnalytics() {
  const response = await fetch(
    `https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}?range=24h`,
    {
      headers: { 'X-API-Key': API_KEY }
    }
  );

  return await response.json();
}

Every External API response is wrapped in a { success, data, timestamp } envelope, and totals live under data.summary:

{
  "success": true,
  "data": {
    "summary": {
      "total_visitors": 1247,
      "total_page_views": 3891,
      "unique_visitors": 1102
    },
    "time_range": "24h",
    "daily_stats": [ /* ... */ ]
  },
  "timestamp": "2026-06-13T00:00:00.000Z"
}

Visitor Data

async function getVisitors() {
  const response = await fetch(
    `https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}/visitors`,
    {
      headers: { 'X-API-Key': API_KEY }
    }
  );

  return await response.json();
}

Inside the data envelope, this returns a visitors array plus a pagination object (limit, offset, has_more). Use the limit and offset query parameters to page through results.

Building a Custom Dashboard

React Example

import { useState, useEffect } from 'react';

function LiveDashboard({ websiteId, apiKey }) {
  const [analytics, setAnalytics] = useState(null);

  // Refresh the analytics summary on an interval that respects your rate limit
  useEffect(() => {
    async function fetchAnalytics() {
      try {
        const response = await fetch(
          `https://api.zenovay.com/api/external/v1/analytics/${websiteId}?range=24h`,
          {
            headers: { 'X-API-Key': apiKey }
          }
        );
        const body = await response.json();
        // Responses are wrapped in a { success, data, timestamp } envelope.
        setAnalytics(body.data);
      } catch (error) {
        console.error('Analytics fetch error:', error);
      }
    }

    fetchAnalytics();
    const interval = setInterval(fetchAnalytics, 5 * 60 * 1000);
    return () => clearInterval(interval);
  }, [websiteId, apiKey]);

  return (
    <div>
      {analytics && (
        <div>
          <h2>Last 24 hours</h2>
          <p>Visitors: {analytics.summary.total_visitors}</p>
          <p>Page Views: {analytics.summary.total_page_views}</p>
          <p>Unique Visitors: {analytics.summary.unique_visitors}</p>
        </div>
      )}
    </div>
  );
}

Rate Limit Considerations

External API rate limits are per API key, and the API is paid-only — the Free row is shown for completeness, but Free-tier keys cannot call it.

PlanRequests/MinuteRecommended Poll Interval
FreeNot available
Pro30Every 5 minutes
Scale60Every 2 minutes
Enterprise120Every minute

Responses include X-RateLimit-Limit and X-RateLimit-Remaining headers (on the fallback path), so you can read them and back off as you approach the limit.

Best Practices

  • Don't poll harder than your plan's rate limit allows — analytics data updates on the order of minutes, not seconds.
  • Cache responses locally between polls.
  • Implement error handling with exponential backoff.
  • For watching live visitors yourself, use the Live View tab rather than polling — it's built for that.

Next Steps

Was this article helpful?