Senden Sie Analyseereignisse direkt vom Backend an Zenovay. Serverseitiges Tracking ist immun gegen Werbeblocker, ermöglicht das Erfassen von Ereignissen, die nur auf dem Server stattfinden (bestätigte Käufe, Webhook-gesteuerte Abonnements), und gibt Ihnen vollständige Kontrolle über das, was gesendet wird.
Warum serverseitiges Tracking?
Vorteile
| Vorteil | Beschreibung |
|---|---|
| Immunität gegen Werbeblocker | Ereignisse erreichen Zenovay auch wenn das Client-Skript im Browser blockiert wird |
| Nur-Server-Ereignisse | Verfolgen Sie Dinge, die nur serverseitig stattfinden — bestätigte Zahlungen, Cron-Jobs, Webhooks |
| Datenkontrolle | Sie entscheiden genau, was gesendet wird |
| Hybrides Tracking | Kombinieren Sie mit dem Client-Skript für vollständige Abdeckung |
Wann verwenden
- E-Commerce-Kaufbestätigung (nach Bestätigung durch den Zahlungsanbieter)
- Backend-Ereignisse (Abonnement erstellt, Abonnement gekündigt)
- Webhook-gesteuerte Ereignisse (Stripe, Zahlungsanbieter)
- Hybrides Tracking (Client-Skript zum Browsing + Server für bestätigte Konversionen)
Tracking-Endpunkt
Serverseitige Anfragen verwenden denselben Ingest-Endpunkt wie das Client-Skript. Senden Sie einen POST zum Tracking-Endpunkt mit dem Tracking-Code Ihrer Website im Pfad:
POST https://api.zenovay.com/e/{trackingCode}
Dies ist ein öffentlicher, nicht authentifizierter Endpunkt — er erfordert keinen API-Schlüssel und ist auf jedem Plan offen (es ist derselbe Pfad, auf den das Tracking-Skript sendet). Der Tracking-Code ist derselbe Wert, den Sie im Attribut data-tracking-code Ihres Installationscodes verwenden.
Information
Der Ingest-Endpunkt wird mit dem Browser-Tracker gemeinsam genutzt, daher ist seine Payload wie die Daten strukturiert, die ein Browser senden würde. Das bedeutet, dass einige Felder, die der Browser automatisch ausfüllt — session_id, device_type, browser, os und user_agent — von Ihnen im JSON-Body angegeben werden müssen, wenn Sie vom Server aufrufen. Anfragen, denen diese fehlen, werden abgelehnt.
Erforderliche Felder
Jedes Ereignis, das Sie senden, muss diese Felder im JSON-Body enthalten:
| Feld | Hinweise |
|---|---|
session_id | Eine Zeichenkette mit mindestens 8 Zeichen. Verwenden Sie denselben Wert für Ereignisse, die zu demselben Besuch gehören. |
url | Eine vollständige, gültige URL (z. B. https://example.com/checkout/success). |
device_type | z. B. desktop, mobile, tablet oder server. |
browser | Ein Browser-/Client-Name. Verwenden Sie etwas Aussagekräftiges für Server-Traffic (z. B. server). |
os | Ein Betriebssystem-Name (z. B. Linux). |
user_agent | Eine User-Agent-Zeichenkette. Vermeiden Sie generische Bot-ähnliche Agents (curl, python, wget, usw.) — diese werden als Bots gefiltert. |
visitor_id ist optional, aber empfohlen (≥8 Zeichen), damit wiederholte Ereignisse an denselben Besucher gebunden sind.
Seitenaufruf vs. Benutzerdefiniertes Ereignis
Die Ereignisart wird mit dem Feld event_type gesetzt:
- Seitenaufruf — lassen Sie
event_typeweg (Standard) oder setzen Sie es aufpageview. - Benutzerdefiniertes Ereignis — setzen Sie
event_typeaufcustom, geben Sie den Ereignisnamen inevent_nameein und alle Metadaten inproperties.
# Benutzerdefiniertes Ereignis (z. B. ein bestätigter Kauf)
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": "USD"
}
}'
# Seitenaufruf
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"
}'
Ein Hinweis zur Geolokalisierung
Bei Browser-Traffic leitet Zenovay den Standort von der IP des verbindenden Besuchers ab. Wenn Sie den Endpunkt von Ihrem Server aufrufen, ist die verbindende IP die Ihres Servers — daher werden Ereignisse nach Ihrer Infrastruktur geortet.
Wenn Sie genaue Geolokalisierung pro Besucher benötigen, führen Sie dieses Tracking clientseitig durch (das Standard-Installationscode-Snippet) oder verwenden Sie den First-Party-Proxy, und reservieren Sie serverseitiges Tracking für Backend-Ereignisse (Käufe, Abonnements), wo der genaue Standort des Benutzers nicht der Punkt ist. Das Hinzufügen eines X-Forwarded-For-Headers bei einem einfachen Server-Aufruf überschreibt nicht die IP des Servers für den öffentlichen Endpunkt.
Implementierungsbeispiele
Node.js / Express
// lib/analytics.js
const TRACKING_CODE = process.env.ZENOVAY_TRACKING_CODE;
const ENDPOINT = `https://api.zenovay.com/e/${TRACKING_CODE}`;
// Basisfelder, die jedes serverseitige Ereignis braucht.
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;
}
}
// Verwendung
$analytics = new ZenovayAnalytics(getenv('ZENOVAY_TRACKING_CODE'));
$analytics->trackEvent('purchase', 'srv-9f2a7c41bd', 'https://example.com/checkout/success', [
'order_id' => 'ORD-12345',
'value' => 99.99
]);
Hybrides Tracking
Das häufigste Muster: Verfolgen Sie das Browsing mit dem Client-Skript und bestätigen Sie Konversionen vom Server, sobald der Zahlungsanbieter diese bestätigt hat.
// Client-seitig: Verfolgen Sie die Absicht mit dem Zenovay-Skript
window.zenovay('track', 'checkout_started');
// Server-seitig: Verfolgen Sie das bestätigte Ereignis von Ihrem Webhook-Handler
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);
});
Bot-Filterung
Zenovay filtert offensichtlichen Bot-Traffic bereits auf der Ingest-Seite, daher werden Ereignisse, die mit generischen Agents wie curl, wget, python oder alles, das gängigen Crawler-Mustern entspricht, gesendet werden, abgelehnt. Daher verwenden die obigen Beispiele einen beschreibenden user_agent für Ihren Server.
Wenn Sie auch echte Client-Anfragen durch Ihr Backend leiten, filtern Sie Crawler vorher heraus, damit Sie die Rate-Limit nicht mit Traffic verbrennen, der ohnehin abgelehnt würde:
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 || ''));
}
Ratenbegrenzungen
Der Tracking-Endpunkt hat Ratenbegrenzungen pro IP-Adresse:
- Burst-Limit: 60 Anfragen pro 10 Sekunden
- Dauerhaftes Limit: 5.000 Anfragen pro Stunde
Diese Limits gelten speziell für den Tracking-Ingest-Endpunkt, nicht für die REST API (die ein separates, kostenpflichtiges Feature mit eigenen Limits ist).
Fehlerbehebung
Ereignisse erscheinen nicht
Überprüfen Sie:
- Der Tracking-Code im URL-Pfad ist korrekt.
- Alle erforderlichen Felder vorhanden (
session_idvon 8+ Zeichen, gültigeurl,device_type,browser,os,user_agent). Fehlende Felder geben einen400mit einer Liste dessen zurück, was fehlt. - Ihr
user_agentwird nicht als Bot gefiltert (vermeiden Siecurl,python, usw.). - Die IP ist nicht ratenbegrenzt.
Doppelte Ereignisse
Stellen Sie sicher:
- Sie verfolgen nicht dasselbe Ereignis sowohl client- als auch serverseitig.
- Webhook-Handler werden nicht mehr als einmal für dasselbe Ereignis ausgelöst.
Geolokalisierung spiegelt Ihren Server wider
Dies ist normal für serverseitige Aufrufe — die verbindende IP ist Ihr Server, nicht der Besucher. Verwenden Sie das Client-Skript (oder einen First-Party-Proxy) für besuchergenaue Geolokalisierung und nutzen Sie serverseitiges Tracking für Backend-Ereignisse, bei denen der Standort nicht das Ziel ist.