La notificación de eventos es crucial para la atribución y la medición.
Connection: keep-alive en el encabezado) para optimizar la performance.session_id: Identificador persistente del visitante. Obligatorio en todos los eventos. Debe mantenerse consistente durante la navegación y entre sesiones dentro de la ventana de conversión (≥ 14 días). El session_id debe ser único por usuario y, idealmente, no expirar en este período.user_id: ID único del cliente en la plataforma, consistente entre canales. Obligatorio en conversión. Opcional (recomendado) para impresión, visualización y clic. El user_id debe ser el mismo entre app, sitio web y tienda física.Después de identificar al usuario y la sesión, siga estas directrices para el disparo de eventos:
impression_url): Dispare el evento inmediatamente después de decidir mostrar los anuncios devueltos por el ad server, incluso si el Anuncio finalmente no se muestra al usuario (por ejemplo, por bloqueos o cambios de diseño).view_url): Dispare el evento cuando al menos el 50% del Anuncio permanezca dentro del viewport del usuario durante 1 segundo continuo.click_url): Dispare el evento siempre que el usuario haga clic en el Anuncio.No es necesario mantener el estado de los eventos entre cargas de página, pero asegúrese de que cada evento se envíe solo una vez para el mismo Anuncio y contexto.
Envíe una solicitud POST a la respectiva URL de evento (impression_url, view_url, click_url) proporcionada en la consulta de anuncios, con un cuerpo JSON que contenga session_id (obligatorio) y user_id (cuando esté disponible).
impression_url cuando se renderiza el Anuncio; view_url cuando el Anuncio esté visible (si usted mide viewability); click_url en el clic del usuario.Content-Type: application/jsonnavigator.sendBeacon() para garantizar el envío asíncrono sin bloquear la navegación y evitar la pérdida de eventos cuando el usuario navega a otra página o cierra el navegador.HTTP 202 Accepted.Consulte ejemplos de envío desde el navegador en examples/EVENTS_IMPRESSIONS_VIEWS_CLICKS_BROWSER.md.
Ejemplo de envío de evento usando Beacon API:
// Función para enviar evento de impresión
function sendImpressionEvent(impressionUrl, userId, sessionId) {
// Datos del evento
const eventData = {
user_id: userId,
session_id: sessionId
};
// Verifica si el navegador soporta la Beacon API
if (navigator.sendBeacon) {
// Convierte los datos a JSON
const blob = new Blob([JSON.stringify(eventData)], {type: 'application/json'});
// Envía el evento de forma asíncrona
const success = navigator.sendBeacon(impressionUrl, blob);
if (!success) {
console.error('Error al enviar evento vía Beacon API');
// Implementar fallback si es necesario
}
} else {
// Fallback para navegadores que no soportan Beacon API
const xhr = new XMLHttpRequest();
xhr.open('POST', impressionUrl, true); // true para asíncrono
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(eventData));
}
}
// Ejemplo de uso
sendImpressionEvent(
'https://events.newtail-media.newtail.com.br/v1/beacon/impression/123456',
'user-123',
'session-456'
);
Importante: El uso de la Beacon API es obligatorio para garantizar que los eventos se envíen incluso cuando el usuario navega a otra página o cierra el navegador. Esto evita la pérdida de eventos y asegura una medición más precisa.
Cuando una compra es finalizada, envíe los datos del pedido.
POST https://events.newtail-media.newtail.com.br/v1/beacon/conversionContent-Type: application/jsonConsulte ejemplos de conversión en examples/EVENTS_CONVERSION_BROWSER.md (Browser) y examples/EVENTS_CONVERSION_CURL.md (cURL).
| Campo del Pedido | Descripción | Tipo | ¿Obligatorio? |
|---|---|---|---|
publisher_id |
ID del publisher. | String | Sí |
user_id |
ID del usuario que realizó la compra. | String | Sí |
session_id |
ID de la sesión de la compra. | String | Sí |
order_id |
ID del pedido. | String | Sí |
created_at |
Fecha/hora del pedido (ISO 8601 en UTC). | String | Sí |
items |
Lista de artículos del pedido. | Array[Item] | Sí |
channel |
Canal de venta (ej.: ecommerce, app, tienda física). | String | Sí |
brand |
Marca/sitio donde ocurrió la venta (necesario cuando existe más de un sitio). | String | No/Sí |
gender |
Indica el género del cliente. F: para femenino, M: para masculino, O: para otros, null: para no identificados. | String | No (Recomendado) |
uf |
Indica el estado de la compra del pedido. | String | No (Recomendado) |
city |
Indica el nombre de la ciudad donde el cliente realizó la compra. | String | No (Recomendado) |
is_company |
Indica si la venta fue realizada a una persona jurídica o física. | Boolean | No (Recomendado) |
email_hashed |
E-mail del usuario en formato hash (SHA256). | String | Sí |
phone_hashed |
Teléfono del usuario en hash (SHA256). | String | No (Recomendado) |
social_id_hashed |
ID social/fiscal del usuario (CUIT/CUIL) en hash (SHA256). | String | No (Recomendado) |
first_name_hashed |
Nombre del usuario (hash). | String | No (Recomendado) |
last_name_hashed |
Apellido del usuario (hash). | String | No (Recomendado) |
Normalización recomendada para hashing:
email_hashed: email en minúsculas y sin espacios (trim); hash SHA-256 en hexadecimal.phone_hashed: teléfono en formato E.164 (ej.: +5491112345678), sin máscaras; hash SHA-256 en hexadecimal.social_id_hashed: documento fiscal solo con dígitos (sin puntos/guiones); hash SHA-256 en hexadecimal.first_name_hashed/last_name_hashed: nombres normalizados (trim, sin espacios dobles); hash SHA-256 en hexadecimal.
| Campo | Descripción | Tipo | Obligatoriedad |
|---|---|---|---|
sku |
Identificación única del SKU del producto | String | Obligatorio |
quantity |
Cantidad comprada del producto | Double | Obligatorio |
price |
Precio original del producto (precio “de”) | Double | Obligatorio |
promotional_price |
Precio promocional del producto (precio “por”) | Double | Obligatorio |
seller_id |
Identificación del vendedor/seller | String | Opcional |
product_id |
Identificación única del producto que engloba el SKU | String | Opcional |
price y promotional_price deben contener el valor unitario del producto, no multiplicado por la cantidadprice y promotional_price no se informan correctamente, la conversión no podrá ser medida{
"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: En el ejemplo anterior, observe que:
{
"messages": [
"conversion will be processed soon"
]
}
La API devuelve errores de validación en un formato compatible con JSON Schema (similar a Ajv).
Ejemplo de respuesta con errores:
[
{
"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"
}
]
Las conversiones solo se computan para campañas cuando ocurre un match de producto. Esto significa que:
Escenario 1 - Con Match (Conversión Computada)
Escenario 2 - Sin Match (Conversión NO Computada)
const enviarConversion = async (datosPedido) => {
const payload = {
channel: "ecommerce",
publisher_id: "xxx",
user_id: datosPedido.userId,
session_id: datosPedido.sessionId,
order_id: datosPedido.orderId,
email_hashed: datosPedido.emailHash,
items: datosPedido.items.map(item => ({
sku: item.sku,
seller_id: item.sellerId || null,
product_id: item.productId || null,
quantity: item.quantity,
price: item.unitPrice, // Valor unitario, no multiplicado
promotional_price: item.unitPromotionalPrice // Valor unitario, no multiplicado
})),
created_at: new Date().toISOString()
};
try {
// Convierte los datos a JSON
const blob = new Blob([JSON.stringify(payload)], {type: 'application/json'});
// Envía el evento de forma así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('Conversión enviada con éxito');
} else {
console.error('Error al enviar conversión vía Beacon API');
}
} else {
// Fallback para navegadores que no soportan 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('Conversión enviada con éxito');
} else if (response.status === 422) {
const errors = await response.json();
console.error('Errores de validación:', errors);
}
}
} catch (error) {
console.error('Error al enviar conversión:', error);
}
};
// Ejemplo 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
}
]
};
enviarConversion(pedido);
product): 14 días.display/video): 14 días.order_id (reenvíos del mismo order_id dentro de 30 días se ignoran).