Mobile Integration
Integrate the Fiskil consent flow into iOS and Android apps using the Link SDK in a WebView
The Fiskil Link SDK currently provides a JavaScript client SDK (@fiskil/link) for web applications. Native Android and iOS SDKs will be available in the coming months.
In the meantime, you can integrate the full consent flow into your mobile app by embedding the Link SDK inside a WebView. This is the recommended approach -- it uses the same SDK as a web integration, runs the consent flow in an overlay managed by the SDK, and communicates results back to your native code through a JavaScript bridge.
This guide assumes you've already set up your backend to create Auth Sessions and are familiar with the Link SDK. If you're new to the Fiskil platform, start with the Quick Start Guide.
How It Works
- Your backend creates an Auth Session via
POST /v1/auth/sessionand returns theauth_session_idto the mobile app - The mobile app loads a local HTML page in a WebView that includes the
@fiskil/linkSDK from CDN - The native app passes the
auth_session_idinto the WebView via a JavaScript bridge - The Link SDK opens the consent flow overlay inside the WebView
- When the flow completes (or fails), the SDK resolves and the HTML page sends the result back to native code through the JavaScript bridge
Create the Auth Session
On your backend, create an Auth Session. When using the Link SDK, you only need to provide the end_user_id -- no redirect_uri or cancel_uri is required.
curl --request POST \
--url https://api.fiskil.com/v1/auth/session \
--header 'Authorization: Bearer ${access_token}' \
--header 'Content-Type: application/json' \
--data '{"end_user_id": "${end_user_id}"}'The response includes the session_id to pass to the Link SDK:
{
"id": "5qcql2s0bn9qfh1m5qd1sl4gth",
"session_id": "ea564d-56012s4-6ds4564",
"auth_url": "https://auth.fiskil.com/consent?session=ea564d-56012s4-6ds4564",
"expires_at": 1621083785
}The Bridge HTML Page
Create a lightweight HTML page that loads the Link SDK from CDN and communicates with your native app through a JavaScript bridge. Bundle this file with your app so the WebView loads it locally.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/@fiskil/link@0.1.6-beta/dist/fiskil-link.umd.js"></script>
</head>
<body>
<script>
function startLink(authSessionId) {
var flow = FiskilLink.link(authSessionId);
flow
.then(function(result) {
sendToNative('success', { consentID: result.consentID });
})
.catch(function(err) {
sendToNative('error', { code: err.code, message: err.message });
});
}
function sendToNative(type, payload) {
var message = JSON.stringify({ type: type, payload: payload });
// iOS (WKWebView)
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.fiskil) {
window.webkit.messageHandlers.fiskil.postMessage(message);
return;
}
// Android (WebView)
if (window.FiskilBridge) {
window.FiskilBridge.onResult(message);
return;
}
}
</script>
</body>
</html>The sendToNative function detects which platform it's running on and routes the message to the appropriate native handler. The native side calls startLink() to kick off the flow once the page is loaded.
iOS Integration (WKWebView)
Load the bridge HTML page in a WKWebView. There are two key integration points: registering a script message handler so the JavaScript sendToNative function can reach your Swift code, and calling startLink() once the page finishes loading.
Register the JS bridge by adding a WKScriptMessageHandler with the name fiskil -- this matches the window.webkit.messageHandlers.fiskil call in the bridge HTML:
let configuration = WKWebViewConfiguration()
configuration.userContentController.add(self, name: "fiskil")
let webView = WKWebView(frame: view.bounds, configuration: configuration)Start the flow once the page has loaded by calling startLink() with the auth session ID via evaluateJavaScript:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("startLink('\(authSessionId)')")
}Handle the result in your WKScriptMessageHandler implementation. The message body is the JSON string sent by sendToNative:
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
// message.body is the JSON string: {"type": "success"|"error", "payload": {...}}
// Parse and handle accordingly
}Bundle the fiskil-link.html file in your app and load it with loadFileURL(_:allowingReadAccessTo:). Make sure JavaScript and DOM storage are enabled on the WebView configuration.
Android Integration (WebView)
Load the bridge HTML page in an Android WebView. The two key integration points are: adding a JavaScript interface so window.FiskilBridge.onResult() can reach your Kotlin code, and calling startLink() once the page finishes loading.
Register the JS bridge by adding a JavaScript interface named FiskilBridge -- this matches the window.FiskilBridge call in the bridge HTML:
val webView = WebView(this).apply {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
}
webView.addJavascriptInterface(object {
@JavascriptInterface
fun onResult(message: String) {
// message is the JSON string: {"type": "success"|"error", "payload": {...}}
// Parse and handle accordingly
}
}, "FiskilBridge")Start the flow once the page has loaded by calling startLink() with the auth session ID:
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
view?.evaluateJavascript("startLink('$authSessionId')", null)
}
}
webView.loadUrl("file:///android_asset/fiskil-link.html")Place the fiskil-link.html file in your assets/ directory. Note that @JavascriptInterface methods are called on a background thread -- switch to the main thread before updating UI.
Institution Selection Strategies
You have two options for how users select their institution (bank or energy provider) during the consent flow.
Option A: Use Fiskil's Built-In Institution List
The simplest approach. When you create an Auth Session without an institution_id, the consent flow rendered by the Link SDK begins with Fiskil's hosted institution picker. The user selects their institution, then proceeds to authenticate.
No additional work is required -- just pass the auth_session_id to the Link SDK as shown above.
{
"end_user_id": "eu_12345"
}Option B: Build Your Own Institution List
For a fully native experience, you can build your own institution picker in your app and pass the selected institution_id when creating the Auth Session. This skips Fiskil's institution selection screen entirely, taking the user straight to authentication.
Step 1: Fetch institutions from the API
Call GET /v1/institutions with your client_id to retrieve the list of available institutions. You can filter by industry to show only banking or energy providers.
curl --request GET \
--url 'https://api.fiskil.com/v1/institutions?industry=banking&client_id={client_id}' \
--header 'accept: application/json; charset=UTF-8'Each institution in the response includes fields you can use to build your UI:
| Field | Description |
|---|---|
id | The institution ID to pass when creating an Auth Session |
name | Display name of the institution |
icon | URL to a square icon (suitable for list items) |
logo | URL to the full logo |
industry | banking or energy |
status.connections.status | OPERATIONAL, DEGRADED, or DOWN |
Step 2: Render a native institution picker
Use the institution data to build a native list or grid in your app. You can add search, filtering, and custom branding that matches your app's design.
Step 3: Pass the selected institution ID
When the user selects an institution, create the Auth Session with the institution_id parameter. The consent flow will skip the institution picker and go directly to the selected institution's login screen.
curl --request POST \
--url https://api.fiskil.com/v1/auth/session \
--header 'Authorization: Bearer ${access_token}' \
--header 'Content-Type: application/json' \
--data '{
"end_user_id": "eu_12345",
"institution_id": "22"
}'Then pass the returned session_id to the Link SDK as normal. The user will skip institution selection and go straight to authentication.
Check the status.connections.status field before presenting an institution to users. If the status is DOWN, consider hiding the institution or showing a notice that it is temporarily unavailable.
Best Practices
- Enable JavaScript and DOM storage in your WebView configuration -- the Link SDK requires both
- Bundle the HTML page locally rather than hosting it remotely, so the WebView loads instantly without a network request
- Handle external links by opening them in the system browser rather than inside the WebView (e.g., privacy policy or help links)
- Support back navigation so users can go back within the consent flow without dismissing the entire WebView
- Clear WebView data between sessions if multiple users share the same device
- Test with sandbox credentials on both iOS and Android before going live -- see the Testing guide for details
- Handle session expiry gracefully -- Auth Sessions expire after 5 days, so create a new session if the user returns after a delay
Next Steps
- Review the Link SDK reference for the full list of options and error codes
- Set up Webhooks to receive consent and data sync notifications
- See Error Types for handling error codes returned by the SDK
- Read the Best Practices guide for general integration recommendations
Was this page helpful?