WebView host page
This is the preferred way to bring myFlowpay into a native mobile app. The app shows a small static page from your own domain in a WebView. That page embeds myFlowpay with the Embedded (iFrame) SDK. The app gets the launch payload from your backend, then a signature for each login. It authenticates both calls with the app token it already has. The app gives both to the page over the WebView JavaScript bridge.
Native app ──(app token)──► Your backend: sign Flowpay payload ──► payload + signature
│
└─► WebView loads a static page on *.yourdomain.com (no login, no redirects)
page: create iframe → fp:READY → asks native for signature → fp:LOGIN
For a comparison with the launch URL, see Mobile apps.
Integration flow
sequenceDiagram
autonumber
participant App as Native app
participant Backend as Your backend
participant Page as Host page (WebView)
participant FP as myFlowpay (iframe)
App->>Page: Loads the static page
Page->>App: Requests the launch payload (bridge)
App->>Backend: Requests the launch payload (app token)
Backend-->>App: Launch payload for this user
App-->>Page: Launch payload
Page->>FP: Creates the iframe
FP-->>Page: fp:READY
Page->>App: Requests a signature for the canonical payload (bridge)
App->>Backend: Requests a signature (app token)
Backend-->>App: Signature
App-->>Page: Signature
Page->>FP: fp:LOGIN
FP-->>Page: fp:LOGIN_SUCCESS
Note over Page,FP: Session refresh repeats the signature steps
Requirements
| Item | Requirement |
|---|---|
| Embed hostname | The same subdomain setup as the web embed, for example flowpay.yourdomain.com. See Subdomain Setup. |
| Page origin | A static page on a subdomain of the same root domain, for example flowpay-app.yourdomain.com. The page and the embed hostname must be same-site. If they are not, the session cookie does not work. Give Flowpay the page origin. Flowpay then lets that origin frame the embed hostname. |
| Page access | The page needs no login and holds no data. Without a launch payload and a signature from the app, it does nothing. |
| Shared secret | Only on your backend. Never put it in the app or in the page. |
| Signing endpoint | Accepts the app token. Signs a canonical payload only if its userId and its merchantId or customerId belong to the user of that token. |
createdAt |
The SDK sets it before each signature. The signature is valid for 5 minutes, so sign each request again. Do not cache signatures. |
1. Host page
Build the page as in Basic Usage with Core SDK. Three things are different.
The launch payload and the signature come from the app. callNative stands for your function that sends a bridge message and returns a Promise of the reply. See Bridge contract. Create the controller with the integrationType that the app returns, so that a customer payload is signed as a customer payload.
const launch = await callNative("launchPayload"); // { integrationType, payload }
const controller = createFlowpayDomController({
embedOrigin: "https://flowpay.yourdomain.com",
integrationType: launch.integrationType,
signatureProvider: {
signPayload: (payload, ctx) =>
createSignedLogin(
payload,
(canonicalPayload) => callNative("sign", { canonicalPayload }),
ctx.integrationType
),
},
});
controller.setLaunchPayload(launch.payload);
External URLs go to the app. The app opens them in an in-app browser.
The app hears about state and can sign the user out.
controller.on("loginSuccess", () => callNative("loaded"));
controller.on("error", (error) => callNative("error", { message: error.message }));
window.flowpayLogout = () => controller.logout();
Keep allow="camera; microphone; geolocation" on the iframe. Identity verification needs the camera.
Add <meta name="viewport" content="width=device-width, initial-scale=1"> to the page. Without it, the WebView lays out the page at desktop width and myFlowpay shows too small.
2. Native app
The app loads the page in a WebView and answers the page's bridge messages.
Bridge contract
| Message | Page sends | App does | App returns |
|---|---|---|---|
launchPayload |
Nothing | Gets the launch payload for the app user from your backend | { integrationType, payload } |
sign |
canonicalPayload |
Gets a signature for canonicalPayload from your backend |
The signature string |
openExternal |
url |
Opens the URL in an in-app browser (Chrome Custom Tabs, SFSafariViewController) |
Nothing |
loaded |
Nothing | Hides the native loading screen | Nothing |
error |
message |
Shows an error or offers a retry | Nothing |
On Android, each page message also carries an id. The reply is a JSON string with the same id and either result or error. On iOS, the reply resolves or rejects the Promise that postMessage returns.
To sign the user out, the app calls window.flowpayLogout() with evaluateJavaScript.
Security rules
- Accept bridge messages only from the main frame of your page origin. The myFlowpay iframe and the frames inside it must not reach the bridge.
- Keep the app token in the app. The app calls your backend. The page never gets the token.
- Your backend signs a canonical payload only if its
userIdand itsmerchantIdorcustomerIdbelong to the user of the app token.
Platform APIs
| Bridge | WKScriptMessageHandlerWithReply (iOS 14+), registered as flowpay. Check frameInfo.isMainFrame and frameInfo.securityOrigin. Call replyHandler on the main thread. |
| New windows | Return nil from WKUIDelegate createWebViewWith. |
| Navigation guard | WKNavigationDelegate decidePolicyFor. |
| Camera | Add NSCameraUsageDescription and NSMicrophoneUsageDescription to Info.plist. Set allowsInlineMediaPlayback = true. Optional: grant in WKUIDelegate requestMediaCapturePermissionFor to skip the repeated WebKit prompt. Grant only while the main frame shows your page origin. Deny in all other cases. |
| File upload | Works without code. |
| Settings | None. JavaScript and storage are on by default. Keep the default WKWebsiteDataStore: a non-persistent store loses the myFlowpay session when the WebView closes. |
| Bridge | WebViewCompat.addWebMessageListener (androidx.webkit), registered as flowpayNative with your page origin in allowedOriginRules. Check isMainFrame and sourceOrigin. Reply with replyProxy.postMessage. Do not use addJavascriptInterface. Every frame can call it and it does not report the caller origin. |
| New windows | Keep javaScriptCanOpenWindowsAutomatically = false. Do not enable setSupportMultipleWindows. |
| Navigation guard | WebViewClient.shouldOverrideUrlLoading. |
| Camera | Add CAMERA and RECORD_AUDIO to the manifest and request them at runtime. In WebChromeClient.onPermissionRequest, grant RESOURCE_VIDEO_CAPTURE and RESOURCE_AUDIO_CAPTURE only while the main frame shows your page origin. Deny in all other cases. |
| File upload | WebChromeClient.onShowFileChooser. |
| Settings | javaScriptEnabled = true, domStorageEnabled = true. |
Navigation
The SDK also calls window.open for each fp:OPEN_EXTERNAL. Do not let the WebView open new windows: the openExternal bridge message already opens the URL in an in-app browser.
Keep the WebView on your page. If the main frame goes to a URL outside your page origin, cancel the navigation. Open the URL in an in-app browser. Do not apply this rule to subframes: the myFlowpay iframe and the identity verification frame inside it must load.
The camera permission check relies on this rule. While your page is in the main frame, only the frames that your iframe allow attribute delegates to can request the camera.
3. Load time
The page has no login, so the time to show myFlowpay is two backend calls (the launch payload, then the signature) plus the iframe load. The app can request the launch payload while the page loads. To make it shorter:
- Create the WebView and load the page before the user opens myFlowpay, for example when the app shows the screen that leads to it.
- Start the launch payload request in the app when it creates the WebView. Answer
launchPayloadfrom that request. - Serve the page with long cache headers. The WebView then loads it from its cache.
- Show a native loading screen until the page sends
loaded.
Session, logout and resume
- Refresh. About 60 seconds before the session expires, myFlowpay sends
fp:SESSION_EXPIRING. The SDK callssignPayloadagain and the app gets a new signature from your backend. The user sees nothing. - Logout. Call
window.flowpayLogout()withevaluateJavaScriptwhen the user signs out of the app. - Resume. Flowpay keeps the journey state. The next login with the same identifiers returns the user to where they stopped.
- Status. Use webhooks to show financing status in native screens.
Branding
Branding is the same as for the web embed. See Customization and Styling.