Saltar al contenido principal

Instalacion del widget

El widget Veridia es un solo HTML custom element. Dos tags <script> y un tag <veridia-widget> — esa es la instalacion completa.

Que se instala

Cuando cargas el widget, tu pagina obtiene:

  • Un custom element <veridia-widget> que podes poner en cualquier lado
  • La libreria face-api.js (~6 MB, usada para calidad de selfie + deteccion de cara)
  • El bundle del widget Veridia (~150 KB, modulo ESM)
  • Dos CustomEvents: veridia:complete y veridia:error

Los model files de face-api.js se cargan lazy en el primer uso (alrededor de 14 MB) — quedan cacheados agresivamente despues.

HTML plano

La integracion mas simple posible:

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Verificacion KYC</title>

<!-- El orden importa: face-api primero, widget despues -->
<script src="https://widget.xxuxe.online/face-api.js"></script>
<script type="module" src="https://widget.xxuxe.online/veridia-widget.min.js"></script>
</head>
<body>
<main>
<h1>Verifica tu identidad</h1>

<veridia-widget
id="kyc"
publishable-key="qv_pub_test_TU_KEY"
api-base="https://api.xxuxe.online"
user-ref="customer-12345"
country="PY"
document-type="dni"
locale="es">
</veridia-widget>
</main>

<script>
document.getElementById('kyc').addEventListener('veridia:complete', (e) => {
console.log('Verification ID:', e.detail.verificationId);
// Envia el ID a tu backend para obtener el veredicto
});
</script>
</body>
</html>

React (Create React App, Vite, etc.)

import { useEffect, useRef } from 'react';

export function VeridiaVerification({ userRef, onComplete, onError }) {
const widgetRef = useRef(null);

useEffect(() => {
const node = widgetRef.current;
if (!node) return;

const completeHandler = (e) => onComplete?.(e.detail);
const errorHandler = (e) => onError?.(e.detail);

node.addEventListener('veridia:complete', completeHandler);
node.addEventListener('veridia:error', errorHandler);

return () => {
node.removeEventListener('veridia:complete', completeHandler);
node.removeEventListener('veridia:error', errorHandler);
};
}, [onComplete, onError]);

return (
<veridia-widget
ref={widgetRef}
publishable-key={import.meta.env.VITE_VERIDIA_KEY}
api-base="https://api.xxuxe.online"
user-ref={userRef}
country="PY"
document-type="dni"
locale="es"
/>
);
}

Carga los scripts una vez en index.html:

<script src="https://widget.xxuxe.online/face-api.js"></script>
<script type="module" src="https://widget.xxuxe.online/veridia-widget.min.js"></script>

TypeScript: agrega esto a un archivo *.d.ts para que JSX acepte el custom element:

declare namespace JSX {
interface IntrinsicElements {
'veridia-widget': React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement> & {
'publishable-key': string;
'api-base': string;
'user-ref'?: string;
'country'?: string;
'document-type'?: string;
'submitted-full-name'?: string;
'require-doc-back'?: string;
'locale'?: string;
'accent-color'?: string;
},
HTMLElement
>;
}
}

Next.js

En Next.js, los custom elements necesitan cargar despues de la hidratacion. Usa next/script con strategy="afterInteractive":

// app/layout.tsx (App Router)
import Script from 'next/script';

export default function RootLayout({ children }) {
return (
<html lang="es">
<body>
{children}
<Script
src="https://widget.xxuxe.online/face-api.js"
strategy="afterInteractive"
/>
<Script
src="https://widget.xxuxe.online/veridia-widget.min.js"
type="module"
strategy="afterInteractive"
/>
</body>
</html>
);
}
// app/onboarding/kyc/page.tsx
'use client';

import { useEffect, useRef } from 'react';
import { useRouter } from 'next/navigation';

export default function KycPage() {
const widgetRef = useRef(null);
const router = useRouter();

useEffect(() => {
const node = widgetRef.current;
if (!node) return;

const handler = async (e) => {
const { verificationId } = e.detail;

// Envia a tu backend
await fetch('/api/kyc/complete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ verificationId }),
});

router.push('/onboarding/success');
};

node.addEventListener('veridia:complete', handler);
return () => node.removeEventListener('veridia:complete', handler);
}, [router]);

return (
<main>
<h1>Verifica tu identidad</h1>
<veridia-widget
ref={widgetRef}
publishable-key={process.env.NEXT_PUBLIC_VERIDIA_KEY}
api-base="https://api.xxuxe.online"
locale="es"
/>
</main>
);
}

