Widget
Mobile apps
Run the widget in a WebView on iOS, Android, React Native or Flutter.
Create a native session
On your backend, create the session with origin: "native". A native session
can never be framed by a website, so it needs no origin allowlist entry.
const s = await verifyme.widget.createSession({ target: phone, origin: "native", client_reference: user.id })
return { token: s.widget_token }Load the frame as the WebView's page
https://verifyme.cubis.tech/widget/frame/<widget_token>Saved branding applies automatically. To override it, append
?c=<base64url(JSON.stringify({ theme, labels }))>.
Listen for the result
The frame posts a JSON string
{"ns":"verifyme","v":1,"type":"success","proof":"vp_…","expiresIn":300}
(also error and resize) to the first bridge it finds:
| Platform | Bridge |
|---|---|
iOS WKWebView | WKScriptMessageHandler named verifyme (body is an object) |
Android WebView | addJavascriptInterface(obj, "VerifymeBridge") with @JavascriptInterface fun postMessage(json: String) |
| React Native | <WebView onMessage={(e) => JSON.parse(e.nativeEvent.data)} /> |
| Flutter | JavaScriptChannel named VerifymeBridge |
<WebView
source={{ uri: `${HOST}/widget/frame/${token}` }}
onMessage={(e) => {
const m = JSON.parse(e.nativeEvent.data)
if (m.ns === "verifyme" && m.type === "success") complete(m.proof)
}}
/>Redeem on your backend
Send the proof to your API and redeem it exactly as for the web. Never ship the API key inside the app.