WebView Integration (Native Apps)
The Embedded SDK mounts a full web form inside an iframe. Most of what that form does is plain DOM/network activity and works identically whether the host page is a desktop browser tab or a native app's WebView. A couple of features are the exception: they're built on browser-native APIs that a native WebView either doesn't implement or silently no-ops. This page covers which features those are, why they break, and how to take them over.
Why this only affects native WebViews
window.print() and anchor-click downloads are ordinary browser APIs — they
work without any special handling when the SDK is embedded in a normal
<iframe> on a normal web page. Native mobile WebViews (iOS WKWebView,
Android WebView) render web content but don't fully implement every
browser-chrome behavior around it:
| Feature | Browser API behind it | What happens in a native WebView |
|---|---|---|
| Print (report view, terms PDF) | window.print() | No print dialog exists to open — the call does nothing, silently |
| Download PDF (report "Save to PDF", terms PDF) | Invisible <a> anchor click | No download manager/save-to-Files sheet — the click does nothing, silently |
Both failures are silent — no error is thrown, nothing reaches onError,
and the user just sees an unresponsive button. If you're embedding the SDK in
a native app and haven't done anything described on this page, this is
almost certainly what your users are hitting.
The fix: takeover handlers
Two mount() options exist specifically for this: handlePrintRequested and
handleDownloadRequested. Provide either one, and the form suppresses that
browser-native default and calls your handler instead — your native code
performs the action however you see fit.
These are documented in full under Takeover Handlers (Native WebViews) in SDK Methods, and their types are in the Type Reference. The short version:
sdk.mount("#form", {
handlePrintRequested: () => {
// Your code — handle the print request however fits your app
},
handleDownloadRequested: ({ url, filename }) => {
// Your code — retrieve `url` and get it to the user as `filename`
},
});
They're named handle* rather than on* deliberately, to signal that
providing one changes behavior rather than just notifying you of
something that already happened — every other mount option starting with
on* is a passive callback. Omit either handler and that action keeps its
default (browser-only) behavior unchanged; this is why shipping the handlers
is additive and doesn't affect existing web integrations.
What each handler gives you
Both handlers are intentionally unopinionated about what you do on the native side — the SDK's job ends at handing you the request; everything past that is entirely your implementation to design.
Print
handlePrintRequested() takes no arguments and returns nothing. It fires
whenever the user asks to print (including a Ctrl/Cmd+P
on the host page), and once you've provided it, the form never calls
window.print() itself. A typical approach is to forward the request to
your native layer and let it drive whatever print experience your platform
offers — the SDK has no expectations beyond that.
Detecting a stale form build
Delegation only takes effect once the embedded form acknowledges it when the
view becomes ready. If your host is bundled against an older form build that
predates delegation support, handlePrintRequested/handleDownloadRequested
are silently never invoked and the form falls back to its browser-native
(non-functional-in-WebView) default — except for a non-fatal onWarning with
code DELEGATION_UNSUPPORTED, whose invalidFields lists which of
'print'/'download' weren't honored. If your takeover handlers appear to do
nothing, check for this warning before assuming a bug in your own handler.
Download
handleDownloadRequested({ url, filename }) fires when the user asks to
download a file, and once you've provided it, the form never triggers its
own browser download. You get a URL and a suggested filename; getting that
file into the user's hands — a share sheet, a save-to-storage flow, or
anything else — is up to you.
Two properties of url are worth knowing regardless of how you implement it:
- It's self-authenticating. It's a presigned URL with authentication
embedded in its own query string, so a plain unauthenticated
GETfrom any HTTP client retrieves the file — you don't need to forward cookies, headers, or any other credential from the WebView's context. - It's short-lived. It expires within minutes, so fetch it promptly rather than queuing the request for later.
The file behind url is a screening report sourced from Experian. Experian's
terms prohibit retaining these reports outside of delivering them to the
requesting consumer or end user — whatever your implementation looks like,
it should get the file to that person and not archive, cache, log, or
otherwise keep a copy under your own control once that's done.
Putting it together
A native integration generally means: detect that your web content is
running inside your app's WebView, give your JavaScript a way to call into
native code (however you choose to structure that), and forward
handlePrintRequested/handleDownloadRequested calls to your native
print/download implementation. Skip registering both handlers when the same
bundle runs in a normal browser tab — you want the default browser behavior
there, not a call into a bridge that doesn't exist.
Checklist for native app developers
- Detect that your web bundle is running inside your app's WebView
- Provide
handlePrintRequestedand implement printing however fits your platform - Provide
handleDownloadRequested, fetch the presigned URL promptly with no extra auth, and get the file to the user without retaining a copy — see the note under Download - Skip both handlers for the same bundle running in a normal browser tab, so default behavior there is unaffected
- Test the print and "Save to PDF" buttons in the report view, and the terms-of-service PDF download in the screening flow
- Watch for an
onWarningwith codeDELEGATION_UNSUPPORTED— see Detecting a stale form build
Next Steps
- Takeover Handlers (Native WebViews) — full mount-option reference
- Type Reference —
DownloadRequestandMountOptionsdeclarations - Best Practices — other production integration guidance