Skip to main content
By the end of this guide the KYC Widget will be running in your app, mounted to a container, and emitting events you can react to.

Before you start

Before you can test the KYC Widget in Sandbox or Production, Uphold must complete a one-time internal setup to enable identity verification for your account. Contact your Account Manager to have this provisioned ahead of your integration.
You’ll need:
  • Access to Widgets API to create widget sessions. Manage your access in Enterprise Portal.
  • A backend that can call the Widgets API to create sessions on behalf of your users.
  • A frontend — a web app, or a native app with a WebView — to embed the Widget.
The Widget runs from one of two hosts depending on environment:

Choose an integration approach

We recommend integrating without the SDK for native apps — it’s simpler to set up. For web-only integrations, the SDK is a solid default. There are two ways to embed the Widget:
  • Web SDK — Install @uphold/enterprise-kyc-widget-web-sdk for a better developer experience — typed events and a more streamlined integration on web. For native apps, the SDK must be bundled into the WebView’s HTML page.
  • JavaScript — Listen for the Widget’s messages over the iframe or WebView and respond to them directly. This is also the simpler option for native apps: there’s no SDK to bundle into the WebView’s HTML page.
Both approaches use the same backend step — creating a session via the Widgets API — and emit the same four lifecycle outcomes (ready, complete, cancel, error).

Shared setup

These two steps are identical whichever approach you choose above — do them once, then jump to the matching section below.

1. Create a session on your backend

The KYC Widget runs against a session — a short-lived, server-side authorization scoped to one flow and one user. Create it server-side using your OAuth credentials.
To create a session, you must have the KYC Widget scope.
Never create session directly from the client. Your client secret must not leave your backend.
Call Create session with the verify flow and the processes you want the user to complete:
The response wraps the session object:
Pass response.session to your frontend (e.g. as part of your page response or via your own API endpoint):
  • With the SDK, it’s the single session argument to the KycWidget constructor — see Setup Web SDK.
  • Without the SDK, session.url is what you load directly into your iframe or WebView, and the whole object is what you send back as init — see Setup with JavaScript.

2. Allow the Widget domain in your CSP

If your web app embeds the Widget in an iframe and enforces a Content Security Policy, allow the Widget host for your environment(s) under frame-src.
If your app does not use CSP, skip this step.

Setup with Web SDK

Install the SDK

Install the SDK in the frontend that will host the Widget — your web app, or the JS bundle loaded by your native WebView.

Initialize and mount the Widget

On the frontend, instantiate KycWidget with the session from Create a session on your backend, then mount it into a container element.
The container must have explicit CSS width and height — the iframe fills its bounds. Minimum recommended size is 400px × 600px.
See the SDK reference for full constructor details.

Handle Widget events

The Widget emits four events during its lifecycle. Wire up handlers before calling mountIframe.
The Widget does not unmount itself. You must call widget.unmount() from complete, cancel, and error handlers.
The complete event signals that the user has submitted all required processes — not that verification was approved. Final verification outcomes (e.g. identity approved or rejected) are delivered asynchronously via KYC webhooks. Monitor those server-side to update your user’s status.

Native apps with the SDK

Setup with JavaScript

Instead of installing the SDK, you can load the Widget’s session url directly — as an iframe you create yourself on web, or as your WebView’s top-level page on native — and speak its underlying message protocol directly. This is useful for hosts that can’t ship a JS bundle to their WebView, or want a fully native shell around the Widget.
The Shared setup steps still apply here — you just don’t install anything. Only how you load the Widget and exchange messages changes.

The message protocol

These are the message types the Widget speaks. The transport carrying them differs per platform — see the tabs below. From the Widget to your host: From your host to the Widget: The init payload spreads the session object from Create a session on your backend (url, token, flow, data) alongside an options object with the same shape as the SDK’s KycWidgetOptions — omit options or pass {} to use defaults.

Specifying the theme appearance

By default, the Widget matches the browser or OS prefers-color-scheme until it receives your init reply. To control the initial appearance yourself — and avoid a flash if it won’t match what you send in init — append a theme_appearance query parameter (dark or light) to session.url before loading it:
This works the same whether you load the result into a web iframe or as your native WebView’s top-level page.

Platform implementation

Mount the session url in an iframe you create yourself, and exchange messages over the standard window.postMessage API. Make sure the iframe’s container has explicit CSS width and height (minimum recommended size is 400px × 600px).

Test in Sandbox

With your Sandbox credentials and the Sandbox Widget host configured, run through this checklist — it applies whichever approach you integrated with:
  • The Widget mounts and ready fires.
  • Completing the verification flow fires complete.
  • Closing or dismissing the Widget fires cancel.
  • If your app uses a CSP (see Shared setup), the browser console shows no violations (look for “Refused to frame”).
Once Sandbox is green, swap your OAuth credentials to Production. The Widget host is selected automatically by the session url returned from your backend — no client-side environment switching is needed.

Configuration reference

The most common SDK options. See the SDK reference for the full schema and all event types.
If you’re integrating without the SDK, these map directly to the options object you send in your init reply.

Troubleshooting

Widget not displaying Confirm the Widget host for your environment is in the frame-src directive of your CSP (see Shared setup). Open DevTools → Console and look for Refused to frame violations. Container is empty after mount The iframe fills its container — the container must have explicit CSS width and height. Minimum recommended size is 400px × 600px. Events not firing in native apps (with the SDK) Verify that:
  • JavaScript is enabled in the WebView.
  • The message bridge is registered before the HTML page loads.
  • Event handler names match the platform-specific bridge contract used in sendToNativeApp.
Events not firing (without the SDK) Verify that:
  • Your message-handler / listener name is exactly uphdKycWidget — the name the Widget checks for on both iOS and Android — and is registered before the WebView loads the session url.
  • You’re replying to load with init — the Widget won’t render anything until it receives it.
  • On web, you’re filtering incoming message events by origin (event.origin === sessionOrigin) — messages from other origins should be ignored, not treated as Widget events.
Widget never unmounts. The SDK does not auto-unmount, and neither does the Widget itself when integrating without it. Call widget.unmount() (SDK) or tear down your iframe/WebView (no SDK) from each terminal message (complete, cancel, error).

Next steps

  • Review the complete SDK Reference for all available methods and events.
  • Follow the user onboarding guide for a step-by-step walkthrough of verifying users with the KYC Widget.