SDK reference · Incode Web SDK 2 Reference / Reference

Troubleshooting

Common issues integrators hit and how to resolve them. Also see the per-module pages and Getting Started for setup-level questions.

Camera issues

Issue Solution
Black screen / no camera preview Use HTTPS (or localhost during development) — getUserMedia is gated behind a secure context.
Permission denied User must grant camera access in the browser. Surface the SDK's permissions.denied state and link them to browser-specific instructions.
Camera in use / NotReadableError Another tab or app holds the camera. The SDK can't release a camera held by another process; instruct the user to close other camera consumers.
Camera freezes when remounting Tear down the previous module before mounting a new camera-using module. Call manager.stop() on the old manager / unmount the old element.
iOS Safari: video doesn't play inline The SDK's own <video> elements are tagged playsinline/muted/autoPlay. If you build a custom UI in headless mode, replicate those attributes — without playsinline, iOS opens video full-screen and breaks face detection.

WASM issues

Issue Solution
WASM not loading Confirm setup({ wasm: ... }) actually ran. With CDN defaults, paths are optional; with setup({ wasm: false }) (or omitted), WASM only loads lazily when a selfie or ID-capture step starts.
WASM 404 When self-hosting, verify wasmPath, glueCodePath, and modelsBasePath resolve. The defaults assume models/ lives next to the WASM binary.
CompileError: WebAssembly.compile() Server is returning the WASM file with the wrong MIME type. Configure your host to return Content-Type: application/wasm for .wasm files (Nginx: add to mime.types; Apache: AddType application/wasm .wasm).
RangeError, Failed to load module script Browser is too old or doesn't support WASM SIMD. Check browser support; fall back to non-SIMD by setting setup({ wasm: { useSimd: false } }).
Face/document detection never triggers Model files are missing. Check the network tab for failing requests under modelsBasePath.

See WASM Configuration for the full surface.

Session issues

Issue Solution
"SDK not configured. Call setup({ apiURL: '...' }) first." Call setup({ apiURL }) before createSession() or any module manager method.
"Token is required" Provide token (from createSession()) on <incode-flow>'s config, or use the self-loading variant with apiKey + configurationId (prototyping only).
Token expired mid-flow Tokens have a TTL set per-tenant in the Dashboard. Long verification sessions can outlive the token. Either bump the TTL in the Dashboard or restart the flow with a fresh session.
Invalid API key Verify the key in the Incode Dashboard under Settings → API Keys. Ensure your domain is allowed under CORS.
Invalid configuration Make sure the configurationId exists, is active, and matches the tenant the API key belongs to.
"No registered module found for: <KEY>" A backend-driven step doesn't have a state machine registered in createOrchestratedFlowManager({ modules: ... }). Log flowState.steps after flowManager.load() to see which keys the backend emitted, and register them. See Headless Mode → Module Registration.

Iframe embedding

Issue Solution
Camera prompt doesn't appear in iframe Add allow="camera; microphone" to the iframe element. getUserMedia requires explicit feature-policy delegation across iframe boundaries.
<incode-flow-completed> redirect blocked The default redirect uses window.location.href, which fails if the iframe doesn't have allow-top-navigation (or allow-top-navigation-by-user-activation). Either grant the sandbox permission or set disable-redirect on <incode-flow-completed> and handle navigation from the parent.
Cookies / storage isolation The SDK uses localStorage for some state (e.g. Deepsight session). Browsers in strict-tracking-prevention mode partition third-party iframe storage; if the iframe is cross-origin, plan for state to be scoped per-iframe and not shared with the host.

Mobile Safari

Issue Solution
Camera prompt requires a user gesture Don't auto-trigger manager.requestPermission() (or auto-mount <incode-selfie> / <incode-id>) on page load. iOS Safari blocks getUserMedia outside of user-gesture handlers. Wire it to a tap on a "Continue" button.
Camera fails after device rotation Some iOS versions invalidate the existing MediaStream on orientation change. Listen for orientationchange (or use a screen.orientation-based hook) and call manager.reset() or remount the module to acquire a fresh stream.
Tutorial Lottie animations don't autoplay iOS suspends requestAnimationFrame in background tabs and after user inactivity. Re-trigger the tutorial on focus if needed.

