Skip to content

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.

controller.on("openExternal", ({ url }) => callNative("openExternal", { url }));

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 userId and its merchantId or customerId belong 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.

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:

  1. Create the WebView and load the page before the user opens myFlowpay, for example when the app shows the screen that leads to it.
  2. Start the launch payload request in the app when it creates the WebView. Answer launchPayload from that request.
  3. Serve the page with long cache headers. The WebView then loads it from its cache.
  4. 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 calls signPayload again and the app gets a new signature from your backend. The user sees nothing.
  • Logout. Call window.flowpayLogout() with evaluateJavaScript when 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.