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:
/e/live/:trackingCodeObtén el conteo de visitantes en vivo
curl -X GET 'https://api.zenovay.com/e/live/ZV_XXXXXXXXXXX'{
"liveCount": 42,
"timestamp": "2025-01-20T14:30:00Z"
}Campos de Respuesta:
| Campo | Tipo | Descripción |
|---|---|---|
liveCount | número | Visitantes actuales en línea (activos en los últimos 5 minutos) |
timestamp | cadena | Marca 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:
/e/realtime/:websiteIdObtén datos de análisis en tiempo real
curl -X GET 'https://api.zenovay.com/e/realtime/ws_abc123'{
"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:
| Campo | Tipo | Descripción |
|---|---|---|
visitors.current | número | Visitantes en línea ahora |
visitors.today | número | Total de visitantes únicos hoy |
visitors.change | número | Cambio porcentual vs ayer |
pageViews.current | número | Visualizaciones de página en los últimos 5 minutos |
pageViews.today | número | Total de visualizaciones de página hoy |
countries | matriz | Países principales por visitantes actuales |
topPages | matriz | Pá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:
/e/stats/:trackingCodeObtén estadísticas de visitantes
curl -X GET 'https://api.zenovay.com/e/stats/ZV_XXXXXXXXXXX'{
"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:
| Campo | Tipo | Descripción |
|---|---|---|
visitors.live | número | Visitantes actuales en línea |
visitors.today | número | Visitantes únicos hoy |
visitors.week | número | Visitantes únicos esta semana |
visitors.month | número | Visitantes únicos este mes |
bounceRate | número | Tasa de rebote (0-1) |
avgSessionDuration | número | Duración promedio de sesión en segundos |
pagesPerSession | número | Promedio de páginas por sesión |
newVisitorRate | número | Porcentaje de visitantes nuevos |
returningVisitorRate | número | Porcentaje de visitantes recurrentes |
Estado del Sitio Web
Verifica si el seguimiento está activo para un sitio web:
/e/:trackingCode/statusVerifica el estado de seguimiento
curl -X GET 'https://api.zenovay.com/e/ZV_XXXXXXXXXXX/status'{
"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:
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:
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:
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:
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 Final | Límite de Velocidad | TTL de Caché |
|---|---|---|
/e/live/:trackingCode | 1000 req/min | 5 segundos |
/e/realtime/:websiteId | 500 req/min | 10 segundos |
/e/stats/:trackingCode | 500 req/min | 30 segundos |
/e/:trackingCode/status | 100 req/min | 60 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:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-TypeManejo de Errores
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
- Almacena localmente en caché - Guarda los datos en memoria para evitar solicitudes innecesarias durante actualizaciones rápidas de la interfaz de usuario
- Debounce de actualizaciones - No actives actualizaciones de la interfaz de usuario más rápido que el TTL de caché
- Maneja sin conexión - Muestra datos obsoletos con una marca de tiempo cuando la red no esté disponible
- Anima cambios - Las transiciones suaves cuando los conteos cambian hacen que la interfaz de usuario se sienta más receptiva
- Muestra estados de carga - Muestra cargadores de esqueletos durante la búsqueda inicial
Próximos Pasos
- Widgets - Widgets incrustables pregenerados
- API Externa - API completa con autenticación
- Eventos Personalizados - Seguimiento de acciones de usuario personalizadas