DNN · Conversion tracking
Conversions are the most valuable event in the funnel and also the most exposed to adblockers, privacy extensions and strict CSPs. The golden rule:
Track conversions server-side, not client-side.
The widget already emits track:click automatically when a user interacts with a result. The final conversion, however, must be reported from your DNN backend when the order moves to 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 }
]
}
searchLogIdis required (@NotBlankonConversionItem,ShopRequestDTO.java:92). The widget emits it on everytrack:clickand stores it in a cookie on the buyer's browser. On DNN you must capture it from JS (browser cookie) and forward it to your server with each order line. WithoutsearchLogIdthe API responds 400.
Headers:
X-Shop-API-Key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Origin: https://your-domain.example
Content-Type: application/json
Implementation with NeuroonClient
If you already have the NeuroonClient set up (see examples/full-csharp), a conversion is a one-liner:
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();
}
Where to hook the handler
Each DNN e-commerce module has its own extension point:
| Module | Recommended hook |
|---|---|
| DNN Commerce | OrderController::ChangeOrderStatus when it moves to Paid. |
| NB_Store | NBrightBuyController::OrderEvent with eventType = "OrderConfirmed". |
| Hotcakes Commerce | OrderService.OrderTransitioned with NewStatus = OrderStatus.Completed. |
| Custom module | The method where you mark the order as paid / shipped. |
Track only once per order. Resends are non-destructive (Neuroon deduplicates by
orderId) but pollute retry dashboards.
Robustness against failures
Tracking must be fire-and-forget: a Neuroon error must never block order confirmation for the customer.
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: confirmation continues normally.
}
}
Retries
Polly is already configured inside the client (3 attempts on 429 / 5xx). If it still fails, persist the order in a local table (Neuroon_Conversion_Outbox) and retry from a nightly job. The endpoint is idempotent by 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
);
Why NOT trust client-side alone
| Block | Approximate % of users affected |
|---|---|
| Adblockers (uBlock, Ghostery, Brave Shields) | 25-40 % in European markets. |
| Safari ITP + iOS Private Relay | residual impact on third-party cookies. |
| Strict CSPs (banking, government) | block any third-party pixel. |
| Offline service workers | do not send beacons before tab close. |
Server-side tracking ensures none of these cases costs you the conversion.
Rate limit
/track/conversion is within the general plugin endpoints bucket. For genuine conversions you will not hit the limit. If you have very high volume (> 10/s sustained), batch in queues with outbox and release in blocks of 5/s.
Next steps
- Recipe · Conversion tracking — cross-stack patterns.
- API ·
/track/conversion— reference (when published). - Examples · Full
NeuroonClient.