Skip to main content
This page assumes you’ve read Secure Elements Overview — it covers minting a client token, loading the SDK, and styling fields, all of which apply here.

See it live

The demo mints its own token and mounts the viewer automatically. Use Remint token & remount if the reveal buttons stop responding, and Reveal, Reveal CVV only, or Mask to try the field-level controls covered below. Open it in its own tab →

Mint a reveal token

Call POST /v1/client-token with "purpose": "reveal" and the virtualCardId you want to show:
Pass the clientToken and loadToken it returns straight into createCardViewer below.

Create the viewer

fields controls which pieces of the card render, in order — omit it and you get ["pan", "expiry", "cvv"]. Each entry is either a bare field name or a { field, individualReveal } object; "pan" is shorthand for { field: "pan", individualReveal: true }. pan, expiry, and cvv are the only valid field names — anything else throws a FluzElementsError (error.code === "INVALID_FIELD") synchronously, from createCardViewer itself, before you ever call mount().
individualReveal defaults to true on every field. Setting it to false prevents that one field from being revealed on its own — see Reveal a single field. It’s independent of reveal(), which always reveals every field regardless of this setting.

Mount it

mount() appends one sandboxed iframe per configured field into the container element you pass it — three separate frames for the default fields, not one combined frame — and returns a promise that resolves once every frame has completed its handshake. It rejects with a FluzElementsError if:
  • the style you passed to createCardViewer fails validation (error.code === "INVALID_STYLE") — see Styling fields
  • a frame doesn’t complete its handshake within mountTimeoutMs (error.code === "MOUNT_TIMEOUT"; defaults to 10 seconds, and is configurable via createCardViewer({ ..., mountTimeoutMs }))
  • a frame fails to load at all, or this viewer is already mounted (error.code === "MOUNT_FAILED") — each CardViewer instance can only be mounted once; create a new one with createCardViewer if you need to mount again

Reveal and mask fields

  • reveal(field?) — async. Fetches the real value from Fluz and displays it. Called with no argument, it fetches and shows every configured field regardless of individualReveal. Called with a field name, it fetches and shows just that field — unless that field was configured with individualReveal: false, in which case it rejects with error.code === "INDIVIDUAL_REVEAL_DISABLED". An unmounted viewer, or a field name that isn’t one of fields, rejects with MOUNT_FAILED.
  • setMask(field, masked, options?) — synchronous, not async. It never fetches anything — it only toggles what’s currently displayed:
    • setMask(field, true) re-masks the field back to its placeholder, whether or not it was ever revealed.
    • setMask(field, false) un-masks it — but only shows the real value if reveal() already fetched one for that field. Call it before any reveal() and the field just stays on its placeholder, since there’s no fetched value yet to show.
    • setMask(field, true, { hidden: true }) blanks the field completely (empty, not even a placeholder) instead of showing dots/last4/expiry. hidden only has an effect while masked is true.
    • There’s no bulk “mask all” call — call setMask once per field in fields if you need to reset the whole viewer.
  • destroy() — tears down every frame and detaches the viewer. Call this on unmount so you don’t leak mounted frames when your component goes away.

Reveal a single field

To reveal just one field on its own (e.g. a “Show CVV” button next to that field), call reveal(field) — every field defaults to allowing this, so no config is needed for the common case. If a field should never be revealed on its own, and only ever appear as part of the whole-card reveal() call, opt it out with { field, individualReveal: false } in fields:
reveal(field) against an opted-out field rejects with FluzElementsError (code: "INDIVIDUAL_REVEAL_DISABLED") without contacting frame-host. Either way, reveal() with no argument always reveals every mounted field — individualReveal has no effect on it.
This is a client-side integration choice, not a server-enforced capability — it controls what your own UI is allowed to trigger, not what data the grant can return. Don’t rely on individualReveal: false as a security boundary.

Handle events

onMount fires once, after every configured field has rendered inside the frame. onError fires for problems that happen inside an already-mounted frame — a failed reveal() or a rate limit — rather than problems with mount() or createCardViewer() itself, which reject or throw directly instead (see below). Both onMount and onError return an unsubscribe function. Every FluzElementsError this capability can produce, and where it surfaces:

Full example

/mint-reveal-token is your own backend route — the one that calls POST /v1/client-token with your Fluz OAuth access token, as described in Mint a client token.

Next steps

Secure Elements Overview

Token minting, SDK loading, styling, and CSP.

Live demo

Reveal, reveal CVV only, and mask, running against staging.

Example integrations

Runnable plain-HTML and React reveal examples with a token-minting server.