Saltar al contenido principal
9 min de lectura

API de Datos en Tiempo Real

Accede a conteos de visitantes en vivo y datos de análisis en tiempo real a través de puntos finales JSON públicos. Estos puntos finales están diseñados para mostrar estadísticas en vivo en tu sitio web y no requieren autenticación.

Descripción General

Los puntos finales en tiempo real proporcionan:

  • Acceso instantáneo - No se requiere autenticación
  • Actualizaciones en vivo - Los datos se actualizan cada 5-30 segundos
  • Baja latencia - Servido desde la red perimetral global de Cloudflare
  • CORS habilitado - Seguro para llamar directamente desde navegadores

URL Base

Todos los puntos finales en tiempo real están disponibles en:

https://api.zenovay.com/e

Conteo de Visitantes en Vivo

Obtén el número actual de visitantes en tu sitio web:

GET/e/live/:trackingCode

Obtén el conteo de visitantes en vivo

SolicitudBash
curl -X GET 'https://api.zenovay.com/e/live/ZV_XXXXXXXXXXX'
Respuesta (200 OK)JSON
{
"liveCount": 42,
"timestamp": "2025-01-20T14:30:00Z"
}

Campos de Respuesta:

CampoTipoDescripción
liveCountnúmeroVisitantes actuales en línea (activos en los últimos 5 minutos)
timestampcadenaMarca de tiempo ISO 8601 de los datos

Análisis en Tiempo Real

Obtén análisis en tiempo real completos que incluyan visitantes, visualizaciones de página y datos geográficos:

GET/e/realtime/:websiteId

Obtén datos de análisis en tiempo real

SolicitudBash
curl -X GET 'https://api.zenovay.com/e/realtime/ws_abc123'
Respuesta (200 OK)JSON
{
"visitors": {
  "current": 42,
  "today": 1234,
  "change": 12.5
},
"pageViews": {
  "current": 156,
  "today": 4567,
  "change": 8.3
},
"countries": [
  { "code": "US", "name": "United States", "count": 18 },
  { "code": "GB", "name": "United Kingdom", "count": 8 },
  { "code": "DE", "name": "Germany", "count": 6 }
],
"topPages": [
  { "path": "/", "visitors": 15 },
  { "path": "/pricing", "visitors": 8 },
  { "path": "/features", "visitors": 5 }
],
"timestamp": "2025-01-20T14:30:00Z"
}

Campos de Respuesta:

CampoTipoDescripción
visitors.currentnúmeroVisitantes en línea ahora
visitors.todaynúmeroTotal de visitantes únicos hoy
visitors.changenúmeroCambio porcentual vs ayer
pageViews.currentnúmeroVisualizaciones de página en los últimos 5 minutos
pageViews.todaynúmeroTotal de visualizaciones de página hoy
countriesmatrizPaíses principales por visitantes actuales
topPagesmatrizPáginas principales por visitantes actuales

Estadísticas de Visitantes

Obtén estadísticas detalladas de visitantes que incluyan tasa de rebote y duración de la sesión:

GET/e/stats/:trackingCode

Obtén estadísticas de visitantes

SolicitudBash
curl -X GET 'https://api.zenovay.com/e/stats/ZV_XXXXXXXXXXX'
Respuesta (200 OK)JSON
{
"visitors": {
  "live": 42,
  "today": 1234,
  "week": 8765,
  "month": 34521
},
"bounceRate": 0.42,
"avgSessionDuration": 185,
"pagesPerSession": 2.9,
"newVisitorRate": 0.65,
"returningVisitorRate": 0.35,
"timestamp": "2025-01-20T14:30:00Z"
}

Campos de Respuesta:

CampoTipoDescripción
visitors.livenúmeroVisitantes actuales en línea
visitors.todaynúmeroVisitantes únicos hoy
visitors.weeknúmeroVisitantes únicos esta semana
visitors.monthnúmeroVisitantes únicos este mes
bounceRatenúmeroTasa de rebote (0-1)
avgSessionDurationnúmeroDuración promedio de sesión en segundos
pagesPerSessionnúmeroPromedio de páginas por sesión
newVisitorRatenúmeroPorcentaje de visitantes nuevos
returningVisitorRatenúmeroPorcentaje de visitantes recurrentes

