A notificação de eventos é crucial para a atribuição e mensuração.
Connection: keep-alive no header) para otimizar a performance.session_id: Identificador persistente do visitante. Obrigatório em todos os eventos. Deve ser consistente durante a navegação e entre sessões dentro da janela de conversão (≥ 14 dias). O session_id deve ser único por usuário e, idealmente, não expirar nesse período.user_id: ID único do cliente na plataforma, consistente entre canais. Obrigatório na conversão. Opcional (recomendado) para impressão, visualização e clique. O user_id deve ser o mesmo entre app, website e loja física.Após identificar o usuário e a sessão, siga estas diretrizes para o disparo de eventos:
impression_url): Dispare o evento imediatamente após decidir exibir os anúncios retornados pelo ad server, mesmo que o Anúncio acabe não sendo exibido ao usuário (por exemplo, devido a bloqueios ou mudanças de layout).view_url): Dispare o evento quando pelo menos 50% do Anúncio permanecer dentro do viewport do usuário por 1 segundo contínuo.click_url): Dispare o evento sempre que o usuário clicar no Anúncio.Não é necessário manter o estado dos eventos entre carregamentos de página, mas garanta que cada evento seja enviado apenas uma única vez para o mesmo Anúncio e contexto.
Envie uma requisição POST para a respectiva URL de evento (impression_url, view_url, click_url) fornecida na consulta de anúncios, com um corpo JSON contendo session_id (obrigatório) e user_id (quando disponível).
impression_url quando o Anúncio for renderizado; view_url quando o Anúncio estiver visível (se você medir viewability); click_url no clique do usuário.Content-Type: application/jsonnavigator.sendBeacon() para garantir o envio assíncrono sem bloquear a navegação e evitar a perda de eventos quando o usuário navega para outra página ou fecha o navegador.HTTP 202 Accepted.Veja exemplos de envio no navegador em examples/EVENTS_IMPRESSIONS_VIEWS_CLICKS_BROWSER.md.
Exemplo de envio de evento usando Beacon API:
// Função para enviar evento de impressão
function sendImpressionEvent(impressionUrl, userId, sessionId) {
// Dados do evento
const eventData = {
user_id: userId,
session_id: sessionId
};
// Verifica se o navegador suporta a Beacon API
if (navigator.sendBeacon) {
// Converte os dados para JSON
const blob = new Blob([JSON.stringify(eventData)], {type: 'application/json'});
// Envia o evento de forma assíncrona
const success = navigator.sendBeacon(impressionUrl, blob);
if (!success) {
console.error('Falha ao enviar evento via Beacon API');
// Implementar fallback se necessário
}
} else {
// Fallback para navegadores que não suportam Beacon API
const xhr = new XMLHttpRequest();
xhr.open('POST', impressionUrl, true); // true para assíncrono
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(eventData));
}
}
// Exemplo de uso
sendImpressionEvent(
'https://events.newtail-media.newtail.com.br/v1/beacon/impression/123456',
'user-123',
'session-456'
);
Importante: O uso da Beacon API é obrigatório para garantir que os eventos sejam enviados mesmo quando o usuário navega para outra página ou fecha o navegador. Isso evita a perda de eventos e garante uma medição mais precisa.
Quando uma compra é finalizada, envie os dados do pedido.
POST https://events.newtail-media.newtail.com.br/v1/beacon/conversionContent-Type: application/jsonVeja exemplos de conversão em examples/EVENTS_CONVERSION_BROWSER.md (Browser) e examples/EVENTS_CONVERSION_CURL.md (cURL).
| Campo do Pedido | Descrição | Tipo | Obrigatório? |
|---|---|---|---|
publisher_id |
ID do publisher. | String | Sim |
user_id |
ID do usuário que realizou a compra. | String | Sim |
session_id |
ID da sessão da compra. | String | Sim |
order_id |
ID do pedido. | String | Sim |
created_at |
Data/hora do pedido (ISO 8601 em UTC). | String | Sim |
items |
Lista de itens do pedido. | Array[Item] | Sim |
channel |
Canal de venda (ex.: ecommerce, app, loja física). | String | Sim |
brand |
Marca/site onde ocorreu a venda (necessário quando existe mais de um site). | String | Não/Sim |
gender |
Indica qual o sexo do cliente. F: para feminino, M: para masculino, O: para outros, null: para não identificados. | String | Não (Recomendado) |
uf |
Indica o estado da compra do pedido. | String | Não (Recomendado) |
city |
Indica qual o nome da cidade o cliente comprou. | String | Não (Recomendado) |
is_company |
Indica se a venda foi feita para pessoa física ou jurídica. | Boolean | Não (Recomendado) |
email_hashed |
E-mail do usuário em formato hash (SHA256). | String | Sim |
phone_hashed |
Telefone do usuário em hash (SHA256). | String | Não (Recomendado) |
social_id_hashed |
CPF/CNPJ do usuário em hash (SHA256). | String | Não (Recomendado) |
first_name_hashed |
Identificação do Primeiro Nome do usuário (hash). | String | Não (Recomendado) |
last_name_hashed |
Identificação do Último Nome do usuário (hash). | String | Não (Recomendado) |
Normalização recomendada para hashing:
email_hashed: e-mail em lowercase e trim, sem espaços extras; hash SHA-256 em hexadecimal.phone_hashed: telefone em formato E.164 (ex.: +5511999999999), sem máscaras; hash SHA-256 em hexadecimal.social_id_hashed: CPF/CNPJ somente dígitos (sem pontos/traços); hash SHA-256 em hexadecimal.first_name_hashed/last_name_hashed: nomes normalizados (trim, sem espaços duplos); hash SHA-256 em hexadecimal.
| Campo | Descrição | Tipo | Obrigatoriedade |
|---|---|---|---|
sku |
Identificação única do SKU do produto | String | Obrigatório |
quantity |
Quantidade comprada do produto | Double | Obrigatório |
price |
Preço original do produto (preço “de”) | Double | Obrigatório |
promotional_price |
Preço promocional do produto (preço “por”) | Double | Obrigatório |
seller_id |
Identificação do vendedor/seller | String | Opcional |
product_id |
Identificação única do produto que engloba o SKU | String | Opcional |
price e promotional_price devem conter o valor unitário do produto, não multiplicado pela quantidadeprice e promotional_price não forem informados corretamente, a conversão não poderá ser mensurada{
"sku": "12221",
"seller_id": "1234",
"product_id": "4567",
"quantity": 1,
"price": 2000.00,
"promotional_price": 1899.00
}
POST https://events.newtail-media.newtail.com.br/v1/beacon/conversion HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"channel": "ecommerce",
"publisher_id": "xxx",
"user_id": "6f92d1e9-00b6-4f8b-9645-faeab321e1cc",
"session_id": "5898b8d1-c250-4bb5-931b-8b9d0ee7b499",
"order_id": "123",
"email_hashed": "xyz",
"items": [
{
"sku": "12221",
"seller_id": "1234",
"product_id": "4567",
"quantity": 1,
"price": 2000.00,
"promotional_price": 1899.00
},
{
"sku": "12222",
"seller_id": null,
"product_id": "4568",
"quantity": 2,
"price": 500.00,
"promotional_price": 400.00
}
],
"created_at": "2023-01-01T09:20:00Z"
}
Nota: No exemplo acima, observe que:
{
"messages": [
"conversion will be processed soon"
]
}
A API retorna erros de validação em um formato compatível com JSON Schema (semântica similar ao Ajv).
Exemplo de resposta com erros:
[
{
"instancePath": "",
"keyword": "required",
"message": "must have required property 'user_id'",
"params": {
"missingProperty": "user_id"
},
"schemaPath": "#/required"
},
{
"instancePath": "",
"keyword": "required",
"message": "must have required property 'order_id'",
"params": {
"missingProperty": "order_id"
},
"schemaPath": "#/required"
},
{
"instancePath": "",
"keyword": "required",
"message": "must have required property 'publisher_id'",
"params": {
"missingProperty": "publisher_id"
},
"schemaPath": "#/required"
},
{
"instancePath": "",
"keyword": "required",
"message": "must have required property 'items'",
"params": {
"missingProperty": "items"
},
"schemaPath": "#/required"
},
{
"instancePath": "",
"keyword": "required",
"message": "must have required property 'created_at'",
"params": {
"missingProperty": "created_at"
},
"schemaPath": "#/required"
}
]
As conversões só são computadas para campanhas quando ocorre um match de produto. Isso significa que:
Cenário 1 - Com Match (Conversão Computada)
Cenário 2 - Sem Match (Conversão NÃO Computada)
const enviarConversao = async (dadosPedido) => {
const payload = {
channel: "ecommerce",
publisher_id: "xxx",
user_id: dadosPedido.userId,
session_id: dadosPedido.sessionId,
order_id: dadosPedido.orderId,
email_hashed: dadosPedido.emailHash,
items: dadosPedido.items.map(item => ({
sku: item.sku,
seller_id: item.sellerId || null,
product_id: item.productId || null,
quantity: item.quantity,
price: item.unitPrice, // Valor unitário, não multiplicado
promotional_price: item.unitPromotionalPrice // Valor unitário, não multiplicado
})),
created_at: new Date().toISOString()
};
try {
// Converte os dados para JSON
const blob = new Blob([JSON.stringify(payload)], {type: 'application/json'});
// Envia o evento de forma assíncrona usando Beacon API
if (navigator.sendBeacon) {
const success = navigator.sendBeacon(
'https://events.newtail-media.newtail.com.br/v1/beacon/conversion',
blob
);
if (success) {
console.log('Conversão enviada com sucesso');
} else {
console.error('Falha ao enviar conversão via Beacon API');
}
} else {
// Fallback para navegadores que não suportam Beacon API
const response = await fetch('https://events.newtail-media.newtail.com.br/v1/beacon/conversion', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (response.status === 202) {
console.log('Conversão enviada com sucesso');
} else if (response.status === 422) {
const errors = await response.json();
console.error('Erros de validação:', errors);
}
}
} catch (error) {
console.error('Erro ao enviar conversão:', error);
}
};
// Exemplo de uso
const pedido = {
userId: "6f92d1e9-00b6-4f8b-9645-faeab321e1cc",
sessionId: "5898b8d1-c250-4bb5-931b-8b9d0ee7b499",
orderId: "123",
emailHash: "xyz",
items: [
{
sku: "12221",
sellerId: "1234",
productId: "4567",
quantity: 1,
unitPrice: 2000.00,
unitPromotionalPrice: 1899.00
}
]
};
enviarConversao(pedido);
product): 14 dias.display/video): 14 dias.order_id (reenvios do mesmo order_id em até 30 dias são ignorados).