The Checktiv Web SDK (@checktiv/sdk-web) publishes one package with several entry points. The two-line client surface (Checktiv.init(...) then mountProvisioned(...)) covers most integrations. The other subpaths let you register the managed modules, use the React wrapper, or - for teams building a fully custom capture renderer - reach the advanced host-side capture core.
This page is the map of that public surface. Each subpath links to its own guide.
The public subpaths
Section titled “The public subpaths”| Subpath | What it is |
|---|---|
. (root) |
The substrate: Checktiv.init(opts) returns a ChecktivClient with mountProvisioned(...) and a per-module mount(module, opts). Also exports the standalone mount(target, opts), which needs no init() call, and the named mountButton widget. Ships no visual module on its own. |
./idv |
The managed IDV module (camera capture, document scan, liveness). Import it so mount('idv') / mountProvisioned can render it. Heavier than . / ./react (see “Bundle size” below). See Quickstart. |
./fraud |
The consent-gated fraud-signal module. Import it to register it; it stays a no-op until the applicant grants consent. See Fraud consent. |
./custom-form |
The managed custom-form module (author-defined fields on a custom_form step). See Custom forms. |
./custom-form/style.css |
The stylesheet the custom-form module needs. It renders real form controls into your page, so this stylesheet must be present. See Custom forms. |
./collect-user-info |
collectUserInfo({ session }): satisfy a collect_user_info step from your own form. A standalone function, not a mounted module (no UI, no registration import). See Collect user info. |
./esign |
The managed e-signature module (read and sign operator-authored documents on an esign step). Import it to register it. There is no stylesheet to link: the document renders in a hosted frame, and the module injects its own scoped stylesheet for the controls it adds to your page. See “The e-signature module” below. |
./credit-history |
The managed credit-history module (authorization and detail screens on a credit_history step). Import it to register it. There is no stylesheet to link: every screen renders in a hosted frame. A credit_history step is only reachable behind a collect_user_info step, so read “Embedded-workflow renderability” below before you wire it. |
./react |
The React wrapper: ChecktivJourney, ChecktivProvider, ChecktivIdv, useChecktiv(), and useCollectUserInfo(). See React. |
./capture |
Advanced. The Tier-1 headless capture core: createCaptureController. No UI - you render everything. See Advanced capture. |
./capture-ui |
Advanced. The Tier-2 batteries-included renderer: mount(). See Advanced capture. |
./capture-ui/style.css |
The stylesheet the managed IDV capture surface needs. mount('idv') and mountProvisioned render through it, so import it once or the capture screen renders unstyled. See Quickstart. |
./workspace |
The reviewer workspace loader: workspace(config) mounts the hosted review surface for your own staff. Not applicant-facing. See Workspace reviewer. |
./cross-device |
The standalone cross-device handoff panel: mountCrossDevice. See Cross-device handoff. |
./idv/cross-device |
Cross-device overlay orchestration for a custom IDV renderer: openCrossDeviceOverlay, preloadCrossDeviceChunk. See Cross-device handoff. |
./agents |
A machine-readable AI-agent steering manifest (manifest.json). See AI agent steering. |
Root exports
Section titled “Root exports”Beyond the mount functions, the . entry exports these values:
version- the version string baked into this bundle at build time, also readable aswindow.Checktiv.versiononce the CDN tag loads. Log it in a bug report to confirm which bundle a page actually loaded, which is the fastest way to catch a stale CDN cache.CHECKTIV_ERROR_CODES- an array of the journey error codes, the ones that arrive on a mounted module’s error callback. It is not every code the SDK can produce:sessions.createandcollectUserInfo().submit()each have their own separate set, and neither appears here. Use this one to check your journey handler covers each case. A later release can add a code, so keep adefaultbranch in anyswitchover a receivederror.code. See Error reference.isSessionsCreateError- a type guard for the error that a failedsessions.createcall rejects with. Use it to tell a rejected create apart from a thrown programming error, rather than inspecting shape by hand.createChecktivError- builds an error carrying the same shape the SDK emits. Useful when your own wrapper needs to surface a failure through the same handler your SDK errors already flow through.InvalidPublishableKeyError- thrown when a publishable key does not match the expected format, so you can catch a malformed key distinctly from a network failure. It is a format check only: a well-formed key for the wrong region or mode parses without complaint here and is rejected server-side instead.
parsePublishableKey is also currently reachable, both from this entry and as window.Checktiv.parsePublishableKey on the CDN global. It is an internal helper, it is not part of the supported surface, and it is removed in the next major release. Do not import it.
Two further root exports are not listed above because they are documented elsewhere: sessions (see Quickstart) and regionToApiBase.
The self-registration model
Section titled “The self-registration model”The managed modules (./idv, ./fraud, ./custom-form, ./esign, ./credit-history) register themselves when you import them. That import is a side effect: importing @checktiv/sdk-web/idv runs a one-time registration so the substrate can resolve 'idv' by name when you call mount('idv') or mountProvisioned.
import { init } from '@checktiv/sdk-web';import '@checktiv/sdk-web/idv'; // registers the IDV module (side-effect import)
const client = init({ publishableKey: 'ah_pk_us_test_...', getSessionToken });client.mountProvisioned({ target: document.getElementById('idv-container') });If a session declares a module you did not import, the mount fails loudly with sdk_load_failed and an actionable message (“import @checktiv/sdk-web/<module> in your app”) rather than a silent blank mount. Import every module your sessions can declare. Because the imports are side effects, keep them: do not let a bundler tree-shake them away.
The root . entry and the ./react entry deliberately do not bundle the managed modules, so a bundler keeps them small. Add the module import yourself.
Bundle size of ./idv
Section titled “Bundle size of ./idv”./idv is the heaviest subpath in the package: importing it adds a runtime schema-validation layer, about 70 KiB gzipped, that the . and ./react entries do not carry. This exists because ./idv parses capture result messages that cross an origin boundary (the capture surface posting results back to your page), and that boundary carries untrusted input, so it is validated at runtime rather than trusted to a compile-time type alone. Every real identity-verification integration imports ./idv, so plan for this cost when sizing your bundle rather than discovering it in a bundle analyzer.
Embedded-workflow renderability
Section titled “Embedded-workflow renderability”The embedded SDK renders four SDK-renderable applicant steps: id_verification (./idv), custom_form (./custom-form), esign (./esign) and credit_history (./credit-history). It does not render a collect_user_info step (the identity-info collection step). If the workflow also contains an SDK-renderable step, the mount emits a checktiv.idv.error with code sdk_load_failed and stops. If the workflow contains no SDK-renderable step at all (a collect step plus screening checks only), the mount renders nothing and emits no error, so do not wait on an event.
You have three ways to resolve this:
- Order the workflow template so an SDK-renderable step is first, or
- Collect identity fields at verification-create time - pass inline
applicantfields on thePOST /v1/sessionscall - and put the verification step first in the workflow template, or - Collect the identity fields in your own form and satisfy the step client-side with
collectUserInfobefore you mount the journey. See Collect user info.
See Quickstart for the verification-create call.
A credit-history workflow always hits this
Section titled “A credit-history workflow always hits this”Read this before you conclude that adding ./credit-history is enough to make a credit workflow render. For the other three modules the collect-first trap is a workflow you can avoid authoring. For credit_history it is unavoidable by construction: the check declares collect_user_info and a date of birth as required inputs, so a workflow template holding a credit step ALWAYS holds a collect step before it, and the template editor refuses to save one that does not. A credit workflow therefore starts on the one step the SDK does not render, every time.
So one of the three resolutions above is mandatory, not optional, and only two of them apply:
- Seed the applicant fields at create. Pass the inline
applicantfields onPOST /v1/sessions, including the date of birth, and the credit step becomes the first step the SDK has to render. This is the least code. - Satisfy the step client-side. Call
collectUserInfo({ session })from your own form before you mount the journey. See Collect user info.
Ordering a different SDK-renderable step first is NOT a third option for a credit-only workflow, because the credit step’s inputs still have to come from somewhere: putting id_verification in front makes the mount succeed and leaves the credit step unsatisfiable.
Two field-level requirements come with it, and both fail at collect-submit time rather than at mount:
- Date of birth is required. The report cannot be ordered without one. A collect step with the date-of-birth field switched off will not save on a template that holds a credit step.
- The name has to be given names and family name as separate values. A host that sends one typed full-name line gets
422 name_components_requiredon the collect submit. Nothing can split a verbatim full name into components safely, and guessing which words are the surname orders a credit file on a different person. If you are on an older@checktiv/sdk-webwhose form renders a single legal-name box, upgrade before your first credit workflow goes live.
The e-signature module
Section titled “The e-signature module”./esign renders an esign step: the applicant reads one or more operator-authored documents, adopts
a signature, and then signs or declines. Adopting the signature is also the consent act - confirming
the adopt dialog records the electronic-records agreement and the adopted signature together, in that
order - so there is no separate “agree to the notice” screen or checkbox to account for. The notice
itself is reachable throughout, from a link inside the adopt dialog and from the frame’s own
More actions menu.
import { init } from '@checktiv/sdk-web';import '@checktiv/sdk-web/esign'; // registers the e-signature module (side-effect import)
const client = init({ publishableKey: 'ah_pk_us_test_...', getSessionToken });client.mountProvisioned({ target: document.getElementById('journey'), esignCopy: { // Every key is optional. An absent key falls back to the SDK's English text. adopt: 'Seleccione la linea de firma en el documento. Anadir su firma tambien registra su acuerdo para usar registros electronicos.', sign: 'Seleccione Finalizar para aplicar su firma al documento de arriba.', labels: { finish: 'Finalizar', decline: 'Rechazar' }, shell: { adoptTitle: 'Anada su firma', statusSigned: 'Firmado' }, }, onEvent: (event) => { if (event.type === 'checktiv.esign.state') renderYourOwnChrome(event.state); if (event.type === 'checktiv.esign.submitted') advance(event.outcome); },});The document itself renders inside a hosted frame served by Checktiv, not in your page. Your page never receives the document content. The module does append controls of its own to your mount target (the per-document download control, and a state panel), but never the document.
Configuration comes from the signing route, never from /sessions/me. GET /sdk/v1/sessions/me
serves an empty config for an esign step on purpose, so there is exactly one casing of every
setting and exactly one place that can be stale. Do not read e-signature settings anywhere else.
On the CDN script tag, the module’s code arrives when the step does. The tag registers the module
immediately, exactly as before, but the loader itself is a separate file the SDK fetches the first
time an esign step mounts, so a page that never reaches one never downloads it. Nothing changes in
your integration. If that fetch cannot complete, the module reports sdk_load_failed and paints a
short line telling the applicant to reload the page, and esignCopy.error is the key that translates
it, the same key every other loading failure uses. See the npm-versus-CDN section above for what to
allow in a strict Content Security Policy.
There is no stylesheet to link. Unlike ./custom-form and ./capture-ui, the module injects its
own scoped stylesheet into your document, under a ctv-esign- prefix, covering every control it
paints on your page. It deliberately never loads the platform’s own global stylesheet, because that
would define generic class names such as .btn and .card inside a page it does not own.
The primary control is labeled Finish
Section titled “The primary control is labeled Finish”The control that applies the adopted signature and submits is Finish, and its label key is
labels.finish. The sign ceremony state keeps its name, but no on-screen control says “Sign”. The
adopt dialog’s confirm control is separate and is labeled Use this signature (labels.adopt); it
adopts a signature and records consent, and it does not sign.
Translating the ceremony
Section titled “Translating the ceremony”esignCopy is the only way to translate the signing surface, and it is a plain string map you
resolve yourself (the SDK ships no internationalization runtime, so nothing here reads a locale). At
the top level it carries one key per ceremony state plus frameTitle, and below that four nested
maps:
- the state keys - one per ceremony state, carrying that state’s prose. The states are exported as
EsignStateand as theESIGN_STATESarray; see “Every ceremony state” below. frameTitle- the signing frame’s accessible name. It is defaulted, and you can override it.labels- the controls and field labels, keyed byEsignLabel.rights- the electronic-records rights panel, keyed byEsignRightsKey.documents- the document download and print controls, keyed byEsignDocumentCopyKey. See “Saving a copy of the document” below.shell- the chrome around the document, keyed byEsignShellKey. This is the largest of the four and the one an integrator most often misses: it holds all three dialogs, the gated Finish control’s per-requirement prose, the in-frame notice view, and the five terminal status words. See “Theshellmap” below.
Every key in every one of those maps is optional and falls back to English, so a partial map is always safe.
A missing map is not a compile error. TypeScript checks the keys you write; it cannot see that
you never assembled shell at all. Omitting a whole map compiles clean and renders English strings
inside an otherwise translated ceremony - on the dialogs, which is where the consent sentence and
the terminal status words live. If you translate at all, translate all four maps.
The shell map
Section titled “The shell map”EsignShellKey has 24 members. Grouped by what they cover:
| Group | Keys |
|---|---|
| The gated Finish control | stepsBlocked, gateRead, gateSignature, gateAge |
| The consent sentence and age attestation | consentTermsLink, consentTermsNewWindow, consentAgeAttest, consentError |
| The adopt-signature dialog | adoptTitle, adoptConsent, adoptFinePrint |
| The decline dialog | declineTitle, declineBody |
| The finish-later dialog | finishLaterTitle, finishLaterBody |
| The in-frame notice view | disclosureTitle, disclosureVersionLabel, disclosurePublicCopy, disclosureBack |
| The terminal status words | statusSigned, statusDeclined, statusVoided, statusExpired, statusWithdrawn |
Two of these carry more weight than the rest:
adoptConsentis the electronic-records consent clause. It is the sentence the applicant agrees to when they confirm the adopt dialog, and its English default names the confirm control by name so that which act does the agreeing is stated rather than inferred. If you translate it, keep that property: name the control, and do not soften it into a bare “I agree”.consentAgeAttestis the only interpolated string in the whole contract. It carries a{count}token in single braces, which the SDK substitutes with the minimum age the operator configured. A translation that drops the token, or that “corrects” it to double braces, is detected and falls back to English rather than rendering a sentence with no number in it.
Saving a copy of the document
Section titled “Saving a copy of the document”The notice the signer agrees to tells them they need the ability to print or save a copy of what they signed, so the module renders a download control for each document on the request.
Unlike the signing surface, this control is plain DOM appended to your mount target. It has to be: the download runs on the credential the module holds, and the hosted signing frame deliberately never receives that credential.
- It appears as soon as the document set is known, and it is still there after the signer has signed, declined or withdrawn, so a copy stays reachable. If the document set can no longer be read (a canceled request, a session past its deadline), the terminal message renders on its own and no download control appears.
- While a single-document signing frame is on screen it stands down, because the frame’s own top bar carries a save control for that document and two controls for one act, stacked, is noise. It comes back the moment the frame does not have one: after the ceremony ends, when the frame could not open, when the module is reporting a failure over a frame it has disabled, while the signer is withdrawing consent (that surface replaces the frame’s top bar), and on any request carrying more than one document. Do not build a second download control to cover the gap; there is not one.
- With more than one document you get one control per document, numbered in order.
- Translate it through
esignCopy.documents, which has four keys:downloadis the control’s label;printAndSignStartedis the line shown after the print-and-sign control hands the signer the file;downloadFailedis the line shown when a download does not complete; anddownloadRemovedis the line shown when the stored copy is gone for good. downloadFailedanddownloadRemovedare two different answers and you should keep them different. A failed download is retryable, and its line says to select the control again. A removed copy is not: the request succeeded and the bytes no longer exist, because the retention horizon passed or an erasure request was carried out. Telling that signer to try again names an act that can never succeed.- A failed download shows that line and changes nothing else. It emits no
checktiv.esign.errorand never moves the ceremony state, because failing to save a copy is not a failed signing. - The line renders on your mount target for every failed download, including one started from the frame’s own save control while this panel’s control is standing down. The frame relays that act to the module and never learns the outcome, so the mount target is the only surface that can report it.
- The module sets no colors of its own here, so the control inherits your page’s text color and
font. It carries
data-checktiv-esign-download(whose value is the document id) and sits in a panel markeddata-checktiv-esign-documents, so you can target both from your own stylesheet. See “Styling hooks” below for the rest.
The signer can withdraw consent or ask for a paper copy
Section titled “The signer can withdraw consent or ask for a paper copy”United States federal law (ESIGN, 15 U.S.C. 7001(c)) gives a consumer who agreed to transact electronically the right to withdraw that consent, and the right to receive the record on paper. The disclosure the signer reads states both rights and names the route for each, so while the signing session is live the module renders those two controls for you. You do not build them, and for as long as they are on screen you must not hide or suppress them.
Both controls live in one place, and only for as long as the session is live:
- While signing is still open, both controls are inside the signing frame. That is true on the hosted journey and inside your own embed alike; there is no second copy on your mount target.
- Once the ceremony has ended for this signer (they signed, declined, or withdrew), neither control is rendered, on either surface. What remains is the per-document download control on your mount target, the sealed copy the workflow emails the signer when that step setting is on, and the published disclosure, which states the route for the post-signing window: contact the company that sent the link. The entitlement is undiminished; the on-screen control is not what carries it.
esignStateOffersRights(state) is exported from ./esign and tells you whether a given state offers
either control, so your own chrome can react without hardcoding a list of states that will go stale.
It returns false for every terminal state, which is the reliable way to see that the controls are
gone. The underlying table ships as ESIGN_STATE_RIGHTS if you want to read it directly.
What that means for your integration:
- Withdrawing consent ends the signing session. The ceremony stops offering to sign, moves to the
withdrawstate, and you receivechecktiv.esign.statecarrying it. Nochecktiv.esign.submittedfollows, because nothing was signed. Render your own “we will be in touch about continuing on paper” chrome for that state if you want to, and do not treat it as an error. - A signer who withdrew and then comes back arrives on
terminal_withdrawn, notwithdraw. These are two different states and you need both.withdrawis the live session, in the moment they withdraw.terminal_withdrawnis every visit after that: the module reads the withdrawal off the record, renders that state with no signing frame at all, and never offers to sign again. You also receiveterminal_withdrawnif a submit is refused because consent was already withdrawn, for example from a second tab. Binding your chrome only towithdrawleaves a returning signer looking at a state you render nothing for. - A paper-copy request is additive: it is passed to your team, and the signer carries on signing. Nothing about your flow changes.
- Both requests are recorded on the document’s audit trail, and a paper-copy request is surfaced in the console so your team can act on it.
- Translate the panel through
esignCopy.rights. As with every other key, an absent one falls back to English, so a partial map is safe.
Following the ceremony from your own UI
Section titled “Following the ceremony from your own UI”The module emits four events, and the union is closed:
| Event | Payload | What it means |
|---|---|---|
checktiv.esign.ready |
none | The module is mounted and running. |
checktiv.esign.state |
state: EsignState |
The ceremony moved. Emitted on every move. |
checktiv.esign.submitted |
sessionId: string, outcome: 'signed' | 'declined' |
The step was submitted. Terminal. |
checktiv.esign.error |
error: ChecktivError |
The module reported a failure. See “Error codes” below. |
checktiv.esign.state is how you render your own journey chrome for the states the module owns
without making a second call of your own: the module holds the credential, so your page should never
re-derive the state.
Not every ceremony ends with checktiv.esign.submitted. A withdrawal ends it with a state change
and nothing else, because nothing was signed. Drive your journey off checktiv.esign.state and treat
submitted as the signed-or-declined case only.
Every ceremony state
Section titled “Every ceremony state”ESIGN_STATES ships from ./esign as a 23-member array, and EsignState is its union. Check your
own handling against the array rather than transcribing this table; it is here so you can see the
shape of the state machine at a glance.
“Rights” is what esignStateOffersRights answers: whether the withdraw-consent and paper-copy
controls are on screen in that state.
| State | Rights | What the signer is doing or seeing |
|---|---|---|
preparing |
no | The documents are still being frozen. No signing frame yet - see “The states with no signing frame”. |
consent |
yes | Server-refusal only. The frame never derives this state; it is reached when a submit is refused for a missing or mismatched consent. |
read |
yes | The document is on screen and waiting to be read. |
scroll_incomplete |
yes | The read-through requirement is on and the end has not been reached, so Finish is off. |
adopt |
yes | No signature has been adopted yet. Selecting the signature line opens the adopt dialog. |
age_gate |
yes | A minimum age is set and no date of birth is on file, so the signer must confirm their age. |
explain |
yes | Everything is done and the signer is being told what Finish will do. |
sign |
yes | Finish is live. |
decline |
yes | The signer is giving a reason for declining. |
withdraw |
yes | The signer is withdrawing electronic-records consent while the session is still live. |
obscured |
yes | Chromium reported the on-screen Finish control as not being painted, so it is off. See “The Finish-button visibility check”. |
age_blocked |
no | The signer is below the operator’s minimum age, so this document can never be signed here. The frame stays up with Decline live inside it. |
frame_blocked |
no | The signing window never opened. No frame at all, and the panel carries working recovery controls. |
conflict |
no | The document changed while the signer had it open. |
token_expired |
no | The session credential lapsed and your host must re-mint one. Recoverable. This is not the signing link running out; that is terminal_expired. |
protocol_mismatch |
no | The loaded build and the signing frame disagree on the channel version. Terminal and deterministic; only loading a newer build clears it. |
error |
no | The load half of a failure: the ceremony could not be resolved, so nothing was ever offered and nothing was signed. |
submit_error |
no | The submit half: the signer acted and this build could not confirm the act was recorded. It deliberately does not claim nothing was signed. |
terminal_signed |
no | Signed. |
terminal_declined |
no | Declined. A normal outcome, not an error. |
terminal_voided |
no | The request was canceled and can no longer be signed. |
terminal_expired |
no | The time to sign has passed. |
terminal_withdrawn |
no | Consent was withdrawn, so nothing was signed and nothing will be. |
The states with no signing frame
Section titled “The states with no signing frame”Several states paint on your mount target with no signing frame on screen at all, so size your container for a panel rather than only for an iframe:
preparingis the first paint, and it is a skeleton. Not an alert, not a spinner with a refresh button. The module polls a bounded number of times while the document set freezes, and a reload control only appears once that poll passes half its ceiling or the wait simply runs long - offering one from the first second would invite a signer to cancel a wait that was about to succeed. The skeleton carriesdata-checktiv-esign-preparing-skeleton.frame_blockedhas three working controls and no frame. A reload and a print-and-sign control on the panel, plus the per-document download beside it. All three work with no frame, because the parent plane is the half holding the credential. This is the documented recovery path when a content blocker or a filtering network stops the signing window from opening.- The five terminal states paint no frame. The frame is torn down when the ceremony concludes.
conflict,protocol_mismatchanderroralso take the surface back from the frame when the frame is the one that reported them.
token_expired, submit_error and age_blocked are the exceptions worth knowing: none of the
three tears a running frame down. age_blocked deliberately leaves it up so Decline stays live
inside it, which is the blocked signer’s one remaining exit.
Error codes
Section titled “Error codes”checktiv.esign.error carries a ChecktivError. The module reports a closed set of eight codes from
the shared taxonomy, and each one selects the ceremony state whose copy explains it:
error.code |
State the module moves to |
|---|---|
token_expired |
token_expired |
protocol_mismatch |
protocol_mismatch |
submit_failed |
submit_error |
session_expired |
error |
upload_failed |
error |
sdk_load_failed |
error |
session_parked |
error |
wrong_token_type |
error |
Three are worth calling out. wrong_token_type is an integration fault on your side, not a dead
session: a client or link token reached a data plane that takes a different credential.
submit_failed is the one code that does not land on error: it means the signer acted and the
result could not be confirmed, which needs a different sentence from a document that never loaded.
And on the CDN script tag, sdk_load_failed also covers the module’s own code not arriving, which is
why the sentence it selects asks the applicant to reload rather than describing the document.
Keep a default branch in any switch over error.code. See
Error reference for what each code means across the whole SDK.
Styling hooks
Section titled “Styling hooks”The module stamps data attributes on everything it paints into your page, so you can target it from your own stylesheet without depending on class names. The two document-panel attributes are the ones most integrations use; the rest are listed so you are not guessing:
| Attribute | Where |
|---|---|
data-checktiv-esign-documents |
The panel holding the per-document controls |
data-checktiv-esign-download |
One download control; the value is the document id |
data-checktiv-esign-download-error |
The failed-download line |
data-checktiv-esign-download-removed |
The removed-copy line |
data-checktiv-esign-shell |
The module’s own scope container |
data-checktiv-esign-panel |
The state panel |
data-checktiv-esign-tone |
On the state panel; the value is the panel’s tone |
data-checktiv-esign-silent |
On a state panel that is mounted but holding nothing |
data-checktiv-esign-terminal-status |
The terminal status word |
data-checktiv-esign-status |
The state’s sentence |
data-checktiv-esign-actions |
The row of panel controls |
data-checktiv-esign-action |
One panel control; the value is the action name |
data-checktiv-esign-preparing-skeleton |
The preparing skeleton |
data-checktiv-esign-print-note |
The line shown after print-and-sign |
Mounting the module on its own
Section titled “Mounting the module on its own”Every example above mounts through mountProvisioned, which is what most integrations want. The
per-module path is also public and takes the module’s own options:
const handle = client.mount('esign', { target: document.getElementById('journey'), copy: esignCopy, // the same EsignCopy map, under `copy` rather than `esignCopy` onEvent: (event) => { /* ... */ }, onRequestHelp: (state) => openYourSupportRoute(state),});
// Idempotent: tears the frame down and stops the transport and the poll.handle.destroy();onRequestHelp is the module’s one host-bindable seam, and it exists for white-label integrations.
On the hosted journey a signer who lands on a terminal or failed state gets a “Request a new link”
control beside the sentence. In your own embed there is no journey around it, so the panel would
otherwise show a sentence naming the sender and nothing to press. Registering a handler binds that
gap to whatever route you actually have - a support page, your own re-issue flow, a live chat - and
the control is painted only when a handler is registered, so an integration that binds nothing keeps
today’s sentence rather than gaining a button wired to nothing. The states that offer it are error
and the four non-signed terminals; the handler receives the state it was pressed from.
mountProvisioned accepts onRequestHelp directly and forwards it to the module, so you do not have
to drop to the per-module path to bind it. It forwards the handler and nothing else: with no handler
bound, the SDK still invents no action of its own.
It is not an applicant-initiated “send me a new signing link”. No such route exists, deliberately: it would be an unauthenticated re-issue trigger on an expired credential.
The Finish-button visibility check is Chromium-only
Section titled “The Finish-button visibility check is Chromium-only”The signing frame observes its own Finish control with IntersectionObserver v2 and turns the action off while the browser reports the control as covered by something else on the page. It does not react to the control being scrolled out of view: off screen is not covered, and telling a signer to scroll when the real problem is an overlay sends them to fix the wrong thing.
trackVisibility is Chromium-only: on Safari and Firefox the browser reports nothing and this
check does nothing at all, which on mobile is a large share of real traffic. Treat it as defense in
depth, never as a security boundary, and never as protection against clickjacking on non-Chromium
traffic. If your page paints over the frame, Chromium users will see the control turn off with an
explanation.
npm vs CDN installation
Section titled “npm vs CDN installation”npm - install the package and import the subpaths you use:
npm install @checktiv/sdk-webimport { init } from '@checktiv/sdk-web';import '@checktiv/sdk-web/idv';Each subpath is independently tree-shakeable, so a ./idv-only integration never pulls in ./fraud.
CDN - one script tag, and every module is registered for you:
<script src="https://sdk.us.checktiv.com/v1/sdk.js" crossorigin="anonymous"></script>The CDN bundle registers ./idv, ./fraud, ./custom-form, ./esign and ./credit-history eagerly, so there is no per-module import to add. After the tag loads, the SDK is available as window.Checktiv. For production, pin a version and add a Subresource Integrity hash. See Versioning and the release notes.
Registration is eager; weight is not. Every module ships its code as a separate file that the SDK fetches from the same origin the first time that module mounts, so a page that never reaches an identity-verification, fraud, custom-form, e-signature or credit-history step never downloads one. Identity verification is by far the largest of them, so the script tag itself is now a small file. The e-signature module splits again on the same principle: the part that paints the first status line arrives when the step is reached, and the part that talks to the signing frame arrives once the server has answered. There is nothing extra to import and nothing to configure. The SDK also links its own stylesheet from the same origin the first time a step renders, so the capture frame and the custom-form fields are styled without you adding a <link>. The one thing to check is your Content Security Policy: all of this is fetched at runtime and does not carry your page nonce, so a strict nonce-only script-src has to allow the SDK origin, and style-src has to allow it too. See Security headers.
Local development and test mode
Section titled “Local development and test mode”A test-mode publishable key with the synthetic driver runs the full checktiv.idv.* event flow locally with no camera and no capture license. See the local-development section of the Quickstart.
Related pages
Section titled “Related pages”- Quickstart - end-to-end integration walkthrough
- React -
ChecktivJourney,ChecktivProvider, andChecktivIdv - Custom forms - the
./custom-formmodule - E-signature - the
./esignmodule - Collect user info - the
./collect-user-infofunction - Cross-device handoff - the
./cross-deviceand./idv/cross-devicesubpaths - Advanced capture - the
./captureand./capture-uisubpaths - Versioning - pinning and the evolution contract
- REST API reference - use the API directly without the SDK