Estado del Sitio Web

Verifica si el seguimiento está activo para un sitio web:

GET/e/:trackingCode/status

Verifica el estado de seguimiento

SolicitudBash
curl -X GET 'https://api.zenovay.com/e/ZV_XXXXXXXXXXX/status'
Respuesta (200 OK)JSON
{
"active": true,
"tracking_code": "ZV_XXXXXXXXXXX",
"domain": "example.com",
"last_event": "2025-01-20T14:29:55Z"
}

Integración de JavaScript

Contador de Visitantes en Vivo Básico

Muestra el conteo de visitantes en vivo en tu sitio web:

Contador de Visitantes en VivoJavaScript
class LiveVisitorCounter {
constructor(trackingCode, elementId) {
  this.trackingCode = trackingCode;
  this.element = document.getElementById(elementId);
  this.intervalId = null;
}

async fetchCount() {
  try {
    const response = await fetch(
      `https://api.zenovay.com/e/live/${this.trackingCode}`
    );
    const data = await response.json();
    this.updateDisplay(data.liveCount);
  } catch (error) {
    console.error('Failed to fetch visitor count:', error);
  }
}

updateDisplay(count) {
  if (this.element) {
    this.element.textContent = count.toLocaleString();
    this.element.classList.add('updated');
    setTimeout(() => this.element.classList.remove('updated'), 300);
  }
}

start(intervalMs = 30000) {
  this.fetchCount();
  this.intervalId = setInterval(() => this.fetchCount(), intervalMs);
}

stop() {
  if (this.intervalId) {
    clearInterval(this.intervalId);
  }
}
}

// Uso
const counter = new LiveVisitorCounter('ZV_XXXXXXXXXXX', 'visitor-count');
counter.start();

Panel de Control en Tiempo Real

Construye un panel de control de análisis mini:

Panel de Control en Tiempo RealJavaScript
async function updateDashboard(websiteId) {
try {
  const response = await fetch(
    `https://api.zenovay.com/e/realtime/${websiteId}`
  );
  const data = await response.json();

  // Update visitor counts
  document.getElementById('live-visitors').textContent = data.visitors.current;
  document.getElementById('today-visitors').textContent = data.visitors.today.toLocaleString();

  // Update pageviews
  document.getElementById('live-pageviews').textContent = data.pageViews.current;

  // Update top countries
  const countriesList = document.getElementById('top-countries');
  countriesList.innerHTML = data.countries
    .slice(0, 5)
    .map(c => `<li>${c.name}: ${c.count}</li>`)
    .join('');

  // Update top pages
  const pagesList = document.getElementById('top-pages');
  pagesList.innerHTML = data.topPages
    .slice(0, 5)
    .map(p => `<li>${p.path}: ${p.visitors}</li>`)
    .join('');

} catch (error) {
  console.error('Dashboard update failed:', error);
}
}

// Actualizar cada 30 segundos
setInterval(() => updateDashboard('ws_abc123'), 30000);
updateDashboard('ws_abc123');

Hook de React

Hook de React personalizado para datos en tiempo real:

Hook useRealtimeAnalyticsTSX
import { useState, useEffect, useCallback } from 'react';

interface RealtimeData {
visitors: {
  current: number;
  today: number;
  change: number;
};
pageViews: {
  current: number;
  today: number;
  change: number;
};
countries: Array<{ code: string; name: string; count: number }>;
topPages: Array<{ path: string; visitors: number }>;
timestamp: string;
}

function useRealtimeAnalytics(websiteId: string, refreshInterval = 30000) {
const [data, setData] = useState<RealtimeData | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);

const fetchData = useCallback(async () => {
  try {
    const response = await fetch(
      `https://api.zenovay.com/e/realtime/${websiteId}`
    );
    if (!response.ok) throw new Error('Failed to fetch');
    const json = await response.json();
    setData(json);
    setError(null);
  } catch (err) {
    setError(err instanceof Error ? err : new Error('Unknown error'));
  } finally {
    setLoading(false);
  }
}, [websiteId]);

