分析イベントをバックエンドから直接 Zenovay に送信します。サーバーサイドトラッキングは広告ブロッカーの影響を受けず、サーバーでのみ発生するイベント(確認済みの購入、ウェブフック駆動のサブスクリプション)の記録を可能にし、送信内容を完全に制御できます。
サーバーサイドトラッキングを使う理由
メリット
| メリット | 説明 |
|---|---|
| 広告ブロッカー対策 | ブラウザでクライアントスクリプトがブロックされてもイベントは Zenovay に到達します |
| サーバーのみのイベント | サーバーでのみ発生することを追跡します — 確認済みの支払い、クーンジョブ、ウェブフック |
| データ制御 | 送信内容を完全に制御できます |
| ハイブリッドトラッキング | クライアントスクリプトと組み合わせてフル カバレッジを実現します |
使用場面
- e コマース購入確認(支払いプロバイダー確認後)
- バックエンドイベント(サブスクリプション作成、キャンセル)
- ウェブフック駆動型イベント(Stripe、支払いプロバイダー)
- ハイブリッドトラッキング(閲覧用クライアントスクリプト + 確認済み転換用サーバー)
トラッキングエンドポイント
サーバーサイドのリクエストはクライアントスクリプトと同じ取り込みエンドポイントを使用します。パスにウェブサイトのトラッキングコードを含めて、トラッキングエンドポイントに POST を送信します:
POST https://api.zenovay.com/e/{trackingCode}
これは公開、非認証エンドポイントです — API キーは必要ありません。すべてのプランで利用可能です(トラッキングスクリプトが送信するのと同じパスです)。トラッキングコードはインストールスニペットの data-tracking-code 属性に指定する値と同じです。
情報
取り込みエンドポイントはブラウザトラッカーと共有されているため、ペイロードはブラウザが送信するデータのように構成されています。つまり、ブラウザが自動的に入力するいくつかのフィールド — session_id、device_type、browser、os、user_agent — はサーバーから呼び出すときに JSON ボディで自分で指定する必要があります。これらが不足しているリクエストは拒否されます。
必須フィールド
送信するすべてのイベントは JSON ボディに次のフィールドを含める必要があります:
| フィールド | 説明 |
|---|---|
session_id | 最低 8 文字の文字列。同じ訪問に属するイベント用に同じ値を再利用します。 |
url | 完全で有効な URL(例:https://example.com/checkout/success)。 |
device_type | 例:desktop、mobile、tablet、server。 |
browser | ブラウザ/クライアント名。サーバートラフィック向けに説明的な内容を使用してください(例:server)。 |
os | OS 名(例:Linux)。 |
user_agent | ユーザーエージェント文字列。ボットのような汎用エージェントは避けてください(curl、python、wget など)— これらはボットとしてフィルタリングされます。 |
visitor_id はオプションですが推奨されます(≥8 文字)。これにより、繰り返されるイベントが同じ訪問者にリンクされます。
ページビュー vs. カスタムイベント
イベント種別は event_type フィールドで設定されます:
- ページビュー —
event_typeを省略(デフォルト)するかpageviewに設定します。 - カスタムイベント —
event_typeをcustomに設定し、イベント名をevent_nameに、メタデータをpropertiesに入れます。
# カスタムイベント(例:確認済みの購入)
curl -X POST "https://api.zenovay.com/e/YOUR_TRACKING_CODE" \
-H "Content-Type: application/json" \
-d '{
"event_type": "custom",
"event_name": "purchase",
"url": "https://example.com/checkout/success",
"referrer": "https://example.com/cart",
"session_id": "srv-9f2a7c41bd",
"device_type": "server",
"browser": "server",
"os": "Linux",
"user_agent": "MyApp-Server/1.0",
"properties": {
"order_id": "ORD-12345",
"value": 99.99,
"currency": "JPY"
}
}'
# ページビュー
curl -X POST "https://api.zenovay.com/e/YOUR_TRACKING_CODE" \
-H "Content-Type: application/json" \
-d '{
"event_type": "pageview",
"url": "https://example.com/products/widget",
"referrer": "https://google.com/search",
"session_id": "srv-9f2a7c41bd",
"device_type": "server",
"browser": "server",
"os": "Linux",
"user_agent": "MyApp-Server/1.0"
}'
ジオロケーションに関する注釈
ブラウザトラフィックについて、Zenovay は接続している訪問者の IP からロケーションを導出します。サーバーからエンドポイントを呼び出すとき、接続している IP はサーバーのものです — したがってイベントは最終ユーザーではなく、インフラストラクチャの場所にジオロケーションされます。
訪問者ごとの正確なジオロケーションが必要な場合は、クライアント側でそのトラッキングを実行するか(標準インストールスニペット)、ファーストパーティプロキシを使用してください。サーバーサイドトラッキングはバックエンドイベント(購入、サブスクリプション)のために予約してください。このような場合、ユーザーの正確な場所は重要ではありません。通常のサーバーコール上で X-Forwarded-For ヘッダーを追加しても、公開エンドポイント用のサーバー IP は上書きされません。
実装例
Node.js / Express
// lib/analytics.js
const TRACKING_CODE = process.env.ZENOVAY_TRACKING_CODE;
const ENDPOINT = `https://api.zenovay.com/e/${TRACKING_CODE}`;
// すべてのサーバーサイドイベントに必要なベースフィールド。
const SERVER_DEFAULTS = {
device_type: 'server',
browser: 'server',
os: 'Linux',
user_agent: 'MyApp-Server/1.0'
};
async function trackEvent(eventName, { url, sessionId, properties = {} }) {
const payload = {
event_type: 'custom',
event_name: eventName,
url,
session_id: sessionId,
properties,
...SERVER_DEFAULTS
};
try {
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
return response.ok;
} catch (error) {
console.error('Analytics error:', error);
return false;
}
}
async function trackPageview({ url, sessionId, referrer = '' }) {
const payload = {
event_type: 'pageview',
url,
referrer,
session_id: sessionId,
...SERVER_DEFAULTS
};
try {
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
return response.ok;
} catch (error) {
console.error('Pageview tracking error:', error);
return false;
}
}
module.exports = { trackEvent, trackPageview };
Python (Flask)
# analytics.py
import os
import requests
from flask import request
TRACKING_CODE = os.getenv('ZENOVAY_TRACKING_CODE')
TRACKING_URL = f'https://api.zenovay.com/e/{TRACKING_CODE}'
SERVER_DEFAULTS = {
'device_type': 'server',
'browser': 'server',
'os': 'Linux',
'user_agent': 'MyApp-Server/1.0',
}
def track_event(event_name, session_id, url, properties=None):
payload = {
'event_type': 'custom',
'event_name': event_name,
'url': url,
'session_id': session_id,
'properties': properties or {},
**SERVER_DEFAULTS,
}
try:
response = requests.post(TRACKING_URL, json=payload, timeout=5)
return response.ok
except Exception as e:
print(f'Analytics error: {e}')
return False
def track_pageview(session_id, url, referrer=''):
payload = {
'event_type': 'pageview',
'url': url,
'referrer': referrer,
'session_id': session_id,
**SERVER_DEFAULTS,
}
try:
response = requests.post(TRACKING_URL, json=payload, timeout=5)
return response.ok
except Exception as e:
print(f'Pageview tracking error: {e}')
return False
PHP
<?php
class ZenovayAnalytics {
private $trackingUrl;
private $defaults = [
'device_type' => 'server',
'browser' => 'server',
'os' => 'Linux',
'user_agent' => 'MyApp-Server/1.0',
];
public function __construct($trackingCode) {
$this->trackingUrl = "https://api.zenovay.com/e/{$trackingCode}";
}
public function trackEvent($eventName, $sessionId, $url, $properties = []) {
$payload = array_merge([
'event_type' => 'custom',
'event_name' => $eventName,
'url' => $url,
'session_id' => $sessionId,
'properties' => $properties,
], $this->defaults);
return $this->sendRequest($payload);
}
public function trackPageview($sessionId, $url, $referrer = '') {
$payload = array_merge([
'event_type' => 'pageview',
'url' => $url,
'referrer' => $referrer,
'session_id' => $sessionId,
], $this->defaults);
return $this->sendRequest($payload);
}
private function sendRequest($payload) {
$ch = curl_init($this->trackingUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5
]);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode >= 200 && $httpCode < 300;
}
}
// 使用例
$analytics = new ZenovayAnalytics(getenv('ZENOVAY_TRACKING_CODE'));
$analytics->trackEvent('purchase', 'srv-9f2a7c41bd', 'https://example.com/checkout/success', [
'order_id' => 'ORD-12345',
'value' => 99.99
]);
ハイブリッドトラッキング
最も一般的なパターン:クライアントスクリプトで閲覧を追跡し、支払いプロバイダーが確認したらサーバーから転換を確認します。
// クライアント側:Zenovay スクリプトを使用して意図を追跡します
window.zenovay('track', 'checkout_started');
// サーバー側:ウェブフックハンドラーから確認済みイベントを追跡します
app.post('/webhooks/stripe', async (req, res) => {
const event = req.body;
if (event.type === 'checkout.session.completed') {
await trackEvent('purchase', {
url: 'https://example.com/checkout/success',
sessionId: 'srv-' + event.data.object.id.slice(-12),
properties: {
order_id: event.data.object.id,
value: event.data.object.amount_total / 100
}
});
}
res.sendStatus(200);
});
ボットフィルタリング
Zenovay は既に取り込み側で明らかなボットトラフィックをフィルタリングしているため、curl、wget、python などの汎用エージェント、または一般的なクローラーパターンに一致するものが含まれるイベントは拒否されます。だからこそ、上記の例ではサーバー用に説明的な user_agent を使用しています。
バックエンド経由で実際のクライアントリクエストも転送している場合は、送信前にクローラーをフィルタリングしてください。そうしないと、いずれにせよ拒否されるトラフィックでレート制限を無駄にしてしまいます:
function isBot(userAgent) {
const botPatterns = [
/bot/i, /crawler/i, /spider/i, /scraper/i,
/curl/i, /wget/i, /python/i, /java\//i,
/googlebot/i, /bingbot/i, /yandex/i
];
return botPatterns.some(pattern => pattern.test(userAgent || ''));
}
レート制限
トラッキングエンドポイントには IP アドレスごとのレート制限があります:
- バースト制限:10 秒間に 60 リクエスト
- 持続制限:1 時間に 5,000 リクエスト
これらの制限はトラッキング取り込みエンドポイント専用です。REST API(独立した有料機能で独自の制限があります)には適用されません。
トラブルシューティング
イベントが表示されない場合
確認事項:
- URL パスのトラッキングコードが正しいかどうか。
- すべての必須フィールドが存在しているかどうか(8 文字以上の
session_id、有効なurl、device_type、browser、os、user_agent)。不足しているフィールドは何が不足しているかを含む400を返します。 user_agentがボットとしてフィルタリングされていないかどうか(curl、pythonなどは避けてください)。- IP がレート制限されていないかどうか。
イベントが重複している場合
確認事項:
- クライアント側とサーバー側の両方で同じイベントを追跡していないかどうか。
- ウェブフックハンドラーが同じイベントに対して複数回発火していないかどうか。
ジオロケーションがサーバーを反映している場合
これはサーバー側の呼び出しで期待される動作です — 接続している IP はサーバーであり、訪問者ではありません。訪問者の正確なジオロケーションにはクライアントスクリプト(またはファーストパーティプロキシ)を使用してください。サーバーサイドトラッキングはロケーションが目的ではないバックエンドイベント用に予約してください。