> ## Documentation Index
> Fetch the complete documentation index at: https://docs.narrativebanking.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Common integration issues and how to resolve them.

Use this page as your first stop when the SDK fails to load, the embedded widget does not render, or downstream requests do not behave as expected.

Each issue below is organised by **symptom**, **cause**, and **fix** so your team can isolate the problem quickly before reaching out for help.

## Token & authentication issues

<AccordionGroup>
  <Accordion title="1. Invalid signature">
    **Symptom:** The SDK shows an authentication error, or the embedded experience never boots.

    **Cause:** The Embed Token was signed with the wrong secret, or the secret does not match the Connected App identified by `iss`.

    **Fix:** Verify that `iss` matches your `NSDK_CONNECTED_APP_CLIENT_ID` and that the token is signed with the matching `NSDK_CONNECTED_APP_SECRET_KEY` on your backend only.
  </Accordion>

  <Accordion title="2. Invalid audience">
    **Symptom:** Token validation fails even though the token structure looks correct.

    **Cause:** The `aud` claim is set to the wrong value.

    **Fix:** Set `aud` exactly to `nsdk-embed`. Do not reuse access-token or refresh-token audiences from other systems.
  </Accordion>

  <Accordion title="3. Clock skew or wrong time unit">
    **Symptom:** Newly minted tokens are treated as expired or not yet valid.

    **Cause:** `iat` and `exp` were generated in milliseconds instead of seconds, or the backend server clock is out of sync.

    **Fix:** Generate `iat` and `exp` as Unix timestamps in **seconds** and keep your backend clock synchronized with a reliable time source.
  </Accordion>

  <Accordion title="4. Missing required claims">
    **Symptom:** The SDK rejects the token immediately during validation.

    **Cause:** One or more required claims are missing or empty.

    **Fix:** Include `iss`, `sub`, `aud`, `iat`, `exp`, and `jti` on every token. Also provide `nsdk.user.name` and `nsdk.user.email` so the embedded session has the expected user context.
  </Accordion>

  <Accordion title="5. Embed token expired before use">
    **Symptom:** The token works in local testing sometimes, but fails in real user flows or after page delays.

    **Cause:** The token is minted too early, cached too long, or given an unnecessarily short lifetime.

    **Fix:** Fetch the token only after the tenant user session is established and close to mount time. Keep the TTL short but practical, typically 5–15 minutes.
  </Accordion>
</AccordionGroup>

## Frontend & embedding issues

<AccordionGroup>
  <Accordion title="6. Loader script not loading">
    **Symptom:** `NSDK` is undefined, or `nsdk-loader.js` never appears in the browser network log.

    **Cause:** `NSDK_BASE_URL` is wrong, the script URL is blocked by CSP, or the browser cannot reach the hosted SDK origin.

    **Fix:** Confirm the exact loader URL, open it directly in the browser, and allow the SDK origin in your `script-src` policy where required.
  </Accordion>

  <Accordion title="7. Container not detected">
    **Symptom:** The page loads successfully but no widget appears.

    **Cause:** The mount container is missing, rendered too late, uses the wrong selector, or is missing required declarative attributes.

    **Fix:** For declarative mode, ensure the container exists before the SDK initializes and includes `data-nsdk="true"`. For imperative mode, confirm the `mount` selector resolves to exactly one element.
  </Accordion>

  <Accordion title="8. Iframe blocked by CSP">
    **Symptom:** The loader runs, but the embedded frame is blocked or the browser console shows CSP errors.

    **Cause:** Your host application does not allow the SDK origin in `frame-src`, `child-src`, or related policies.

    **Fix:** Update your CSP to allow the Narrative SDK origin for framed content and any required network requests from the embedded experience.
  </Accordion>

  <Accordion title="9. Token not reaching the iframe">
    **Symptom:** The container is present, but the embedded experience behaves as if no token was supplied.

    **Cause:** The token is set after boot, the wrong attribute or property is used, or the runtime reads the container before the token handoff completes.

    **Fix:** In declarative mode, set `data-nsdk-token` before the SDK boots. In imperative mode, pass `embedToken` directly in `NSDK('boot', ...)` and confirm the token value is not empty.
  </Accordion>