useEffect(() => {
  fetchData();
  const interval = setInterval(fetchData, refreshInterval);
  return () => clearInterval(interval);
}, [fetchData, refreshInterval]);

return { data, loading, error, refetch: fetchData };
}

// Uso en componente
function AnalyticsDashboard({ websiteId }: { websiteId: string }) {
const { data, loading, error } = useRealtimeAnalytics(websiteId);

if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!data) return null;

return (
  <div className="dashboard">
    <div className="stat">
      <span className="label">Live Visitors</span>
      <span className="value">{data.visitors.current}</span>
    </div>
    <div className="stat">
      <span className="label">Today</span>
      <span className="value">{data.visitors.today.toLocaleString()}</span>
    </div>
  </div>
);
}

Composable de Vue

Composable de Vue 3 para datos en tiempo real:

Composable useRealtimeAnalyticsTypeScript
import { ref, onMounted, onUnmounted } from 'vue';

interface RealtimeData {
visitors: { current: number; today: number; change: number };
pageViews: { current: number; today: number; change: number };
countries: Array<{ code: string; name: string; count: number }>;
topPages: Array<{ path: string; visitors: number }>;
}

export function useRealtimeAnalytics(websiteId: string, refreshInterval = 30000) {
const data = ref<RealtimeData | null>(null);
const loading = ref(true);
const error = ref<Error | null>(null);
let intervalId: number | null = null;

async function fetchData() {
  try {
    const response = await fetch(
      `https://api.zenovay.com/e/realtime/${websiteId}`
    );
    if (!response.ok) throw new Error('Failed to fetch');
    data.value = await response.json();
    error.value = null;
  } catch (err) {
    error.value = err instanceof Error ? err : new Error('Unknown error');
  } finally {
    loading.value = false;
  }
}

onMounted(() => {
  fetchData();
  intervalId = window.setInterval(fetchData, refreshInterval);
});

onUnmounted(() => {
  if (intervalId) clearInterval(intervalId);
});

return { data, loading, error, refetch: fetchData };
}

Límites de Velocidad

Los puntos finales en tiempo real tienen los siguientes límites de velocidad:

Punto FinalLímite de VelocidadTTL de Caché
/e/live/:trackingCode1000 req/min5 segundos
/e/realtime/:websiteId500 req/min10 segundos
/e/stats/:trackingCode500 req/min30 segundos
/e/:trackingCode/status100 req/min60 segundos

Los datos se almacenan en caché en el borde. Múltiples solicitudes dentro del TTL de caché recibirán los mismos datos, lo que hace que sea seguro hacer encuestas frecuentes desde código del lado del cliente.

Configuración de CORS

Todos los puntos finales en tiempo real admiten CORS y se pueden llamar directamente desde navegadores:

Encabezados CORSTEXT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-Type

Manejo de Errores

Ejemplo de Manejo de ErroresJavaScript
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
  try {
    const response = await fetch(url);

    if (response.status === 429) {
      // Rate limited - wait and retry
      const retryAfter = response.headers.get('Retry-After') || '60';
      await new Promise(r => setTimeout(r, parseInt(retryAfter) * 1000));
      continue;
    }

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    if (i === maxRetries - 1) throw error;
    // Exponential backoff
    await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
  }
}
}

// Uso
try {
const data = await fetchWithRetry('https://api.zenovay.com/e/live/ZV_XXXXXXXXXXX');
console.log('Live visitors:', data.liveCount);
} catch (error) {
console.error('Failed after retries:', error);
}

Mejores Prácticas

  1. Almacena localmente en caché - Guarda los datos en memoria para evitar solicitudes innecesarias durante actualizaciones rápidas de la interfaz de usuario
  2. Debounce de actualizaciones - No actives actualizaciones de la interfaz de usuario más rápido que el TTL de caché
  3. Maneja sin conexión - Muestra datos obsoletos con una marca de tiempo cuando la red no esté disponible
  4. Anima cambios - Las transiciones suaves cuando los conteos cambian hacen que la interfaz de usuario se sienta más receptiva
  5. Muestra estados de carga - Muestra cargadores de esqueletos durante la búsqueda inicial

Próximos Pasos

¿Fue útil esta página?