> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fintoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate the Widget as a WebView

> Integrate the Fintoc Widget as a WebView in your mobile application.

Embed the Fintoc Widget inside your iOS or Android app with a native WebView, configured through URL query parameters.

## Integration

To integrate the Widget as a WebView on iOS and Android, load the following URL:

```text theme={null}
https://webview.fintoc.com/widget.html
```

Pass the Widget configuration in the query string instead of in client-side JavaScript.

<Info>
  **Using React Native?**

  To integrate the WebView in a React Native app, use the [`@fintoc/fintoc-react-native`](https://github.com/fintoc-com/fintoc-react-native) library.
</Info>

## How it works

Configure the Fintoc WebView with query parameters for the product you want to use:

```text theme={null}
https://webview.fintoc.com/widget.html
  ?public_key=YOUR_PUBLIC_KEY
  &holder_type=individual
  &product=payments
  &country=cl
  &session_token=YOUR_SESSION_TOKEN
```

| Parameter       | Type     | Description                                                                                                                                                                                                                                                                |
| --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `public_key`    | `string` | Identifier for your application within Fintoc. Fintoc assigns each `Link` created with the key to the organization or user that owns the key.<br />The key also determines the environment. Sandbox keys start with `pk_test_`, and production keys start with `pk_live_`. |
| `holder_type`   | `string` | Type of account to connect to Fintoc. One of `business` or `individual`. Not required when `product` is `payments` (Payment Initiation).                                                                                                                                   |
| `product`       | `string` | Product and type of `Link` to create. One of `movements`, `subscriptions`, `invoices`, or `payments`.                                                                                                                                                                      |
| `country`       | `string` | Lowercase ISO 3166-1 alpha-2 code of the country to connect to. One of `cl` or `mx`. Defaults to `cl`. Not required when `product` is `payments` (Payment Initiation).                                                                                                     |
| `webhook_url`   | `string` | URL that receives a request after Fintoc creates a `Link`. The request includes the `Link` object's `link_token`. Only the `movements` and `invoices` products use this parameter.                                                                                         |
| `session_token` | `string` | Token your backend creates with a [Checkout Session](/api/payments-api/checkout-sessions/checkout-sessions-create). The Widget uses `session_token` to load and configure the payment flow. Only the `payments` product uses this parameter.                               |
| `widget_token`  | `string` | Token your backend creates to initialize and configure the Widget for the `subscriptions` product.                                                                                                                                                                         |
| `link_token`    | `string` | Identifier of an existing `Link`. Include it to configure the Widget for a `Link` already created with the `movements` product.                                                                                                                                            |

You can construct the query string separately before appending it to the WebView URL:

```text theme={null}
public_key=YOUR_PUBLIC_KEY&holder_type=individual&product=movements&country=cl&link_token=YOUR_LINK_TOKEN
```

## Usage example

The following snippets show the WebView set up on Android and iOS:

```kotlin theme={null}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  supportActionBar?.hide()

  val widgetInitializationUrl = generateWidgetInitializationUrl()

  // Modify WebView settings. Some settings may not be applicable
  // or necessary for your integration.
  val fintocWebview = findViewById<WebView>(R.id.webview)
  val webSettings = fintocWebview.settings
  webSettings.javaScriptEnabled = true
  webSettings.javaScriptCanOpenWindowsAutomatically = true
  webSettings.domStorageEnabled = true
  webSettings.cacheMode = WebSettings.LOAD_NO_CACHE
  webSettings.useWideViewPort = true

  fintocWebview.loadUrl(widgetInitializationUrl.toString())
}

private fun generateWidgetInitializationUrl(): Uri {
  val builder = Uri.parse("https://webview.fintoc.com/widget.html")
    .buildUpon()
    .appendQueryParameter("holder_type", "individual")
    .appendQueryParameter("product", "payments")
    .appendQueryParameter("public_key", "YOUR_PUBLIC_KEY")
    .appendQueryParameter("session_token", "YOUR_SESSION_TOKEN")
  return builder.build()
}
```

```swift theme={null}
import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate, UIScrollViewDelegate, WKUIDelegate {

    private var webView: WKWebView!

    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        webView.navigationDelegate = self
        webView.allowsBackForwardNavigationGestures = false
        webView.scrollView.bounces = false
        webView.isMultipleTouchEnabled = false
        webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true

        // Disable zoom.
        webView.scrollView.delegate = self
        webView.scrollView.minimumZoomScale = 1.0
        webView.scrollView.maximumZoomScale = 1.0

        let url = generateInitializationURL()
        webView.load(URLRequest(url: url))
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

    @objc(scrollViewWillBeginZooming:withView:) func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        scrollView.pinchGestureRecognizer?.isEnabled = false
    }

    func webView(
        _ webView: WKWebView,
        createWebViewWith configuration: WKWebViewConfiguration,
        for navigationAction: WKNavigationAction,
        windowFeatures: WKWindowFeatures
    ) -> WKWebView? {
        guard navigationAction.targetFrame == nil,
              let url = navigationAction.request.url else { return nil }

        UIApplication.shared.open(url)
        return nil
    }

    func generateInitializationURL() -> URL {
        let params = [
            "holder_type": "individual",
            "product": "payments",
            "public_key": "YOUR_PUBLIC_KEY",
            "session_token": "YOUR_SESSION_TOKEN",
        ]
        var components = URLComponents()
        components.scheme = "https"
        components.host = "webview.fintoc.com"
        components.path = "/widget.html"
        let queryItems = params.map { URLQueryItem(name: $0, value: $1) }
        components.queryItems = queryItems
        return components.url!
    }

    func webView(
      _ webView: WKWebView,
      decidePolicyFor navigationAction: WKNavigationAction,
      decisionHandler: @escaping ((WKNavigationActionPolicy) -> Void)
    ) {
      guard let url = navigationAction.request.url else {
        decisionHandler(.allow)
        return
      }
      let linkScheme = "fintocwidget"
      let actionScheme = url.scheme
      let actionType = url.host ?? ""
      if actionScheme == linkScheme {
        switch actionType {
        case "succeeded":
          print("Succeeded")
        case "exit":
          print("Exited")
        case "event":
          print("Widget event detected: \(url)")
        default:
          print("Another widget action detected: \(actionType)")
        }
        decisionHandler(.cancel)
        return
      } else {
        decisionHandler(.allow)
      }
    }
}
```

The Swift example includes a `webView` method that handles link clicks inside the WebView. In the example, links open in Safari, but you can customize this behavior. For example, links can open inside the same app. This matters because customers using [Payment Initiation](/guides/payments/overview-payment-initiation) can click a link to download the transaction voucher after they finish the payment flow. Allow these links to open so the customer can download the voucher.

## WebView redirections

After you integrate the WebView, you can interact with its events using redirects:

| Method      | Redirect URL                                           | Description                                                                                                                                          |
| :---------- | :----------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onSuccess` | `fintocwidget://succeeded`                             | Fires after the flow finishes successfully.                                                                                                          |
| `onExit`    | `fintocwidget://exit`                                  | Fires after your customer closes the Widget before finishing.                                                                                        |
| `onEvent`   | `fintocwidget://event/{event_name}?queryparam={value}` | Fires for every event available on the Widget. For more information about these events, see [Widget events](/guides/resources/widget/widget-events). |

<Warning>
  **Handle `onEvent` in a WebView**

  The WebView enables `onEvent` by default. Handle the `fintocwidget://event/{event_name}` redirect so your app receives Widget events.
</Warning>

To use these methods on Android and iOS, use the following snippets:

```kotlin theme={null}
webview.webViewClient = object : WebViewClient() {
  override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
    val parsedUri = url?.let(Uri::parse) ?: return false
    if (parsedUri.scheme == "fintocwidget") {
      val action = parsedUri.host
      if (action == "succeeded") {
        // onSuccess
      }
      if (action == "exit") {
        // onExit
      }
      if (action == "event") {
        // onEvent
      }
      return true
    }
    return false
  }
}
```

```java theme={null}
webview.setWebViewClient(new WebViewClient() {
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
    Uri parsedUri = Uri.parse(url);
    if ("fintocwidget".equals(parsedUri.getScheme())) {
      String action = parsedUri.getHost();
      if ("succeeded".equals(action)) {
        // onSuccess
      }
      if ("exit".equals(action)) {
        // onExit
      }
      if ("event".equals(action)) {
        // onEvent
      }
      return true;
    }
    return false;
  }
});
```

```swift theme={null}
func webView(
  _ webView: WKWebView,
  decidePolicyFor navigationAction: WKNavigationAction,
  decisionHandler: @escaping ((WKNavigationActionPolicy) -> Void)
) {
  guard let url = navigationAction.request.url else {
    decisionHandler(.allow)
    return
  }
  let linkScheme = "fintocwidget"
  let actionScheme = url.scheme
  let actionType = url.host ?? ""
  if actionScheme == linkScheme {
    switch actionType {
    case "succeeded":
      // onSuccess
      break
    case "exit":
      // onExit
      break
    case "event":
      // onEvent
      break
    default:
      print("Widget action detected: \(actionType)")
    }
    decisionHandler(.cancel)
    return
  } else {
    decisionHandler(.allow)
  }
}
```

<Warning>
  **Add the `fintocwidget` URL scheme on iOS**

  Before integrating the Fintoc Widget with your iOS app, register `fintocwidget` as a URL scheme in the app's `Info.plist` file. This configuration allows your app to handle Widget redirects.
</Warning>

```xml theme={null}
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>fintocwidget</string>
    </array>
    <key>CFBundleURLName</key>
    <string>your.bundle.id</string>
  </dict>
</array>
```

## Test the integration

Load the WebView with a `pk_test_` public key to run against the sandbox environment. Complete the flow with Fintoc's [test credentials](/guides/resources/test-mode), then confirm your app receives the `fintocwidget://succeeded` redirect.