</AccordionGroup>

## Backend & network issues

<AccordionGroup>
  <Accordion title="10. CORS blocks token endpoint">
    **Symptom:** The frontend cannot fetch the Embed Token even though the backend route exists.

    **Cause:** The token endpoint is on a different origin and CORS is not configured for the tenant frontend.

    **Fix:** Prefer a same-origin token route. If cross-origin is required, explicitly configure CORS for the tenant frontend origin and any credentialed requests.
  </Accordion>

  <Accordion title="11. Token endpoint is not authenticated">
    **Symptom:** The wrong user receives a token, or unauthenticated requests can still mint one.

    **Cause:** The backend route trusts browser input without validating the tenant application's own authenticated user session.

    **Fix:** Require an authenticated tenant session on the backend before minting each token, and derive the token subject from trusted server-side user context.
  </Accordion>
</AccordionGroup>

## Session & runtime issues

<AccordionGroup>
  <Accordion title="12. Widget renders but shows an unauthenticated state">
    **Symptom:** The shell or frame appears, but the user is shown a restricted or unauthenticated experience.

    **Cause:** The token was minted for the wrong tenant user, the tenant session changed before boot, or a stale token was reused.

    **Fix:** Mint a fresh token for the current authenticated tenant user, avoid browser-side token storage, and retry the flow with a newly issued token.
  </Accordion>

  <Accordion title="13. Widget stops working after SPA navigation">
    **Symptom:** The widget works on the first route load but breaks after navigating within a single-page application.

    **Cause:** The host app unmounted the container, reused a stale DOM node, or never cleaned up a previous runtime instance.

    **Fix:** Recreate the mount container on route entry, re-run boot when the page remounts, and call `NSDK('destroy')` during cleanup when using imperative mode.
  </Accordion>
</AccordionGroup>

## Data & product surface issues

<AccordionGroup>
  <Accordion title="14. API returns 401 after successful embed">
    **Symptom:** The embedded widget boots, but downstream product requests still return `401`.

    **Cause:** Bootstrap succeeded, but the requested product surface, tenant mapping, or user-level access is not ready for the downstream request.

    **Fix:** First confirm the widget booted with a fresh token. Then verify the user, tenant, and product surface access expected by the destination API or experience.
  </Accordion>

  <Accordion title="15. Data sync delays or missing data">
    **Symptom:** The widget loads, but expected account, transaction, or customer data is missing or stale.

    **Cause:** Upstream data has not finished syncing yet, the wrong environment is being tested, or the tenant-user mapping does not line up with the source data.

    **Fix:** Confirm the correct environment, allow time for source-data processing, and validate that the target tenant user has the expected records available to the provisioned experience.
  </Accordion>

  <Accordion title="16. Different-currency bank account is rejected">
    **Symptom:** A user tries to add another bank account, but the connection is rejected with a currency-related message.

    **Cause:** Narrative SDK supports multiple connected accounts only when those accounts use the same currency. Multi-currency account support is outside the current release.

    **Fix:** Continue with same-currency accounts for this user. If multi-currency support is required, include the user email, attempted currency, provider, and approximate timestamp in the support request.
  </Accordion>

  <Accordion title="17. Money page appears empty immediately after onboarding">
    **Symptom:** A newly onboarded user reaches Money but does not immediately see the expected fresh metrics or actions.

    **Cause:** Onboarding completion and Money data readiness can happen close together, and some views may need the latest available snapshot to finish preparing.

    **Fix:** Refresh the page after setup completes. If the issue persists, include the user email, approximate completion time, and environment in the support request.
  </Accordion>
</AccordionGroup>

## Still stuck?

<Info>
  If you are still blocked after working through this guide, use [Support](/sdk/support) for the contact path and the checklist of details to include in your request.
</Info>
