Troubleshooting

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

📘

This guide is specific to Web SDK 2.0. If you are still using 1.x, you can find documentation here. We strongly recommend upgrading - contact your Incode Representative for upgrade information.

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

Camera issues

IssueSolution
Black screen / no camera previewUse HTTPS (or localhost during development) — getUserMedia is gated behind a secure context.
Permission deniedUser must grant camera access in the browser. Surface the SDK's permissions.denied state and link them to browser-specific instructions.
Camera in use / NotReadableErrorAnother 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 remountingTear 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 inlineThe 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

IssueSolution
WASM not loadingConfirm 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 404When 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 scriptBrowser 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 triggersModel files are missing. Check the network tab for failing requests under modelsBasePath.

See WASM Configuration for the full surface.

Session issues

IssueSolution
"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-flowTokens 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 keyVerify the key in the Incode Dashboard under Settings → API Keys. Ensure your domain is allowed under CORS.
Invalid configurationMake 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

IssueSolution
Camera prompt doesn't appear in iframeAdd allow="camera; microphone" to the iframe element. getUserMedia requires explicit feature-policy delegation across iframe boundaries.
<incode-flow-completed> redirect blockedThe 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 isolationThe 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

IssueSolution
Camera prompt requires a user gestureDon'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 rotationSome 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 autoplayiOS 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:

DirectiveWhy
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

IssueSolution
Styles not appliedImport @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 effectOverride at :root with --variable: value;. Make sure the override loads after the SDK theme.
Component not visibleParent 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 propagateOverride the --primitive-color-brand-* scale rather than individual component tokens — semantic and component tokens cascade from the primitives. See Theming & Styling.

Build / TypeScript issues

IssueSolution
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 18React 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 largeUse subpath imports (@incodetech/web/selfie, never the package root). See Bundle Optimization.
Tree-shaking not workingUse 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

IssueSolution
CORS errors on /omni/start (or other API endpoints)Whitelist your domain in the Incode Dashboard.
API requests failingVerify the apiURL matches the environment your API key was issued for (demo vs. production tenants are separate).
Firewall blockingAllow *.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

IssueSolution
Selfie ends in closed state and the flow doesn't continueclosed 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.successCall idManager.nextStep() to advance to frontFinished or processing. The state machine waits for the explicit advance.
expired state — reset() does nothingThe expired state only responds to RETRY_CAPTURE. Call idManager.retryCapture().
Mandatory consent screen shows for every flowThe 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 [email protected] with: SDK alpha version, browser + OS, the failing flow's configurationId, and the steps to reproduce.