6分で読めます
リアルタイムデータAPI
公開JSONエンドポイントを通じてライブビジター数とリアルタイム分析データにアクセスします。これらのエンドポイントは、ウェブサイトでライブ統計を表示するために設計されており、認証は必要ありません。
概要
リアルタイムエンドポイントが提供するもの:
- 即座にアクセス可能 - 認証は不要です
- ライブアップデート - データは5~30秒ごとに更新されます
- 低レイテンシー - Cloudflareのグローバルエッジネットワークから配信されます
- CORS有効 - ブラウザから直接安全に呼び出せます
ベースURL
すべてのリアルタイムエンドポイントは以下で利用可能です:
https://api.zenovay.com/e
ライブビジター数
あなたのウェブサイト上の現在のビジター数を取得します:
GET
/e/live/:trackingCodeライブビジター数を取得
リクエストBash
curl -X GET 'https://api.zenovay.com/e/live/ZV_XXXXXXXXXXX'レスポンス (200 OK)JSON
{
"liveCount": 42,
"timestamp": "2025-01-20T14:30:00Z"
}レスポンスフィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
liveCount | number | 現在オンラインのビジター数(過去5分以内にアクティブ) |
timestamp | string | データのISO 8601タイムスタンプ |
リアルタイム分析
ビジター、ページビュー、地理的データを含む包括的なリアルタイム分析を取得します:
GET
/e/realtime/:websiteIdリアルタイム分析データを取得
リクエストBash
curl -X GET 'https://api.zenovay.com/e/realtime/ws_abc123'レスポンス (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"
}レスポンスフィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
visitors.current | number | 現在オンラインのビジター数 |
visitors.today | number | 本日のユニークビジター総数 |
visitors.change | number | 前日比の変化率(パーセンテージ) |
pageViews.current | number | 過去5分間のページビュー数 |
pageViews.today | number | 本日のページビュー総数 |
countries | array | 現在のビジター数上位の国 |
topPages | array | 現在のビジター数上位のページ |
ビジター統計
バウンスレートとセッション期間を含む詳細なビジター統計を取得します:
GET
/e/stats/:trackingCodeビジター統計を取得
リクエストBash
curl -X GET 'https://api.zenovay.com/e/stats/ZV_XXXXXXXXXXX'レスポンス (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"
}レスポンスフィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
visitors.live | number | 現在オンラインのビジター数 |
visitors.today | number | 本日のユニークビジター数 |
visitors.week | number | 今週のユニークビジター数 |
visitors.month | number | 今月のユニークビジター数 |
bounceRate | number | バウンスレート (0-1) |
avgSessionDuration | number | 平均セッション時間(秒) |
pagesPerSession | number | セッションあたりの平均ページ数 |
newVisitorRate | number | 新規ビジターの割合 |
returningVisitorRate | number | リターンビジターの割合 |
ウェブサイトのステータス
ウェブサイトのトラッキングが有効かどうかを確認します:
GET
/e/:trackingCode/statusトラッキングステータスを確認
リクエストBash
curl -X GET 'https://api.zenovay.com/e/ZV_XXXXXXXXXXX/status'レスポンス (200 OK)JSON
{
"active": true,
"tracking_code": "ZV_XXXXXXXXXXX",
"domain": "example.com",
"last_event": "2025-01-20T14:29:55Z"
}JavaScript統合
基本的なライブカウンター
ウェブサイトにライブビジター数を表示します:
ライブビジターカウンターJavaScript
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);
}
}
}
// 使用方法
const counter = new LiveVisitorCounter('ZV_XXXXXXXXXXX', 'visitor-count');
counter.start();リアルタイムダッシュボード
ミニ分析ダッシュボードを構築します:
リアルタイムダッシュボードJavaScript
async function updateDashboard(websiteId) {
try {
const response = await fetch(
`https://api.zenovay.com/e/realtime/${websiteId}`
);
const data = await response.json();
// ビジター数を更新
document.getElementById('live-visitors').textContent = data.visitors.current;
document.getElementById('today-visitors').textContent = data.visitors.today.toLocaleString();
// ページビュー数を更新
document.getElementById('live-pageviews').textContent = data.pageViews.current;
// 上位の国を更新
const countriesList = document.getElementById('top-countries');
countriesList.innerHTML = data.countries
.slice(0, 5)
.map(c => `<li>${c.name}: ${c.count}</li>`)
.join('');
// 上位のページを更新
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);
}
}
// 30秒ごとに更新
setInterval(() => updateDashboard('ws_abc123'), 30000);
updateDashboard('ws_abc123');React Hook
リアルタイムデータ用のカスタムReactフック:
useRealtimeAnalytics HookTSX
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 };
}
// コンポーネントでの使用方法
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>
);
}Vue Composable
リアルタイムデータ用のVue 3 Composable:
useRealtimeAnalytics ComposableTypeScript
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 };
}レート制限
リアルタイムエンドポイントには以下のレート制限があります:
| エンドポイント | レート制限 | キャッシュTTL |
|---|---|---|
/e/live/:trackingCode | 1000リクエスト/分 | 5秒 |
/e/realtime/:websiteId | 500リクエスト/分 | 10秒 |
/e/stats/:trackingCode | 500リクエスト/分 | 30秒 |
/e/:trackingCode/status | 100リクエスト/分 | 60秒 |
データはエッジでキャッシュされます。キャッシュTTL内の複数のリクエストは同じデータを受け取るため、クライアント側のコードから頻繁にポーリングすることが安全です。
CORS設定
すべてのリアルタイムエンドポイントはCORSをサポートしており、ブラウザから直接呼び出すことができます:
CORSヘッダーTEXT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-Typeエラーハンドリング
エラーハンドリングの例JavaScript
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url);
if (response.status === 429) {
// レート制限 - 待機して再試行
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;
// 指数バックオフ
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
}
}
}
// 使用方法
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);
}ベストプラクティス
- ローカルにキャッシュ - 高速なUI更新中の不要なリクエストを避けるため、メモリにデータを保存します
- 更新を遅延 - キャッシュTTLより速くUI更新をトリガーしないでください
- オフライン対応 - ネットワークが利用できない場合、タイムスタンプ付きの古いデータを表示します
- 変更をアニメーション化 - カウント変更時のスムーズなトランジションでUIがより反応的に感じられます
- 読み込み状態を表示 - 初期フェッチ中はスケルトンローダーを表示します
次のステップ
このページは役に立ちましたか?