Widget configuration
Complete reference for everything you can configure on the <veridia-widget> custom element.
All attributes
Ten attributes are observed. Only one is required.
| Attribute | Required | Default | Description |
|---|---|---|---|
publishable-key | Yes | — | Your qv_pub_* or qv_pubt_* key |
api-base | No | https://api.xxuxe.online | API endpoint |
user-ref | No | — | Your own user identifier (max 128 chars) |
country | No | — | ISO 3166-1 alpha-2 country code (PY, BR, MX, …) |
document-type | No | — | dni, passport, drivers_license, national_id, other |
submitted-full-name | No | — | User's full name for fuzzy matching (max 255 chars) |
require-doc-back | No | on, except for passports | Whether to capture the back of the document |
locale | No | browser locale, then en | UI language: en, es, pt |
accent-color | No | #0f172a | Any valid CSS color |
active-liveness | No | off | Opt in to the RBS-2 active-liveness challenge |
Attribute details
publishable-key (required)
The only required attribute. It identifies your tenant. Two prefixes:
qv_pubt_*— test environmentqv_pub_*— live environment
Note the test prefix is qv_pubt_, not qv_pub_test_.
<veridia-widget publishable-key="qv_pubt_FJJWXMA2RN2XPRDK6YJX4KTVD0XSQHW9">
Get yours from the dashboard under API keys.
A publishable key can start and submit verifications. It cannot read verdicts — GET /v1/verify/{id} returns 401 secret_key_required for it. That restriction is the whole reason it is safe to put this key in your page source. Never put a qv_sec_* / qv_sect_* key in a browser.
If this attribute is missing when the user presses Start, the widget emits veridia:error with code invalid_api_key.
api-base (optional)
The Veridia API endpoint. It defaults to https://api.xxuxe.online, so in production you can leave it out entirely.
<veridia-widget api-base="https://api.xxuxe.online">
Set it only if you have been given a different endpoint.
user-ref (optional but recommended)
Your own identifier for the user. Max 128 chars. Typically your database primary key.
<veridia-widget user-ref="customer-12345">
It is echoed back in the webhook payload, under userRef.
It is not returned in the veridia:complete event, and it is not returned by GET /v1/verify/{id}. If your integration reads the verdict by polling rather than by webhook, user-ref will never come back to you — store the verificationId → user mapping yourself when veridia:complete fires. See Events.
country (optional but recommended)
ISO 3166-1 alpha-2 country code. Hints which document layout to expect, improving OCR accuracy. The widget uppercases it for you, so py works as well as PY.
<veridia-widget country="PY">
| Code | Country |
|---|---|
PY | Paraguay |
BR | Brazil |
MX | Mexico |
AR | Argentina |
CO | Colombia |
CL | Chile |
PE | Peru |
UY | Uruguay |
document-type (optional)
Hint of what document the user will submit.
| Value | Description |
|---|---|
dni | National ID card (DNI, CI, cédula) |
passport | Passport |
drivers_license | Driver's license |
national_id | Generic national ID |
other | Any other ID document |
Any other value is ignored — the attribute is validated, not trusted.
<veridia-widget document-type="dni">
This also decides the default for require-doc-back, below.
submitted-full-name (optional)
The user's full legal name as they typed it on your form. Max 255 chars. The backend fuzzy-matches it against the OCR'd name and reports the result as the name_match score.
<veridia-widget submitted-full-name="Juan Carlos Perez Gonzalez">
require-doc-back (optional)
Whether the widget asks for a photo of the back of the document.
The default is on for every document type except passport. If you set neither require-doc-back nor document-type, the widget asks for the back — three capture steps, not two. Passports have no back, so document-type="passport" removes the step by itself.
Turning it off requires the exact string "false" or "0":
<!-- Off: two capture steps. -->
<veridia-widget document-type="dni" require-doc-back="false">
<!-- ON. "no" is not "false", and neither is an empty value. -->
<veridia-widget document-type="dni" require-doc-back="no">
<veridia-widget document-type="dni" require-doc-back="">
Anything that is not "false" or "0" resolves to true. This is the opposite of the usual HTML boolean-attribute convention, where presence alone means true and the value is ignored — here the value is what counts.
When you need the back: most Latin American DNIs/CIs carry address and MRZ data on the reverse. Brazilian RG, Mexican INE and similar need both sides.
locale (optional)
UI language: en, es, or pt. Defaults to navigator.language, falling back to English for anything unrecognized.
<veridia-widget locale="es">
accent-color (optional)
Primary color for buttons, links, focus outlines and progress indicators. Default #0f172a (slate-900, near black) — not blue.
Accepts any valid CSS color, not just hex. See Customization.
<veridia-widget accent-color="#7C3AED">
active-liveness (optional)
Opts in to the RBS-2 active-liveness challenge: a server-issued head-pose and reactive-flash challenge that runs after the selfie. Off by default.
<veridia-widget active-liveness="true">
Like require-doc-back, the only values that mean off are "false" and "0"; any other value turns it on. Presence of the attribute with no value turns it on.
Two things to plan for:
- The challenge adds a step to the user's flow and takes time to complete.
- It performs many more uploads than the plain flow (roughly 20 per verification). That matters against the per-IP rate limit of 100 requests / 60 s: several mobile users behind the same CGNAT address can exhaust it mid-capture. See Rate limits.
Programmatic configuration
Instead of attributes, you can set the whole config object in JavaScript:
const widget = document.querySelector('veridia-widget');
widget.config = {
publishableKey: 'qv_pubt_YOUR_KEY',
userRef: 'customer-12345',
country: 'PY',
documentType: 'dni',
requireDocBack: false,
locale: 'es',
accentColor: '#7C3AED',
activeLiveness: true,
};
The property names are camelCase, mirroring the kebab-case attributes. Setting config re-renders immediately.
This is the better option when your values come from application state, and the only option for values you would rather not put in the DOM.
Changing attributes at runtime
Changing an observed attribute re-reads all attributes and re-renders:
widget.setAttribute('locale', 'pt');
widget.setAttribute('accent-color', '#10B981');
config with attribute changesAttributes are authoritative. Touching any observed attribute rebuilds the configuration from the attributes alone — everything you set through the config setter is discarded in that instant, including publishableKey.
The practical failure: you configure the widget with widget.config = {...}, then switch the language with setAttribute('locale', 'pt'). The key is now empty, the user presses Start, and the flow dies with invalid_api_key and a "misconfigured" screen that sends you to audit a dashboard where nothing is wrong.
Pick one mechanism. If you configure programmatically, change the language by assigning a new config object, not by setting an attribute.
Configuration changes do not reset the state machine. Change country or document-type before the user starts capturing — mid-flow changes will not retroactively alter steps already taken.
Multiple widgets on the same page
Several instances can coexist (applicant and guarantor, for example). Each keeps its own configuration, camera and state.
<veridia-widget id="primary-user" publishable-key="…" user-ref="user-123"></veridia-widget>
<veridia-widget id="guarantor" publishable-key="…" user-ref="guarantor-456"></veridia-widget>
face-api.js is loaded once globally by the script tag — there is no per-instance loading penalty. A full example is in Examples.
Payload size
Measured on the current build:
| Asset | Size | When |
|---|---|---|
face-api.js | ~1.33 MB | On page load |
veridia-widget.min.js | ~45 KB | On page load |
Face detection model (tiny_face_detector) | ~196 KB | Lazily, on first capture |
About 1.6 MB total on a cold cache, then browser-cached. One model is loaded, not the full face-api set.
If you have read a figure like 20 MB in an older version of this page, it was wrong by more than tenfold — worth re-checking if that number ruled the widget out for a data-constrained audience.
Styling and sizing
The widget renders in a Shadow DOM, so your page CSS cannot reach inside it and its CSS cannot leak out. The customization surface is accent-color, locale, the host element's box, and subclassing.
The inner card is capped at max-width: 440px and sets no container minimum height. Full details, including subclassing, are in Customization.
Events and error codes
The widget emits two events, veridia:complete and veridia:error. The complete list of error codes lives in Events.
If you are looking for codes like errorInvalidKey or errorBlurry, they were never error codes — they are internal translation-string names that an earlier version of this page published by mistake. The real codes are camera_denied, camera_unavailable, upload_failed, api_unreachable, invalid_api_key, insufficient_credits, rate_limited, user_cancelled and internal_error.
What's next
- Events — event shapes and the full error-code table.
- Customization — accent color, locale, sizing, subclassing.
- Installation — framework-specific setup.
- API Reference — the server-side API that returns verdicts.