Saltar al contenido principal

Venta cruzada

Cuando el host tiene cart.enabled = true, el widget puede pedir al backend recomendaciones complementarias para el carrito actual: productos que suelen comprarse junto a los items presentes, descartando los que ya están en el carrito o que ya viste. Se renderiza con CrossSellSection.

Endpoint

POST/api/widget/cart/cross-sell
curl -X POST https://api.neuroon.ai/api/widget/cart/cross-sell \
-H "X-Widget-Token: $WIDGET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"productIds": ["p_iphone_15"],
"language": "es"
}'

Definido en WidgetProductController.java (body: CartCrossSellRequestDTO { productIds: string[], language?: string }). Devuelve { message, products[] }. Si no hay recomendaciones aplicables, responde 204 No Content sin body.

Diferencia con cartAction.ADD_SUGGESTION

Hay dos canales por los que el widget recomienda añadir un producto:

CanalOrigenUX
POST /api/widget/cart/cross-sellEl widget invoca el endpoint cuando se monta el cart drawer o tras cambios de itemsSección con varios productos en el drawer / página de carrito.
cartAction.ADD_SUGGESTION en SearchResponseEl agente conversacional decide proactivamente (durante búsqueda) que tiene sentido sugerir un producto concretoTarjeta premium con confirmationPrompt, una sola sugerencia.

Ranking

El backend usa señales como:

  • Co-compra histórica (carritos cerrados con ambos productos).
  • Compatibilidad de categoría (regla declarativa por shop).
  • Margen y stock (penaliza out-of-stock).
  • Reduplicación (no devuelve productos ya en el carrito).

El motor de recomendaciones está en el engine Python, no en este repo del widget. Si necesitas inspeccionar la lógica concreta, abre un issue a soporte.

Cuándo se invoca

  • Al abrir el drawer del carrito si no hay datos cacheados.
  • Cuando el drawer está abierto y cambian los items del carrito (debounce 600 ms en useCartCrossSell.ts:90). El listener no se dispara automáticamente con cada neuroon:cart-update — sólo cuando el drawer está visible.
  • Manual: widget.openCart().

Tracking

Click en una card de cross-sell se reporta como evento normal (POST /api/widget/track/click) con metadata.source = 'cross_sell', lo que permite medir incremento real vs base.

Próximas lecturas