Troubleshooting
Partial batches (HTTP 207), rejected or unknown event codes, and conversions that fail.
The fastest way to debug an install is to send traffic with the development key and open Dev mode: every request shows up live with the reason it failed and how to fix it. Add debug: true to orwel.init() to see the SDK logs in the browser console.
How the ingest answers
| Endpoint | Status | Meaning |
|---|---|---|
POST /ingest |
200 |
The event was stored. |
POST /ingest |
400 |
The event was rejected. The body says why, for example Event not found: <code>. |
POST /ingest/batch |
200 |
Every event in the batch was stored. |
POST /ingest/batch |
207 |
Some events were stored and some were not. The refused events are in failedEvents. |
POST /ingest/batch |
400 |
The batch itself is invalid: bad JSON, missing batchId, count or events, count not equal to the number of events, more than 100 events, or a bad key. Nothing was stored. |
POST /ingest/batch |
500 |
No event in the batch could be stored. |
A 207 body looks like this:
{
"success": false,
"error": "Some events failed to process",
"code": "VALIDATION_ERROR",
"details": {
"processed": 9,
"failed": 1,
"batchId": "batch_1760000000000_k2j3h4",
"failedEvents": [ { "type": "track", "code": "quote_sent", "...": "..." } ]
}
}The SDK does not retry rejected events, because resending an invalid event would loop forever. Since SDK 1.7.1 a 400 is logged in the console with the server response and the rejected codes before the events are discarded:
Batch rejected (400) - events DISCARDED, not retrying { codes: [...], serverResponse: "..." }
Event rejected (400) - DISCARDED, not retrying { code: "...", serverResponse: "..." }
A 207 counts as delivered for the SDK, so the events it refused are not logged in the console. Use Dev mode to see them.
Events rejected as unknown
Symptom: some track() calls never appear, the batch answers 207 (or 500 if every event failed), and Dev mode shows event_not_found.
Cause: the server only accepts track() codes that exist in your workspace catalog: the Orwel catalog plus the custom codes your workspace registered. Codes are not created on the fly.
Fix:
- Open Journeys setup or Features setup in the Development section, add the code to a journey or feature (from the catalog, or as a Custom event) and save. See Journeys and features setup.
- Or change your code to an existing catalog code.
- Check the Status tab: the code should move from "Not registered" to "Tested" once it arrives with the development key.
Conversions are not gated by the catalog, so this never affects conversion().
Events lost on large flushes (SDK before 1.7.1)
Symptom: pages that fire many events (long sessions, heavy auto detection) lose whole blocks of events, with nothing in the console and nothing on the server.
Cause: before 1.7.1 the SDK posted the whole queue (up to 1000 events) in one batch. The server caps a batch at 100 events and answers 400, and older SDKs treated that 400 as "do not retry" without logging anything.
Fix: update the SDK. 1.7.1 sends the queue in chunks of 100.
npm i orwel@latestA conversion fails or never shows up
conversion() is async and resolves with the real outcome. Read it:
const { success, reason } = await orwel.conversion('demo_request', { email })
if (!success) console.warn('Orwel conversion failed:', reason)reason |
What happened | Fix |
|---|---|---|
visitor_unresolved |
The visitor id did not resolve within 5 seconds, so the conversion was not sent (it would have arrived with no visitor). | Make sure orwel.init() runs early on every page, before the form can be submitted, and that requests to api.orwel.io are not blocked (ad blockers, a strict Content Security Policy). |
delivery_failed |
The request was sent but the server did not acknowledge it (network error, timeout, or a rejection). | Check the console with debug: true and the request in Dev mode. |
error |
Something threw inside the SDK. | Check the console with debug: true. |
If conversion() throws instead of resolving, the input is invalid: the code is not snake_case, the properties are not an object, or an email field is not a valid address.
The conversion arrives but the lead looks wrong
| Symptom | Cause | Fix |
|---|---|---|
| No notification email, lead not enriched | No email (or phone) in the conversion properties or a previous identify(). |
Pass email in the conversion properties. |
| The lead shows as direct or organic | The landing URL had no UTMs or ad click ids. | Tag your ads and links (see Attribution). Test with ?utm_source=test. |
| Two leads for one submit | SDK before 1.6 had no conversionId, so retries were not deduplicated exactly. |
Update the SDK. |
The conversion is missing after a successful submit and a form_abandon appears instead |
The form was unmounted before the conversion was sent, or orwel.form() with trackAbandon saw the form disappear. |
await orwel.conversion() before showing the success state, and do not combine orwel.form() with a manual conversion on the same form. |
| The lead has a Dev badge and no integrations ran | It was sent with the development key. | Expected. Use the production API key in production. |
init() throws
apiKey must start with "orwel_"orappears to be invalid (too short): the environment variable is empty or wrong. Check the variable name for your framework (for exampleNEXT_PUBLIC_ORWEL_KEY,PUBLIC_ORWEL_KEY,VITE_ORWEL_KEY).config must be an object: callorwel.init({ apiKey }), notorwel.init(apiKey).
API and MCP
401with a public or development key: those keys only send data. Create an API key (orwel_sk_) to read.403from a browser: the page's origin is not in the key's allowed origins, or the key is server only.403 plan_not_allowedon/mcp: the workspace has no active subscription.