Content Security Policy

If your app uses a strict CSP, the SDK needs:

Directive Why
script-src 'wasm-unsafe-eval' (or 'unsafe-eval' for older browsers) WASM compilation/instantiation needs eval-style permissions.
worker-src blob: Some ML model loading paths spawn workers from blob URLs.
connect-src https://*.incodesmile.com (replace with your environment) XHR/fetch to Incode API endpoints.
img-src 'self' blob: data: Captured frames are rendered to canvas/<img> from blob/data URIs.
media-src 'self' blob: Camera streams.
style-src 'self' 'unsafe-inline' (or hash/nonce) Some module styles inline values during render.

Test against your CSP before deploying — browsers fail silently for some directives, especially WASM-related ones.

Styling issues

Issue Solution
Styles not applied Import @incodetech/web/base.css plus a theme (@incodetech/web/themes/light.css or dark.css), plus per-module CSS like @incodetech/web/flow/styles.css.
Overrides not taking effect Override at :root with --variable: value;. Make sure the override loads after the SDK theme.
Component not visible Parent container needs explicit dimensions. The element has display: block but no intrinsic size — use height: 100vh (or any height) on the parent or a style="display:block; height:100vh" on the element itself.
Brand color tweak doesn't propagate Override the --primitive-color-brand-* scale rather than individual component tokens — semantic and component tokens cascade from the primitives. See Theming & Styling.

Build / TypeScript issues

Issue Solution
Property 'incode-flow' does not exist on type 'JSX.IntrinsicElements' React 18 strict-checks JSX. Add the JSX augmentation from Framework Integration → TypeScript: JSX support for incode-* tags. React 19+ doesn't need this.
<incode-flow config={{token}}> renders nothing on React 18 React 18 serializes JSX props through setAttribute, so object/function props become "[object Object]". Use the ref + useEffect pattern from Framework Integration → Universal pattern. React 19+ can use the simpler form.
Bundle too large Use subpath imports (@incodetech/web/selfie, never the package root). See Bundle Optimization.
Tree-shaking not working Use subpath imports (@incodetech/web/<module>), not the package root. Verify with your bundler's size analyzer.
Circular import or Cannot find module '@incodetech/infra' @incodetech/infra is internal — never import from it directly. Use the @incodetech/core/<subpath> re-exports.

See Bundle Optimization for performance details.

Network issues

Issue Solution
CORS errors on /omni/start (or other API endpoints) Whitelist your domain in the Incode Dashboard.
API requests failing Verify the apiURL matches the environment your API key was issued for (demo vs. production tenants are separate).
Firewall blocking Allow *.incodesmile.com in your egress allow-list (and the CDN domain you point WASM paths at, if self-hosting).
Upload progress stuck at 0% Older browsers don't expose upload progress on fetch. The SDK falls back to XMLHttpRequest when an onUploadProgress callback is set.

Flow-level edge cases

Issue Solution
Selfie ends in closed state and the flow doesn't continue closed is final — the manager won't transition further on its own. In orchestrated flows, call flowManager.completeModule(). In standalone usage, navigate the user out. See Module: Selfie → Handling cancellation.
ID capture stuck on capture.success Call idManager.nextStep() to advance to frontFinished or processing. The state machine waits for the explicit advance.
expired state — reset() does nothing The expired state only responds to RETRY_CAPTURE. Call idManager.retryCapture().
Mandatory consent screen shows for every flow The screen only renders when the upload response sets showMandatoryConsent: true, which is driven by regulationType in the session. Verify the configuration in the Dashboard.

Getting help

  1. Check the browser console for SDK errors. The SDK prefixes most warnings/errors clearly.
  2. Inspect the Network tab — failing API requests usually have a meaningful error body.
  3. Subscribe to flow events via subscribeEvent from @incodetech/core/events to capture the SDK's analytics stream — useful when reproducing issues for support.
  4. Contact support@incode.com with: SDK alpha version, browser + OS, the failing flow's configurationId, and the steps to reproduce.
Was this page helpful?