Widget Integration V2
Integrate the VerifiMe V2 widget with versioned CDN distribution and SRI integrity support
The VerifiMe V2 widget is a drop-in verification UI served from a versioned CDN. Each release is immutable and published with a SHA-384 hash for integrity verification.
Try it live: use the Widget Demo to test the full invite and widget flow against staging or production.
Integration Options
IIFE loads via a plain <script> tag with no bundler required. ESM is used as a <script type="module"> CDN include or downloaded for local bundling. Independently of format, Latest is a mutable alias that always serves the current build, while Versioned pins an exact version with a Subresource Integrity hash so the browser verifies the file before executing it. Versioned requires a pinned URL (SRI is incompatible with mutable aliases) and crossorigin="anonymous".
Loading widget versions...
Widget API
Add a container element to your page:
<div id="verifime-widget"></div>When using the ESM build as a local bundle, import the default export:
import VerifimeWidget from "./verifime-widget.esm.js";Then initialise the widget:
const instance = VerifimeWidget(selector, trackingReference, options);On unmount:
instance.destroy();| Parameter | Type | Description |
|---|---|---|
selector | string | CSS selector for the container element, e.g. "#verifime-widget" |
trackingReference | string | UUID returned by POST /v1/user/invite |
options.onSuccess | () => void | See onSuccess() below. |
options.onError | (err: { code: string; message: string }) => void | Called on network error, API error, or polling timeout |
options.email | string (optional) | Pre-fills the email field on the widget form |
options.cspNonce | string (optional) | Pass your server-generated CSP nonce if your Content-Security-Policy uses style-src 'nonce-...'. Applied to inline styles injected by the widget. See CSP Requirements below. |
options.assetMode | 'data' | 'url' (optional, default 'data') | Font loading strategy. 'data' bundles the Outfit font as a base64 data URI (requires font-src data:). 'url' loads it from the widget CDN (requires font-src https://widget.verifime.com). See CSP Requirements below. |
Return value: { destroy() } stops the status poller and removes the widget from the DOM. Always call this on unmount to prevent the status poller running in the background after the widget is removed.
Framework usage
useEffect(() => {
if (!window.VerifimeWidget) return;
const instance = window.VerifimeWidget(
"#verifime-widget",
trackingReference,
{
onSuccess: () => console.log("completed"),
onError: (err) => console.error(err),
}
);
return () => instance?.destroy();
}, [trackingReference]);
return <div id="verifime-widget" />;Always return a cleanup function from useEffect (return () => instance?.destroy()) to stop the status poller and remove the widget DOM on unmount. Without this, React strict mode double-mount will initialise two widget instances and leak the poller.
<template>
<div id="verifime-widget"></div>
</template>
<script setup>
import { onMounted, onUnmounted } from "vue";
const props = defineProps({ trackingReference: String });
let instance;
onMounted(() => {
instance = window.VerifimeWidget("#verifime-widget", props.trackingReference, {
onSuccess: () => console.log("completed"),
onError: (err) => console.error(err),
});
});
onUnmounted(() => {
instance?.destroy();
});
</script>import { Component, Input, OnInit, OnDestroy } from "@angular/core";
@Component({
selector: "app-verification",
template: `<div id="verifime-widget"></div>`,
})
export class VerificationComponent implements OnInit, OnDestroy {
@Input() trackingReference!: string;
private widgetInstance: { destroy(): void } | null = null;
ngOnInit(): void {
this.widgetInstance = (window as any).VerifimeWidget(
"#verifime-widget",
this.trackingReference,
{
onSuccess: () => console.log("completed"),
onError: (err: any) => console.error(err),
}
);
}
ngOnDestroy(): void {
this.widgetInstance?.destroy();
}
}const instance = VerifimeWidget("#verifime-widget", trackingReference, {
onSuccess: () => console.log("completed"),
onError: (err) => console.error(err),
});
// On teardown (page navigation, SPA route change, component unmount):
instance.destroy();CSP Requirements
If your page uses a Content-Security-Policy header, the required directives depend on the assetMode option and the environment you are integrating against.
| Directive | assetMode: 'data' (default) | assetMode: 'url' |
|---|---|---|
script-src | https://widget.verifime.com | https://widget.verifime.com |
style-src | 'nonce-...' or 'unsafe-inline' | 'nonce-...' or 'unsafe-inline' |
font-src | data: | https://widget.verifime.com |
img-src | https://qr-code.prod.verifime.com | https://qr-code.prod.verifime.com |
connect-src | https://api.prod.verifime.com | https://api.prod.verifime.com |
| Directive | assetMode: 'data' (default) | assetMode: 'url' |
|---|---|---|
script-src | https://widget.verifime.com | https://widget.verifime.com |
style-src | 'nonce-...' or 'unsafe-inline' | 'nonce-...' or 'unsafe-inline' |
font-src | data: | https://widget.verifime.com |
img-src | https://qr-code.dev.verifime.com | https://qr-code.dev.verifime.com |
connect-src | https://api.stage.verifime.com | https://api.stage.verifime.com |
Use assetMode: 'url' if your policy forbids data: URIs. The font-src domain is the same as script-src, so no new domain needs whitelisting.
Pass cspNonce to use nonce-based style-src instead of 'unsafe-inline'. The nonce is applied to all style elements the widget injects.
Strict CSP example
For integrators whose policy forbids data: URIs, use assetMode: 'url' together with cspNonce:
VerifimeWidget("#verifime-widget", trackingReference, {
cspNonce: "your-nonce-here",
assetMode: "url",
});Set the following Content-Security-Policy header value:
script-src https://widget.verifime.com; style-src 'nonce-your-nonce-here'; font-src https://widget.verifime.com; img-src https://qr-code.prod.verifime.com; connect-src https://api.prod.verifime.comscript-src https://widget.verifime.com; style-src 'nonce-your-nonce-here'; font-src https://widget.verifime.com; img-src https://qr-code.dev.verifime.com; connect-src https://api.stage.verifime.comWidget Behaviour
The widget polls the tracking status API using exponential backoff (starting at 1s, capping at 10s), pauses when the browser tab is hidden, and resumes on visibility. Polling stops after 30 minutes; if no terminal status is reached by then, onError is called with code: "TIMEOUT". The widget updates its display accordingly:
| Status | Display |
|---|---|
Inactive | QR code and "Verify with VerifiMe" button |
Active | "Verifying with VerifiMe" message with spinner |
Completed | Triggers onSuccess() |
Callbacks
onSuccess() is called when the customer completes data entry (Phase 1). It does not confirm that identity verification or risk assessment is complete. Those are asynchronous processes confirmed via webhook.
onError(err) is called on technical errors such as network failures, API errors, or polling timeout. The err object contains a code and message:
code | When |
|---|---|
NETWORK_ERROR | Request to the status API failed (no response) |
API_ERROR | Status API returned an error response |
TIMEOUT | Polling stopped after 30 minutes without a terminal status |
Versioning Policy
| Environment | API endpoint baked in | Version |
|---|---|---|
staging | api.stage.verifime.com | Tracked independently (e.g. 2026-03-30.2) |
production | api.prod.verifime.com | Tracked independently (e.g. 2026-03-30.4) |
Versioned files are immutable. Once published they never change.
Migration from V1
The API signature is identical. Two changes are required:
-
Update the script URL:
Before (V1) After (V2) widget.static.prod.verifime.com/widgets/verifime-widget.min.jswidget.verifime.com/widget/production/latest/verifime-widget.iife.jswidget.static.stage.verifime.com/widgets/verifime-widget.min.jswidget.verifime.com/widget/staging/latest/verifime-widget.iife.js -
Call
destroy()on cleanup: V2 returns an instance object. Store it and callinstance.destroy()before re-initialising or on component unmount. V1 had no return value and no cleanup mechanism.