Skip to main content

Troubleshooting

The errors you will see when integrating Neuroon and the direct solution.

401 Unauthorized — expired token

Your Widget Token expired (TTL: 24 hours).

Solution:

curl -X POST https://api.neuroon.ai/api/shops/$SHOP_ID/widget-token \
-H "X-Shop-API-Key: $API_KEY"

Cache the new token and replace data-token. If this happens repeatedly, schedule rotation every 23 hours from your server.

401 Unauthorized — invalid Shop API Key

You are calling /api/plugin/shops/... with a key that does not match the shopId in the URL, or the key does not exist.

Verify:

  1. The key is in the dashboard, in the correct shop.
  2. The key starts with sk_ and is 35 characters total.
  3. You are NOT mixing Production (api.neuroon.ai) with Development (dev-api.neuroon.ai).

403 Forbidden — Origin mismatch

The browser is loading the widget from a domain that does not match the registered URL of your shop.

Solution:

  1. Go to https://neuroon.ai/dashboard → your shop → Settings and check that URL points to your real domain.
  2. If you have multiple domains (staging.yourshop.com + yourshop.com), contact support to add additional origins.

403 Forbidden — Domain not verified

Your domain is not verified yet.

Solution:

  1. Dashboard → your shop → Verify domain → follow the instructions (add the meta tag or DNS record).
  2. Call /api/plugin/shops/{shopId}/verify again.

429 Too Many Requests

You exceeded the rate limit of a specific endpoint.

Solution: read the Retry-After header (in seconds) and wait. Implement exponential backoff:

async function withRetry(fn, max = 3) {
for (let i = 0; i < max; i++) {
const res = await fn();
if (res.status !== 429) return res;
const wait = (parseInt(res.headers.get('retry-after')) || 2 ** i) * 1000;
await new Promise(r => setTimeout(r, wait));
}
throw new Error('Rate limit exceeded after retries');
}

See Rate limits for exact per-endpoint values.

CORS error in the browser

Your frontend is calling /api/plugin/shops/... directly from the browser. That does not work and is not meant to: the plugin endpoint is server-to-server.

Solution: move that call to your backend. The browser should only call /api/widget/* with X-Widget-Token. To sync products, generate tokens and track conversions server-side, everything goes from your server.

Widget does not appear / blank screen

First, open the browser console.

SymptomCauseFix
data-token is emptyYour template is not printing the tokenPrint the token from your server with the right template engine syntax (<%= token %>, {{ token }}, ${token})
Failed to load https://cdn.neuroon.ai/widget.jsCSP blocks the CDNAdd script-src https://cdn.neuroon.ai and connect-src https://api.neuroon.ai to your Content-Security-Policy
Widget loads but searches yield 0 resultsProducts not indexed yetWait 2-5 seconds after sync. If still empty after 30 s, check the 200 OK from sync had newProducts: N with N > 0
VerificationHow
Sync returned newProducts > 0 and failed: 0Check the JSON response from POST products/sync
More than 5 s elapsed since 200 OKWait. Indexing is eventual (typically 2-5 s)
externalId and url are not emptyThe backend rejects products with empty required fields

If everything is correct and it doesn't appear in 30 s, contact support with your shopId and the affected externalId.

Errors on the sync endpoint (400)

If you receive 400 Bad Request when syncing, the response body includes errors with details:

{
"totalReceived": 2,
"newProducts": 1,
"failed": 1,
"errors": [
{ "externalId": "abc-123", "error": "name must not be blank" }
]
}

Required validations:

  • externalId not empty
  • name not empty, max 512 characters (@Size(max=512) in ShopRequestDTO.java:72)
  • price ≥ 0
  • currency ISO 4217 (3 letters: EUR, USD, MXN...)
  • valid url

Still stuck

Support — include in your message:

  • shopId
  • Endpoint you were calling
  • Request body (without secrets)
  • Response status code and body
  • Approximate time (UTC) so we can correlate.