This page is about one number: how long an applicant waits between your page starting to load and the Checktiv surface being ready to use. It explains what the SDK does on its own, the one API call that helps most, and - just as important - the popular tuning advice that does nothing here, so you do not spend a change on it.
Every figure below was measured on a throttled connection against the real built SDK. Where something was reasoned from a specification rather than measured, the text says so.
How a script-tag page loads the SDK
Section titled “How a script-tag page loads the SDK”- Your
<script src=".../v1/sdk.js">downloads and evaluates. When it finishes,window.Checktivis ready. - You call
Checktiv.init(...)and thenclient.mountProvisioned({ target }). - The SDK asks our API which step this session is on.
- Only then does it know which module to render, and it downloads that module’s code.
sdk.js itself is small - it contains no module code at all. The module code lives in separate files fetched at step 3->4. That is what keeps an applicant on an e-signature step from downloading the identity-capture engine, and vice versa.
The cost of that design is the ordering: step 4 cannot begin until step 3 answers, because step 3 is what says which module to fetch.
The one change worth making: preload
Section titled “The one change worth making: preload”If your application already knows which step the session is on - and it usually does, because your backend minted the session - tell the SDK. It will start downloading that module’s code immediately, in parallel with step 3, instead of waiting for it.
<script src="https://sdk.us.checktiv.com/v1/sdk.js" crossorigin="anonymous"></script><script> const checktiv = Checktiv.init({ publishableKey: 'ah_pk_us_live_...' });
// Start fetching the module you know is coming. Call it as early as you know. checktiv.preload(['idv']);
checktiv.mountProvisioned({ target: '#checktiv', getSessionToken });</script>Measured end to end against the real build, with the module fetch overlapping the session lookup instead of queuing behind it:
| Connection | Without preload |
With preload |
Improvement |
|---|---|---|---|
| 1.6 Mbps, 150 ms round trip | 576.6 ms | 416.5 ms | 160 ms faster |
| 400 Kbps, 400 ms round trip | 1763.9 ms | 1384.8 ms | 379 ms faster |
The slower the connection and the slower our API is for that request, the more it saves.
What to pass
Section titled “What to pass”Pass the modules the flow actually needs. preload is a hint, never a commitment:
- It never throws and returns nothing. There is no state to manage and nothing to await.
- A name your integration has not imported, or a download that fails, is a silent no-op. The real mount still runs its own load and still reports any failure through the normal error path.
- A wrong guess costs the applicant the download and nothing else. Do not pass the full module list “just in case” - that is the download you were trying to avoid.
- Calling it more than once is safe. The browser reuses the file it already has.
fraud is deliberately not preloaded
Section titled “fraud is deliberately not preloaded”Passing 'fraud' does nothing. The fraud module collects behavioral signals, and its consent gate is answered at mount time, so downloading its code beforehand would put a collector on the applicant’s device before they had answered. That is a decision the SDK makes for you and it is not configurable. Every other module preloads normally, and a call naming both preloads the rest.
The React wrapper builds the client for you. Preload from wherever you first know the flow - typically the same place you fetch the session token.
Things that do NOT help here
Section titled “Things that do NOT help here”These come up in every front-end performance review. On this integration they are inert, and two of them can make things worse. They are listed so you can skip them with confidence.
preconnect to the SDK CDN - no benefit
Section titled “preconnect to the SDK CDN - no benefit”A <link rel="preconnect"> opens a connection early so a later request does not pay for one. But the SDK fetches its module files from the same origin your <script src> came from - they are resolved as siblings of the running script. By the time a module is fetched, your browser has already been talking to that origin to download sdk.js. There is no connection left to open.
A preconnect to our API origin is a different question: that is a separate host the SDK contacts at step 3. We have not measured a benefit and cannot honestly quote one, because it depends on your visitors’ DNS and TLS timings rather than on anything in the SDK. If you already preconnect to your own API hosts as a matter of practice, adding ours is harmless; we do not claim a number for it.
<link rel="preload" as="script"> for a module file - actively harmful if you get it wrong
Section titled “<link rel="preload" as="script"> for a module file - actively harmful if you get it wrong”Do not hand-write a preload tag for a module file.
If the tag’s cross-origin settings do not exactly match how the SDK fetches the file, the browser downloads it twice and warns in the console: “A preload for … is found, but is not used because the request credentials mode does not match.” We reproduced this: the file was fetched twice and the bytes doubled. On an identity-capture module that is a large, pointless second download on the exact journey you were trying to speed up.
preload(['idv']) does the same job with none of that risk, and it is the supported way to ask for it.
Guessing the module file URL
Section titled “Guessing the module file URL”Module filenames and paths are build output and can change between SDK versions. Referencing them from your own page couples your HTML to our build. Use preload, which resolves the correct URL for the version you actually loaded.
Things that genuinely matter
Section titled “Things that genuinely matter”Use a classic <script src>
Section titled “Use a classic <script src>”Load sdk.js with a plain <script src="...">. It is a classic script, not an ES module, and window.Checktiv is how you reach it.
Allow our origin in your Content Security Policy
Section titled “Allow our origin in your Content Security Policy”Module files are fetched at runtime by the SDK, so a strict script-src must allow the SDK origin (or use 'strict-dynamic'). Without it, module loads fail under CSP and the applicant sees a load-failure notice. See Security headers for the exact directives, including the style-src entry the SDK’s stylesheet needs.
Put the script where it can start early
Section titled “Put the script where it can start early”sdk.js blocks the parser while it evaluates, exactly like any classic script. Put it in <head> or early in <body> so it is not queued behind your own application bundle. It is small; what matters is that it starts early, because everything else waits on it.
Prefer our CDN over a proxy or a self-hosted copy
Section titled “Prefer our CDN over a proxy or a self-hosted copy”Fetching sdk.js from our CDN is the fastest path and the one with the least to maintain. A copy on your own origin costs you three things: it pins you to a build we no longer serve, it loses the cache your applicants may already share with other sites, and it is only complete if you also mirror every module file that sits beside the bundle, because the SDK resolves those relative to the URL your page loaded sdk.js from.
Self-hosting is supported if that is what your policy requires. Mirroring the directory is the part that is easy to miss, so follow If you proxy or self-host the bundle, which is the authority on how to do it.
If you use npm instead of the script tag
Section titled “If you use npm instead of the script tag”None of the above applies to module downloading: your bundler resolves the module graph at build time, so there are no runtime module files to fetch and preload is a no-op. What matters there is ordinary bundling hygiene - import only the module subpaths your flow uses (@checktiv/sdk-web/idv and friends), and let your bundler code-split the route that hosts the widget. See Modules overview.