> For the complete documentation index, see [llms.txt](https://verisync.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://verisync.gitbook.io/docs/integration-options/mobile/webview.md).

# Webview

When it comes to identity verification with Verisync in your mobile applications, there are two ways to go about it:

1. **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
2. **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.

{% hint style="info" %}
**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
{% endhint %}

### Why use a WebView? <a href="#why-use-a-webview" id="why-use-a-webview"></a>

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:

1. 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 <a href="#generating-the-checkout-url" id="generating-the-checkout-url"></a>

```
GET https://app.verisync.co/synchronizer/authorize?flow_id=:flow_id&client_id=:client_id&redirect_url=:redirect_url&metadata=:metadata
```

<table><thead><tr><th>Parameter name</th><th width="293">Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td><code>flow_id</code></td><td><code>string</code></td><td><code>true</code></td><td>The id of the flow created of the request user info</td></tr><tr><td><code>client_id</code></td><td><code>string</code></td><td><code>true</code></td><td>The client ID you received from Verisync it's on your dashboard integration page</td></tr><tr><td><code>redirect_url</code></td><td><code>string</code></td><td><code>true</code></td><td>The URL  where your users will be sent after authorization.</td></tr><tr><td><code>email</code></td><td><code>string</code></td><td><code>false</code></td><td>The user email address</td></tr><tr><td><code>metadata</code></td><td><code>object</code></td><td><code>false</code></td><td>Stringified JSON object of custom data.</td></tr></tbody></table>

### Displaying Synchronizer in Your WebView <a href="#displaying-checkout-in-your-webview" id="displaying-checkout-in-your-webview"></a>

If the url config is correct, then load the Webview widget. See the sample code below:

{% tabs %}
{% tab title="React Native" %}

```javascript
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 }
    />
  );
}

```

{% endtab %}

{% tab title="Flutter" %}

```dart
@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;
      },
    ),
  );
}

```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
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)
  }
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
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)")
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

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.
