Skip to content

SDK reference

https://cdn.pryvc.com/v1/pryvc.js — under 4 KB gzipped, zero dependencies, ES2020. Works with plain HTML forms and SPAs (React, Vue, Svelte…).

Attribute Required Description
data-client-id Your public client id (pc_…)
data-fields Comma-separated field keys to request
data-purpose Shown verbatim on the consent screen
data-duration Consent duration, e.g. 90d, 1y (default 90d, max 2y)
data-mode fill (default) or submit (auto-submits the form after filling)
data-env test for sandbox mode
data-label Custom button label (default “Share with PRYVC”)
data-flow auto (default: popup with automatic full-page-redirect fallback when popups are blocked — iOS Safari, in-app webviews), redirect (always navigate), or popup (never fall back). In the redirect flow the page returns with the share completed and the URL cleaned.
data-style Button style tokens, space/comma-separated: dark, light, outline, minimal, pill, sm, lg (combinable, e.g. dark pill lg). Unknown tokens are ignored. See the live gallery.
data-handoff auto (default) or off. Controls scan to share — the QR the consent screen offers on a laptop so the consumer can approve on their phone.

On a non-phone device where the consumer is not signed in, the consent screen shows a QR code alongside the sign-in options. The consumer scans it with their phone’s camera, sees the same consent screen there (already signed in, or one emailed code away), approves, and the form on the originating device fills — the same one-scan experience as paying by phone, without a wallet and without a charge.

Nothing changes for you. Your embed, the filled event, the redeem call, the fingerprint and the ledger record are identical to a same-device consent, because the handoff is transport only:

  • The share code is bound to the originating window’s PKCE challenge, so only your page can redeem it; the phone never holds the verifier.
  • The consumer’s phone is shown the requesting device — browser, platform, approximate location — before approving. A code relayed from another screen does not match, and the consumer is told to decline. This is the only structural defense a QR flow has against relay, so it is on by default and cannot be disabled by the integrator.
  • Codes live three minutes, work once, and the desktop polls for the result (plain polling by design; there is nothing to keep open).

Turn it off with data-handoff="off" (or handoff: 'off' programmatically) if your page is only ever reached from a phone.

What’s next: wallet-based identity and age

Section titled “What’s next: wallet-based identity and age”

The handoff is designed as a general approve on the phone, deliver to the desktop channel. Its kind is share today. A future identity kind is reserved for requests where the phone presents a credential from Apple Wallet or Google Wallet — verified name, age-over, or address from a government ID — rather than a stored profile, for businesses that must verify rather than merely collect. Same QR, same consent screen, same receipt discipline; the SDK surface will not change. No date is promised.

The SDK maps returned fields to your inputs in priority order:

  1. Explicit: <input data-pryvc-field="email"> — always wins.
  2. Autocomplete: standard tokens (given-name, postal-code, tel, …).
  3. Heuristics: input type="email"/type="tel", then name/id patterns (fname, last_name, zip, …).

Passwords, hidden inputs, checkboxes, radios, and file inputs are never touched. input and change events are dispatched so framework state stays in sync.

const instance = Pryvc.init({
clientId: 'pc_your_client_id',
fields: ['first_name', 'email'],
purpose: 'Newsletter signup',
duration: '90d',
mode: 'fill',
container: document.querySelector('#share-slot'), // optional: renders the button
form: document.querySelector('#my-form'), // optional: fill target
});
await Pryvc.open(); // launch the flow without the rendered button
Pryvc.on('filled', ({ fields, share_id }) => { /* form was populated */ });
Pryvc.on('submitted', ({ fields, share_id }) => { /* mode: submit fired */ });
Pryvc.on('error', ({ code, message }) => { /* redeem_failed, … */ });
Pryvc.on('closed', () => { /* consumer dismissed the popup */ });

Listeners registered before the button boots are queued and attached automatically — inline <script> blocks right after the embed tag are safe.

  • PKCE (S256) binds the popup consent to your page’s redemption call.
  • postMessage is origin-pinned in both directions; a state nonce prevents replay across concurrent popups.
  • Codes are single-use with a 60-second TTL, and redemption checks your page’s Origin header against the origin registered at consent time.