> For a complete page index, fetch https://docs.transak.com/llms.txt

# iOS

The Transak iOS integration allows you to embed a fully functional interface directly into your native iOS application using Webview.

Google Pay is not supported with iOS webview integration.

#### Do not override the WebView user agent

Transak uses the default `User-Agent` to detect that the widget is running inside a native WebView, which determines the payment methods we offer. Replacing it strips those identifiers, so users may be shown methods that cannot complete in a WebView and our support team loses the signal needed to diagnose failures.

Keep the default `User-Agent` unchanged. If you need to identify your app, use your platform's append-only option

#### Add Camera Permission

Update your `Info.plist` to include camera permission (required for KYC verification):

```xml
<key>NSCameraUsageDescription</key>
<string>Permission required for Camera Access.</string>
```

#### Implement WebView in View Controller

Configure your View Controller to load the Transak widget URL using your preferred implementation:

**`SwiftUI`**

```swift title="SwiftUI"
import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    let url: URL

    func makeUIView(context: Context) -> WKWebView {
        let webview = WKWebView()
        return webview
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        let request = URLRequest(url: url)
        uiView.load(request)
    }
}

struct ContentView: View {
    var body: some View {
        WebView(url: URL(string: "https://global-stg.transak.com?apiKey=<YOUR_API_KEY>&sessionId=<YOUR_SESSION_ID>")!)
        .edgesIgnoringSafeArea(.all)
        .padding(10)
    }
}
```

**`UIKit`**

```swift title="UIKit"
import UIKit
import WebKit

class WebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
    @IBOutlet weak var webView: WKWebView!

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

    override func viewDidLoad() {
        super.viewDidLoad()
        let myURL = URL(string: "https://global-stg.transak.com?apiKey=<YOUR_API_KEY>&sessionId=<YOUR_SESSION_ID>")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }

    func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        if let serverTrust = challenge.protectionSpace.serverTrust {
            completionHandler(.useCredential, URLCredential(trust: serverTrust))
        }
    }
}
```

#### Create Widget URL (using Backend Only)

Call the [Create Widget URL](/api/public/create-widget-url) API from your backend to generate a secure widget url using

Query parameters

The response returns a `widgetUrl` that should be used to load Transak in iOS Webview.

A `widgetUrl` is valid for 5 minutes and can only be used once. A new `widgetUrl` must be generated for every user flow.

**Example Request:**

```bash
curl --request POST \
  --url https://api-gateway-stg.transak.com/api/v2/auth/session \
  --header 'access-token: YOUR_ACCESS_TOKEN' \
  --header 'content-type: application/json' \
  --data '{
  "widgetParams": {
    "apiKey": "YOUR_API_KEY",
    "referrerDomain": "yourdomain.com"
  }
}'
```

## Use cases

Use the table below to choose the right approach for redirects, order data, and WebView events.

<table>
  <thead>
    <tr>
      <th>
        Feature
      </th>

      <th>
        Approach
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        How to redirect users back to your app after a transaction
      </td>

      <td>
        [Deeplink](#deeplinking)
      </td>
    </tr>

    <tr>
      <td>
        How to get order data (e.g. status, order ID, amount)
      </td>

      <td>
        [Deeplink](#deeplinking), [Events](#events)
      </td>
    </tr>

    <tr>
      <td>
        Listen to WebView events (order created, widget close, etc.)
      </td>

      <td>
        [Events](#events)
      </td>
    </tr>
  </tbody>
</table>

### Deeplink

Transak supports deeplinking through the use of the `redirectURL` query parameter to enable seamless navigation after the purchase/sell process is completed.

#### Register Deeplink in Info.plist

Add the URL scheme to your `Info.plist` to handle the deeplink

```xml
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>myapp</string>
        </array>
    </dict>
</array>
```

#### Handle Deeplink and Parse Parameters

Listen for the deeplink and parse the returned parameters in your App

When Transak redirects back, it includes additional query parameters appended to deeplink URL mentioned [here](/customization/query-parameters#redirecturl-1).

```swift
@main
struct SampleApp: App {
     @State private var deepLinkPath: URL?

     var body: some Scene {
         WindowGroup {
             ContentView()
             NavigationView {
                 if let deepLinkPath = deepLinkPath {
                   // handle deeplink query parameters
                 } else {
                   ContentView()
                 }
             }
             .onOpenURL { url in
                 if url.scheme == "myapp" {
                     deepLinkPath = url
                 }
             }
         }
     }
}
```

#### Pass redirectURL in Create Widget URL API

Call the [Create Widget URL](/api/public/create-widget-url) API from your backend to generate a secure widget url using

Query parameters

along with `redirectURL` parameter.

The response returns a `widgetUrl` that should be used to load Transak in iOS Webview.

A `widgetUrl` is valid for 5 minutes and can only be used once. A new `widgetUrl` must be generated for every user flow.

**Example Request:**

```bash
curl --request POST \
  --url https://api-gateway-stg.transak.com/api/v2/auth/session \
  --header 'access-token: YOUR_ACCESS_TOKEN' \
  --header 'content-type: application/json' \
  --data '{
  "widgetParams": {
    "apiKey": "YOUR_API_KEY",
    "referrerDomain": "yourdomain.com",
    "redirectURL": "myapp://transak-redirect"
  }
}'
```

### Events

Transak allows listening of in-widget events (like order creation, completion, and widget close) through native event handlers in iOS WebViews.

Add a script message handler to your WebView using the handler name

IosWebview

to listen for all frontend events.

```swift
struct WebView: UIViewRepresentable {
    let url: URL

    func makeCoordinator() -> WebViewCoordinator {
        return WebViewCoordinator(self)
    }

    func makeUIView(context: Context) -> WKWebView {
        let contentController = WKUserContentController()
        contentController.add(context.coordinator, name: "IosWebview")

        let config = WKWebViewConfiguration()
        config.userContentController = contentController

        let webView = WKWebView(frame: .zero, configuration: config)
        webView.navigationDelegate = context.coordinator
        webView.load(URLRequest(url: url))

        return webView
    }

    func updateUIView(_ webView: WKWebView, context: Context) {}

    class WebViewCoordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
        var parent: WebView

        init(_ parent: WebView) {
            self.parent = parent
        }

        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if message.name == "IosWebview", let body = message.body as? String {
                print(body)
            }
        }
    }
}
```

#### Supported Events

<table>
  <thead>
    <tr>
      <th>
        Event Name
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `TRANSAK_WIDGET_INITIALISED`
      </td>

      <td>
        Widget initialised with query params
      </td>
    </tr>

    <tr>
      <td>
        `TRANSAK_WIDGET_OPEN`
      </td>

      <td>
        Widget fully loaded
      </td>
    </tr>

    <tr>
      <td>
        `TRANSAK_ORDER_CREATED`
      </td>

      <td>
        Order created by user
      </td>
    </tr>

    <tr>
      <td>
        `TRANSAK_ORDER_SUCCESSFUL`
      </td>

      <td>
        Order is successful
      </td>
    </tr>

    <tr>
      <td>
        `TRANSAK_ORDER_CANCELLED`
      </td>

      <td>
        Order is cancelled
      </td>
    </tr>

    <tr>
      <td>
        `TRANSAK_ORDER_FAILED`
      </td>

      <td>
        Order is failed
      </td>
    </tr>

    <tr>
      <td>
        `TRANSAK_WIDGET_CLOSE`
      </td>

      <td>
        Widget is about to close
      </td>
    </tr>
  </tbody>
</table>