Vue 3

Vue trata custom elements automaticamente. No necesita config especial:

<template>
<veridia-widget
ref="widget"
:publishable-key="publishableKey"
api-base="https://api.xxuxe.online"
:user-ref="userRef"
locale="es"
/>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const props = defineProps({
publishableKey: { type: String, required: true },
userRef: { type: String, required: true },
});

const emit = defineEmits(['complete', 'error']);
const widget = ref(null);

const completeHandler = (e) => emit('complete', e.detail);
const errorHandler = (e) => emit('error', e.detail);

onMounted(() => {
widget.value?.addEventListener('veridia:complete', completeHandler);
widget.value?.addEventListener('veridia:error', errorHandler);
});

onUnmounted(() => {
widget.value?.removeEventListener('veridia:complete', completeHandler);
widget.value?.removeEventListener('veridia:error', errorHandler);
});
</script>

Carga los scripts en index.html:

<script src="https://widget.xxuxe.online/face-api.js"></script>
<script type="module" src="https://widget.xxuxe.online/veridia-widget.min.js"></script>

Angular

En Angular, necesitas permitir custom elements en tu modulo:

// app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';

@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
// ...
})
export class AppModule {}

Despues usalo en templates:

<veridia-widget
#widget
[attr.publishable-key]="publishableKey"
api-base="https://api.xxuxe.online"
[attr.user-ref]="userRef"
locale="es"
(veridia:complete)="onComplete($event)"
(veridia:error)="onError($event)">
</veridia-widget>

Mobile webview

El widget funciona dentro de iOS WebView y Android WebView. Dos requerimientos:

  1. Permisos de camara: la app host tiene que dar acceso a camara. En iOS, WKWebView.allowsInlineMediaPlayback = true. En Android, override onPermissionRequest para dar RESOURCE_VIDEO_CAPTURE.
  2. HTTPS: incluso en WebView, el widget rechaza correr en origenes inseguros.

Troubleshooting

"Este widget esta mal configurado"

Mas comun: tu dominio no esta en la lista de allowed origins del dashboard.

Fix: dashboard → API Keys → editar tu key → agregar el dominio (ej. https://tuapp.com, o http://localhost:3000 para dev).

El widget carga pero nunca muestra el boton Comenzar

Generalmente face-api.js fallo cargando. Revisa la consola del browser por 404s o errores CSP.

Fix: verifica las URLs de los scripts:

  • https://widget.xxuxe.online/face-api.js deberia devolver 200
  • https://widget.xxuxe.online/veridia-widget.min.js deberia devolver 200

"Camara no disponible"

El usuario denego permiso de camara, o la pagina no es HTTPS.

Fix: asegurate que tu pagina se sirva sobre HTTPS. Los browsers bloquean camara en http:// (excepto localhost).

Las capturas salen borrosas / se dispara el flag de calidad

Los dispositivos mobile auto-focusean mejor que las laptops. Decile a los usuarios que se tomen su tiempo y mantengan firme.

Si tu audiencia usa mayormente desktops, ajusta accent-color y dale claridad UI, pero acepta que algunos usuarios van a necesitar 2-3 reintentos.

React: warning sobre atributo desconocido

React no reconoce custom elements por defecto. Agrega la declaracion TypeScript de arriba, o setea suppressHydrationWarning en el parent.

Next.js: document is not defined durante build

El widget usa APIs del browser. Marca tu pagina como client component ('use client') y asegurate que los scripts usen strategy="afterInteractive".

Errores CSP (Content Security Policy)

Si tu sitio tiene CSP estricto, agrega estas directivas:

script-src 'self' https://widget.xxuxe.online;
connect-src 'self' https://api.xxuxe.online https://*.r2.cloudflarestorage.com;
img-src 'self' blob: data: https://widget.xxuxe.online;
media-src 'self' blob:;
worker-src blob:;

El connect-src para R2 es necesario para upload directo de imagenes desde el browser.

El widget muestra el idioma equivocado

Setea el atributo locale explicitamente:

<veridia-widget locale="es">

Default es el locale del browser, fallback a ingles.

Verificando la instalacion

Una instalacion funcionando deberia pasar este checklist:

CheckComo verificar
Scripts carganTab Network de DevTools — ambos 200
Custom element registradodocument.querySelector('veridia-widget') devuelve un elemento
Boton Comenzar se muestraVisible boton "Comenzar" / "Start"
Prompt de camara apareceDespues de tocar Comenzar
La captura tiene exitoEl evento veridia:complete se dispara con un verificationId

Que sigue