When it comes to identity verification with Verisync in your mobile applications, there are two ways to go about it:
Using the Verisync library built for your tech stack of choice - You can integrate Verisync directly into your Android or iOS app using our mobile SDK. For mobile frameworks like Ionic or React Native, please find the libraries
Using a WebView - You can use the synchronizer URL and embed it in a WebView on your mobile application. We'll be covering this option in this guide.
Code snippets
For the purposes of this guide, we'll include sample code for mobile apps built using Flutter, React Native, native Android, and iOS, but the flow described works for all the mobile app development stacks
Why use a WebView?
There are different reasons to consider using the hosted checkout in a WebView over integrating directly with the mobile SDK. Regardless of which method you choose, the verification are still being processed by the same underlying APIs. The only difference is the verification experience you'll be offering to your users. Some of the pros of using a WebView are:
By using our hosted checkout, the entire payment experience is controlled by Verisync. This means you don't have to build a checkout UI in your mobile application for identity verification, hence less code is required to integrate it.
Configuring the synchronizer URL
GET https://app.verisync.co/synchronizer/authorize?flow_id=:flow_id&client_id=:client_id&redirect_url=:redirect_url&metadata=:metadata
Parameter name
Type
Required
Description
flow_id
string
true
The id of the flow created of the request user info
client_id
string
true
The client ID you received from Verisync it's on your dashboard integration page
redirect_url
string
true
The URL where your users will be sent after authorization.
email
string
false
The user email address
metadata
object
false
Stringified JSON object of custom data.
Displaying Synchronizer in Your WebView
If the url config is correct, then load the Webview widget. See the sample code below:
import React from 'react';
import { WebView } from 'react-native-webview';
export default function App() {
const synchronizer_url = 'https://app.verisync.co/synchronizer/authorize?flow_id=:flow_id&client_id=:client_id&redirect_url=:redirect_url&metadata=:metadata';
const redirect_url = 'https://yourredirecturl.com';
const cancel_url = "https://yourcancelurl.com";
onNavigationStateChange = state => {
const { url } = state;
if (!url) return;
if (url === callback_url) {
const redirectTo = 'window.location = "' + callback_url + '"';
this.webview.injectJavaScript(redirectTo);
}
if (url === cancel_url) {
// handle webview removal
// You can either unmount the component, or
// Use a navigator to pop off the view
// Run the cancel payment function if you have one
}
};
return (
<WebView
source={{ uri: authorization_url }}
style={{ marginTop: 40 }}
onNavigationStateChange={ this.onNavigationStateChange }
/>
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: WebView(
initialUrl: 'https://app.verisync.co/synchronizer/authorize?flow_id=:flow_id&client_id=:client_id&redirect_url=:redirect_url&metadata=:metadata',
javascriptMode: JavascriptMode.unrestricted,
userAgent: 'Flutter;Webview',
navigationDelegate: (navigation) {
//Listen for redirect URL
if (navigation.url == ":redirect_url") {
Navigator.of(context).pop(); //close webview
}
if (navigation.url == "https://your-cancel-url.com") {
//handle webview removal
Navigator.of(context).pop(); //close webview
//Run the cancel payment function if you have one
}
return NavigationDecision.navigate;
},
),
);
}
class MainActivity : AppCompatActivity() {
private val synchronizerUrl: String
get() = "https://app.verisync.co/synchronizer/authorize?flow_id=:flow_id&client_id=:client_id&redirect_url=:redirect_url&metadata=:metadata"
private val redirectUrl: String
get() = "https://yourredirecturl.com"
private val cancelUrl: String
get() = "https://your-cancel-url.com"
override fun onCreate(savedInstanceState: Bundle?) {
// ...
}
@SuppressLint("SetJavaScriptEnabled")
private fun loadCheckout() {
val webView: WebView = findViewById(R.id.webview)
webView.settings.apply {
javaScriptEnabled = true
javaScriptCanOpenWindowsAutomatically = true
domStorageEnabled = true
}
webView.webViewClient = object: WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
val url: Uri? = request?.url
if (url?.host == redirectUrl) {
return true
}
if (url?.host == cancelUrl) {
// handle webview removal
// Run the cancel payment function if you have one
return true
}
return super.shouldOverrideUrlLoading(view, request)
}
}
webView.loadUrl(synchronizerUrl)
}
}
import WebKit
class CheckoutViewController: UIViewController, WKNavigationDelegate {
// ..........
//This is helper to get url params
func getQueryStringParameter(url: String, param: String) -> String? {
guard let url = URLComponents(string: url) else { return nil }
return url.queryItems?.first(where: { $0.name == param })?.value
}
// This is a WKNavigationDelegate func we can use to handle redirection
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping ((WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
/*
We control here when the user wants to cancel a payment.
By default a cancel action redirects to http://cancelurl.com/.
Based on our workflow we can for example remove the webview or push
another view to the user.
*/
if url.absoluteString == "http://cancelurl.com/"{
decisionHandler(.cancel)
}
else{
decisionHandler(.allow)
}
//After a successful transaction we can check if the current url is the callback url
//and do what makes sense for our workflow. We can get the transaction reference for example.
if url.absoluteString.hasPrefix(redirect_url){
let reference = getQueryStringParameter(url: url.absoluteString)
print("reference (reference)")
}
}
}
}
If you have webhooks implemented, a sync.success or sync.processing event will be sent to your webhook URL, and it's recommended you use this to deliver value to the user in your backend.