DNN · Tracking de conversiones
Las conversiones son el evento más valioso del funnel y también el más vulnerable a adblockers, extensiones de privacidad y CSPs estrictas. La regla de oro:
Trackea conversiones server-side, no client-side.
El widget ya emite track:click automáticamente cuando un usuario interactúa con un resultado. La conversión final, en cambio, debes notificarla desde tu backend DNN cuando el pedido pasa a estado Confirmed / Paid.
Endpoint
/api/plugin/shops/{shopId}/track/conversion{
"orderId": "ORD-2026-0001",
"orderValue": 199.95,
"currency": "EUR",
"conversions": [
{ "productId": "SKU-001", "searchLogId": "log_aaa", "quantity": 2, "lineTotal": 79.98 },
{ "productId": "SKU-042", "searchLogId": "log_bbb", "quantity": 1, "lineTotal": 119.97 }
]
}
searchLogIdobligatorio (@NotBlankenConversionItem,ShopRequestDTO.java:92). El widget lo emite en cadatrack:clicky lo guarda en una cookie del comprador. En DNN tienes que capturarlo desde JS (cookie del navegador) y reenviarlo a tu servidor con cada línea de pedido. SinsearchLogIdla API responde 400.
Headers:
X-Shop-API-Key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Origin: https://your-domain.example
Content-Type: application/json
Implementación con NeuroonClient
Si ya tienes el NeuroonClient montado (ver examples/full-csharp), una conversión es una línea:
public void OnOrderConfirmed(Order order)
{
var client = new NeuroonClient();
client.TrackConversionAsync(
orderId: order.Id.ToString(),
orderValue: order.Total,
currency: order.Currency,
lines: order.Lines.Select(l => new NeuroonClient.ConversionLine
{
ProductId = l.Sku,
Quantity = l.Quantity,
LineTotal = l.Price * l.Quantity
})
).GetAwaiter().GetResult();
}
Dónde enganchar el handler
Cada módulo de e-commerce DNN tiene su propio punto de extensión:
| Módulo | Hook recomendado |
|---|---|
| DNN Commerce | OrderController::ChangeOrderStatus cuando pasa a Paid. |
| NB_Store | NBrightBuyController::OrderEvent con eventType = "OrderConfirmed". |
| Hotcakes Commerce | OrderService.OrderTransitioned con NewStatus = OrderStatus.Completed. |
| Módulo propio | El método donde marcas el pedido como cobrado / shipped. |
Trackea una sola vez por pedido. Reenvíos no son destructivos (Neuroon deduplica por
orderId), pero contaminan dashboards de retry.
Robustez vs. fallos
El tracking debe ser fire-and-forget: un error de Neuroon nunca debe bloquear la confirmación del pedido al cliente.
public async Task TrackOrderSafelyAsync(Order order)
{
try
{
await new NeuroonClient().TrackConversionAsync(
orderId: order.Id.ToString(),
orderValue: order.Total,
currency: order.Currency,
lines: order.Lines.Select(l => new NeuroonClient.ConversionLine
{
ProductId = l.Sku,
Quantity = l.Quantity,
LineTotal = l.Price * l.Quantity
}));
}
catch (Exception ex)
{
DnnLog.Warn($"Neuroon conversion tracking failed for order {order.Id}: {ex.Message}");
// No re-throw: la confirmación sigue su curso.
}
}
Reintentos
Polly ya está configurado dentro del cliente (3 intentos sobre 429 / 5xx). Si tras eso falla, persiste el pedido en una tabla local (Neuroon_Conversion_Outbox) y reintenta con un job nocturno. El endpoint es idempotente por orderId.
CREATE TABLE Neuroon_Conversion_Outbox (
OrderId NVARCHAR(64) PRIMARY KEY,
Payload NVARCHAR(MAX) NOT NULL,
Attempts INT NOT NULL DEFAULT 0,
LastError NVARCHAR(1024) NULL,
CreatedAt DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),
UpdatedAt DATETIME2 NULL,
SyncedAt DATETIME2 NULL
);
Por qué NO confiar solo en el client-side
| Bloqueo | % aproximado de usuarios afectados |
|---|---|
| Adblockers (uBlock, Ghostery, Brave Shields) | 25-40 % en mercados europeos. |
| Safari ITP + iOS Private Relay | impacto residual sobre cookies third-party. |
| CSPs restrictivas (banca, gobierno) | bloquean cualquier pixel third-party. |
| Service workers offline | no envían beacons antes de cerrar tab. |
El tracking server-side hace que ninguno de estos casos te haga perder la conversión.
Rate limit
/track/conversion está dentro del bucket general de plugin endpoints. Para conversiones genuinas no llegarás al límite. Si tienes un volumen muy alto (> 10/s sostenido), agrupa en colas con outbox y suéltalas en bloques de 5/s.
Próximos pasos
- Recipe · Conversion tracking — patrones cross-stack.
- API ·
/track/conversion— referencia (cuando esté publicada). - Ejemplos ·
NeuroonClientcompleto.