Skip to main content

Analytics and tracking

The widget reports two kinds of events to the backend:

  • Automatic events (product clicks, detected conversions) emitted by the widget in response to user interaction.
  • Manual events (custom business events) sent from your host via POST /api/widget/analytics/event or the batch endpoint.

All traffic flows through the X-Widget-Token header and shares the rate-limit policy of WidgetRateLimitFilter.

Automatic events

EventEndpointWhen
Product clickPOST /api/widget/track/clickThe user clicks on a card or CTA of a result.
Assisted conversionPOST /api/widget/track/conversionThe widget detects a conversion via conversionSelector (when tracking.conversions = true).

Both endpoints are defined in WidgetTrackingController.java. The payload includes searchLogId and productId (plus optional orderId, orderValue, currency, timeToConversionMs, userSessionId on conversion) to close the attribution loop.

Manual events

For events the widget does not detect (banner impression, category click, etc.) use the generic endpoint:

POST/api/widget/analytics/event
curl -X POST https://api.neuroon.ai/api/widget/analytics/event \
-H "X-Widget-Token: $WIDGET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"eventType": "category_click",
"searchLogId": "log_abc",
"productId": "p_1",
"metadata": { "category": "running" }
}'

Controller: WidgetAnalyticsController.java.

Batch

To reduce round-trips from high-volume clients:

POST/api/widget/analytics/events/batch
curl -X POST https://api.neuroon.ai/api/widget/analytics/events/batch \
-H "X-Widget-Token: $WIDGET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"events": [
{ "eventType": "result_impression", "searchLogId": "log_abc", "productId": "p_1", "position": 1 },
{ "eventType": "result_impression", "searchLogId": "log_abc", "productId": "p_2", "position": 2 }
]
}'

The batch accepts up to 100 events per request (@Size(min = 1, max = 100) on BatchRequest).

Recommendation: batch 5–20 events or flush every 2 s, whichever happens first. navigator.sendBeacon is ideal for flush on unload.

Event schema

FieldTypeRequiredNotes
eventTypestring (max 30)yesEvent identifier. Must match a value of WidgetAnalyticsEventType.
searchLogIdstring (max 255)recommendedTies the event to the search session.
conversationIdstring (max 36)noConversation UUID.
productIdstring (max 255)noRelated product id, when relevant.
userSessionIdstring (max 255)noOpaque user session id.
responseTypestring (max 20)noAgent response type, when relevant.
enricherTypestring (max 30)noEnricher that produced the event.
positionintegernoPosition in the list (impression/click).
metadataobjectnoFree-form pairs key → string | number | boolean (up to 20 entries).

Exact validation: EventRequest in WidgetAnalyticsController.java.

Rate limits

WidgetRateLimitFilter applies a different limit per endpoint family (all per minute, per shop):

Endpoint familyLimit/min
/api/widget/search/*200
/api/widget/suggestions300
/api/widget/compare10
/api/widget/analytics/* (event and events/batch)500
/api/widget/track/* (click, conversion) and the rest100

If you exceed the limit you receive 429 Too Many Requests with Retry-After, X-RateLimit-Limit and X-RateLimit-Remaining. See Authentication → Rate Limits.

Further reading