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…).
Declarative attributes
Section titled “Declarative attributes”| 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. |
Cross-device: scan to share
Section titled “Cross-device: scan to share”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.
Field mapping
Section titled “Field mapping”The SDK maps returned fields to your inputs in priority order:
- Explicit:
<input data-pryvc-field="email">— always wins. - Autocomplete: standard tokens (
given-name,postal-code,tel, …). - 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.
Programmatic API
Section titled “Programmatic API”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 buttonEvents
Section titled “Events”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.
Security model
Section titled “Security model”- PKCE (S256) binds the popup consent to your page’s redemption call.
postMessageis origin-pinned in both directions; astatenonce prevents replay across concurrent popups.- Codes are single-use with a 60-second TTL, and redemption checks your page’s
Originheader against the origin registered at consent time.