Envie eventos de análise diretamente do seu backend para o Zenovay. O rastreamento no lado do servidor é imune a bloqueadores de anúncios, permite que você registre eventos que ocorrem apenas no servidor (compras confirmadas, assinaturas orientadas por webhook) e oferece controle total sobre o que é enviado.
Por que o rastreamento no lado do servidor?
Benefícios
| Benefício | Descrição |
|---|---|
| Imunidade a bloqueadores de anúncios | Os eventos chegam ao Zenovay mesmo quando o script do cliente está bloqueado pelo navegador |
| Eventos apenas do servidor | Rastreie coisas que ocorrem apenas no lado do servidor — pagamentos confirmados, jobs de cron, webhooks |
| Controle de dados | Você decide exatamente o que é enviado |
| Rastreamento híbrido | Combine com o script do cliente para cobertura completa |
Quando usar
- Confirmação de compra em comércio eletrônico (após confirmação do provedor de pagamento)
- Eventos de backend (assinatura criada, assinatura cancelada)
- Eventos acionados por webhook (Stripe, provedores de pagamento)
- Rastreamento híbrido (script do cliente para navegação + servidor para conversões confirmadas)
Endpoint de rastreamento
As solicitações do lado do servidor usam o mesmo endpoint de ingestão que o script do cliente. Envie um POST ao endpoint de rastreamento com o código de rastreamento do seu site no caminho:
POST https://api.zenovay.com/e/{trackingCode}
Este é um endpoint público, não autenticado — não requer uma chave de API e está aberto em todos os planos (é o mesmo caminho para o qual o script de rastreamento envia). O código de rastreamento é o mesmo valor que você coloca no atributo data-tracking-code do seu snippet de instalação.
Informação
O endpoint de ingestão é compartilhado com o rastreador do navegador, portanto sua carga útil é estruturada como os dados que um navegador enviaria. Isso significa que alguns campos que o navegador preenche automaticamente — session_id, device_type, browser, os e user_agent — devem ser fornecidos por você no corpo JSON ao chamar a partir de um servidor. As solicitações que não têm esses campos são rejeitadas.
Campos obrigatórios
Cada evento que você enviar deve incluir esses campos no corpo JSON:
| Campo | Notas |
|---|---|
session_id | Uma string de pelo menos 8 caracteres. Reutilize o mesmo valor para eventos que pertencem à mesma visita. |
url | Uma URL completa e válida (por exemplo https://example.com/checkout/success). |
device_type | por exemplo desktop, mobile, tablet ou server. |
browser | Um nome de navegador/cliente. Use algo descritivo para tráfego de servidor (por exemplo server). |
os | Um nome de sistema operacional (por exemplo Linux). |
user_agent | Uma string de user-agent. Evite agentes genéricos semelhantes a bots (curl, python, wget, etc.) — eles são filtrados como bots. |
visitor_id é opcional, mas recomendado (≥8 caracteres) para que eventos repetidos se vinculem ao mesmo visitante.
Visualização de página vs. Evento personalizado
O tipo de evento é definido com o campo event_type:
- Visualização de página — omita
event_type(padrão) ou defina-o comopageview. - Evento personalizado — defina
event_typeparacustom, coloque o nome do evento emevent_namee quaisquer metadados emproperties.
# Evento personalizado (por exemplo, uma compra confirmada)
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"
}
}'
# Visualização de página
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"
}'
Uma nota sobre a geolocalização
Para tráfego de navegador, o Zenovay obtém a localização do IP do visitante que se conecta. Quando você chama o endpoint do seu servidor, o IP que se conecta é o do seu servidor — portanto, os eventos serão geolocalizados para sua infraestrutura, não para o usuário final.
Se você precisar de geolocalização precisa por visitante, execute esse rastreamento no lado do cliente (o snippet de instalação padrão) ou use o proxy first-party, e reserve o rastreamento no lado do servidor para eventos de backend (compras, assinaturas) onde a localização exata do usuário não é o ponto. Adicionar um header X-Forwarded-For em uma chamada simples do servidor não sobrescreve o IP do servidor para o endpoint público.
Exemplos de implementação
Node.js / Express
// lib/analytics.js
const TRACKING_CODE = process.env.ZENOVAY_TRACKING_CODE;
const ENDPOINT = `https://api.zenovay.com/e/${TRACKING_CODE}`;
// Campos base que cada evento do lado do servidor precisa.
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;
}
}
// Uso
$analytics = new ZenovayAnalytics(getenv('ZENOVAY_TRACKING_CODE'));
$analytics->trackEvent('purchase', 'srv-9f2a7c41bd', 'https://example.com/checkout/success', [
'order_id' => 'ORD-12345',
'value' => 99.99
]);
Rastreamento híbrido
O padrão mais comum: rastreie a navegação com o script do cliente e confirme conversões do servidor assim que o provedor de pagamento as confirmar.
// Lado do cliente: rastreie a intenção usando o script Zenovay
window.zenovay('track', 'checkout_started');
// Lado do servidor: rastreie o evento confirmado de seu manipulador de webhook
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);
});
Filtragem de bots
O Zenovay já filtra tráfego de bot óbvio no lado da ingestão, portanto eventos enviados com agentes genéricos como curl, wget, python ou qualquer coisa que corresponda a padrões comuns de crawler são rejeitados. É por isso que os exemplos acima usam um user_agent descritivo para seu servidor.
Se você também encaminhar solicitações de cliente reais através do seu backend, filtre crawlers antes de enviar para não queimar seu limite de taxa em tráfego que seria rejeitado de qualquer forma:
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 || ''));
}
Limites de taxa
O endpoint de rastreamento tem limites de taxa por endereço IP:
- Limite de rajada: 60 requisições por 10 segundos
- Limite sustentado: 5.000 requisições por hora
Esses limites se aplicam especificamente ao endpoint de ingestão de rastreamento, não à API REST (que é um recurso pago separado com seus próprios limites).
Solução de problemas
Os eventos não aparecem
Verifique:
- O código de rastreamento no caminho da URL está correto.
- Todos os campos obrigatórios estão presentes (
session_idde 8+ caracteres,urlválida,device_type,browser,os,user_agent). Campos ausentes retornam um400com uma lista do que está faltando. - Seu
user_agentnão está sendo filtrado como um bot (evitecurl,python, etc.). - O IP não tem limite de taxa.
Eventos duplicados
Certifique-se:
- Você não está rastreando o mesmo evento tanto do lado do cliente quanto do servidor.
- Os manipuladores de webhook não estão disparando mais de uma vez para o mesmo evento.
A geolocalização reflete seu servidor
Isso é esperado para chamadas do lado do servidor — o IP que se conecta é seu servidor, não o visitante. Use o script do cliente (ou um proxy first-party) para geolocalização precisa do visitante e use o rastreamento no lado do servidor para eventos de backend onde a localização não é o objetivo.