Reference

Troubleshooting

The snags people actually hit: a CORS error that is really a 500, walkthroughs that come back empty, and steps that show text but never point at anything.

A CORS error, or a 500 on the preflight

If the browser reports a CORS failure and the preflight OPTIONS request returns a 500 with no CORS headers, the cause is almost always that your origin is not allowed and the backend rejected it by throwing rather than denying cleanly.

  • The origin must match exactly. http://localhost:3000, http://localhost:3001, and https://yourapp.com are three different origins. Scheme, host, and port all count.
  • For a distributed SDK you should not hand-list every origin globally. Keep the SDK routes open at the CORS layer and gate origins per key, through the publishable key's own origin allowlist.

Find the exact origin

The browser console names it: "from origin 'X' has been blocked". Allow X verbatim.

The walkthrough comes back empty

You ask for something and get "no walkthrough matches that yet". Open the network tab: you will usually see a match call that found nothing, then a generate call that also returned empty.

The reason is almost always missing vocabulary. The generator will not invent selectors, so on a site it knows nothing about it has nothing to build from. Populate vocabulary (upsert a few elements, crawl, or import) and the same request generates a real walkthrough.

Steps show text but do not point at anything

The walkthrough starts, the card shows the instruction, but no cursor lands on an element. That means the step's selector did not match anything on the page.

  • Confirm the element exists when the step runs. In single-page apps it may render after a delay; the SDK retries briefly, but a slow async element can still miss.
  • Prefer a stable data-nudge-id over a structural selector. A :nth-child selector breaks the moment the layout shifts.
  • Set fallback_selectors on the step so a single change does not break it.

The launcher never appears

  • Check mount() actually ran, in the browser, after init().
  • If you render on the server, the call must be client-only. Running it during SSR does nothing because there is no window.
  • If you set trigger: { mode: "programmatic" }, there is no launcher by design. Start walkthroughs from your own UI.
  • Check the console and network tab for a failed load or a 401 from a bad key.

Requests return 401

The key was rejected. Either it is wrong, revoked, or it is a secret key used in the browser. Secret keys (sk_) are server-only; the browser must use a publishable key (pk_). If the key has an origin allowlist, the request must come from one of those origins.

A real 500 on a route (not the preflight)

If a request still 500s after CORS is sorted, it is a server-side error. Check your backend logs for the stack trace. Common causes are a missing environment variable (the backend hard-fails in production without REDIS_URL, for instance) or a database call hitting a table that was not migrated. The trace names the exact line.