Widget AT Valid — Demo e Integraciones
Validación de email en tiempo real para cualquier formulario. Pruébalo abajo y copia el snippet de tu plataforma.
Se requiere verificación de seguridad antes de usar la demo
Validación detallada
Resultado completo con puntuación, calificación e indicadores
Validación automática (modo widget)
widget.js con reglas de aceptación, validación HTML5 y preventSubmit
API programática
ATValid.validate(email, callback) — valida sin vincularse al DOM
Ejemplos de integración
Una etiqueta de script, un ATValid.init(). Reemplaza pk_live_… por la clave pública de app.atvalid.com/apis (restríngela a tus dominios).
HTML puro — inicio rápido
Cualquier sitio: pega antes de </body>. Cada input[type="email"] se valida al salir del campo.
<!-- Add before </body> -->
<script src="https://www.atvalid.com/widget/v2/widget.js"></script>
<script>
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
preventSubmit: true // block the submit while the email is invalid
});
</script> MutationObserver, así que los formularios inyectados después (AJAX, SPAs, constructores) se detectan solos. No se envía nada a la dirección — la verificación ocurre en el servidor.Todas las opciones, reglas de aceptación y mensajes
Se muestran los valores por defecto. messages.sub (v2.1) da el motivo específico en lugar de un "inválido" genérico.
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
selector: 'input[type="email"]', // which inputs to bind
validateOn: 'blur', // 'blur' | 'input'
verifyAfterDelay: 1000, // ms after typing stops (validateOn: 'input')
timeout: 10, // seconds
showFeedback: true, // message under the input
preventSubmit: false, // block submit when blocked/invalid
formValidation: false, // HTML5 setCustomValidity()
blockOnRateLimit: false,
statusAppendTo: null, // CSS selector or element for the feedback
ignoredForms: [], // form names/ids to skip
ignoredInputs: [], // input names/ids to skip
allow: {
states: ['deliverable', 'risky', 'unknown'], // 'undeliverable' is never accepted by default
free: true, // Gmail, Outlook, Yahoo…
role: true, // info@, sales@, admin@…
disposable: false // temp-mail domains
},
messages: {
checking: 'Verifying email...',
valid: 'Valid email address',
invalid: 'This email appears to be invalid',
disposable: 'Disposable email addresses are not allowed',
role: 'Role-based email addresses are not allowed',
free: 'Free email addresses are not allowed',
suggestion: 'Did you mean {suggestion}?',
networkError: 'Could not verify email. Please check your connection.',
rateLimited: 'Too many requests. Please wait a moment.',
noCredits: 'Validation service temporarily unavailable',
error: 'Could not verify email at this time',
// v2.1 — specific reasons (partial overrides are fine)
sub: {
not_found: 'This mailbox does not exist',
mailbox_full: 'This mailbox is full and cannot receive email',
null_mx: 'This domain does not accept email',
no_mx: 'This domain has no mail server',
blacklist: 'This email domain is blacklisted',
parked: 'This domain is parked and does not receive email',
no_reply: 'No-reply addresses cannot be used',
greylist: 'The mail server asked us to try again later',
toxic: 'This email address cannot be accepted',
catch_all: 'We could not confirm this mailbox exists',
smtp_unknown: 'The mail server did not respond',
suspicious: 'This email address looks suspicious'
}
},
onValidate: function (email, result) { console.log(email, result); },
onError: function (email, error) { console.error(email, error.code, error.message); }
}); WordPress — Contact Form 7, WPForms, Gravity Forms, Elementor, Formidable, Ninja Forms
Agrega en footer.php antes de </body>, o con el plugin "Insert Headers and Footers" / "WPCode" (pie de todo el sitio).
<script src="https://www.atvalid.com/widget/v2/widget.js"></script>
<script>
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
selector: [
'.wpcf7-email', // Contact Form 7
'.wpforms-field-email input', // WPForms
'.gfield input[type="email"]', // Gravity Forms
'.elementor-field-type-email input', // Elementor Forms
'.frm_form_field input[type="email"]', // Formidable
'.nf-form-cont input[type="email"]', // Ninja Forms
'input[type="email"]' // anything else
].join(', '),
validateOn: 'blur',
preventSubmit: true,
allow: { disposable: false, role: false }
});
</script> widget.js de la combinación.RD Station — landing pages y pop-ups
Landing page → Configuración → "Código personalizado (HTML/JS)" → antes de </body>. Los formularios de RD cargan dinámicamente; el widget los espera.
<script src="https://www.atvalid.com/widget/v2/widget.js"></script>
<script>
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
selector: 'input[type="email"], input[name="email"]',
preventSubmit: true,
formValidation: true, // RD's own validation shows our message
allow: { disposable: false }
});
</script> HubSpot — formularios, landing pages, pop-ups
Configuración → Sitio web → Páginas → Avanzado → "HTML del pie del sitio" (o por página). Los formularios de HubSpot se renderizan dinámicamente — se detectan automáticamente.
<script src="https://www.atvalid.com/widget/v2/widget.js"></script>
<script>
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
selector: 'input[type="email"], .hs-input[name="email"]',
preventSubmit: true,
allow: { disposable: false }
});
// Optional: re-scan when HubSpot signals a form is ready
window.addEventListener('message', function (e) {
if (e.data && e.data.type === 'hsFormCallback' && e.data.eventName === 'onFormReady') {
ATValid.refresh();
}
});
</script> Mailchimp — formulario de suscripción incrustado
Pega después del código de embed de Mailchimp en tu sitio (las landing pages alojadas por Mailchimp no aceptan JS personalizado).
<!-- your Mailchimp embed form is above -->
<script src="https://www.atvalid.com/widget/v2/widget.js"></script>
<script>
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
selector: '#mc-embedded-subscribe-form input[type="email"], #mce-EMAIL',
validateOn: 'input', // validate while typing (debounced 1s)
verifyAfterDelay: 1000,
preventSubmit: true,
allow: { disposable: false, role: false }
});
</script> Google Tag Manager — etiqueta Custom HTML
Tipo de etiqueta "HTML personalizado", activador "Todas las páginas" (o solo páginas con formularios). Funciona en cualquier CMS sin tocar el tema.
<script>
(function () {
var s = document.createElement('script');
s.src = 'https://www.atvalid.com/widget/v2/widget.js';
s.async = true;
s.onload = function () {
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
preventSubmit: true,
allow: { disposable: false },
onValidate: function (email, result) {
// push to the dataLayer for GA4 / conversion rules
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'atvalid_email_verified',
atv_accepted: result.accepted,
atv_state: result.state,
atv_sub_status: result.subStatus,
atv_score: result.score
});
}
});
};
document.head.appendChild(s);
})();
</script> onValidate envía un evento al dataLayer para GA4 / reglas de conversión.Webflow, Wix, Shopify, Squarespace — código personalizado del sitio
Webflow: Configuración del proyecto → Código personalizado → Pie. Wix: Configuración → Código personalizado → Fin del body. Shopify: theme.liquid antes de </body>. Squarespace: Configuración → Avanzado → Inyección de código → Pie.
<script src="https://www.atvalid.com/widget/v2/widget.js"></script>
<script>
ATValid.init({
publicKey: 'pk_live_your_public_key_here',
// covers Webflow (.w-input), Wix, Shopify (customer/contact forms) and Squarespace
selector: 'input[type="email"], input.w-input[type="email"], input[name="customer[email]"], input[name="contact[email]"]',
preventSubmit: true,
allow: { disposable: false }
});
</script> React / Next.js
Carga una vez, vincula a tu input, destruye al desmontar. En Next.js marca el componente con 'use client'.
import { useEffect } from 'react';
export function ContactForm() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://www.atvalid.com/widget/v2/widget.js';
script.async = true;
script.onload = () => {
window.ATValid.init({
publicKey: 'pk_live_your_public_key_here',
selector: '#email-input',
preventSubmit: true,
formValidation: true,
allow: { disposable: false },
onValidate: (email, result) => console.log(email, result.accepted, result.subStatus)
});
};
document.body.appendChild(script);
return () => {
window.ATValid && window.ATValid.destroy();
document.body.removeChild(script);
};
}, []);
return (
<form>
<input id="email-input" type="email" placeholder="Email" />
<button type="submit">Submit</button>
</form>
);
} ATValid.refresh() (o confía en el MutationObserver, activo por defecto).Vue 3 / Nuxt
Misma idea con onMounted / onBeforeUnmount. En Nuxt mantenlo dentro de <ClientOnly> o de un componente client.
<script setup>
import { onMounted, onBeforeUnmount } from 'vue';
let script;
onMounted(() => {
script = document.createElement('script');
script.src = 'https://www.atvalid.com/widget/v2/widget.js';
script.async = true;
script.onload = () => window.ATValid.init({
publicKey: 'pk_live_your_public_key_here',
selector: '#email',
preventSubmit: true,
allow: { disposable: false }
});
document.body.appendChild(script);
});
onBeforeUnmount(() => {
window.ATValid && window.ATValid.destroy();
script && script.remove();
});
</script>
<template>
<form><input id="email" type="email" /><button>Submit</button></form>
</template> Callbacks, eventos DOM y el objeto de resultado (v2.1)
Usa onValidate o escucha atv:verified / atv:error en document.
document.addEventListener('atv:verified', function (e) {
var r = e.detail.result;
// r = {
// valid: true|false, // API-level verdict
// accepted: true|false, // passed your allow rules → decides the submit
// state: 'deliverable'|'risky'|'unknown'|'undeliverable',
// subStatus: 'ok'|'not_found'|'mailbox_full'|'disposable'|'null_mx'|'no_mx'|'typo'|
// 'blacklist'|'parked'|'no_reply'|'greylist'|'catch_all'|'suspicious'|
// 'role_based'|'toxic'|'smtp_unknown'|'risky'|'invalid', (v2.1)
// toxicity: 0..5, // reputation risk (≥3 is never accepted) (v2.1)
// catchAllConfidence: 0..10|null, // evidence the mailbox exists on a catch-all domain (v2.1)
// score: 0..100, grade: 'A'..'F',
// disposable, free, role: booleans,
// suggestion: '[email protected]' | null, // typo fix (clickable in the feedback)
// email: '[email protected]',
// raw: { ...full API response }
// }
if (!e.detail.accepted) console.log('blocked:', r.subStatus);
});
document.addEventListener('atv:error', function (e) {
// e.detail.error: NETWORK_ERROR | TIMEOUT | RATE_LIMITED | NO_CREDITS |
// DOMAIN_BLOCKED | AUTH_ERROR | API_ERROR | PARSE_ERROR | NO_KEY
console.warn(e.detail.email, e.detail.error);
}); | Atributo en el input | Valores | Significado |
|---|---|---|
data-atv-valid | "true" | "false" | Aceptado por tus reglas (lo que revisa preventSubmit) |
data-atv-state | deliverable | risky | unknown | undeliverable | Estado derivado |
data-atv-bound | "1" | El widget está vinculado a este input |
API programática — sin vínculo con el DOM
Valida bajo demanda (p. ej. antes de un envío XHR), vuelve a escanear, limpia la caché, desmonta.
// Validate a single address (publicKey optional if init() already ran)
ATValid.validate('[email protected]', 'pk_live_your_key', function (result) {
console.log(result.accepted, result.state, result.subStatus, result.score, result.toxicity);
});
ATValid.refresh(); // re-scan the DOM for new email inputs (SPA navigation)
ATValid.clearCache(); // forget the 5-minute in-page cache
ATValid.destroy(); // remove listeners, observer, styles and feedback Estilos
El widget inyecta un CSS mínimo; sobrescribe cualquier clase en tu hoja de estilos.
.atv-input-valid { border-color: #22c55e !important; box-shadow: 0 0 0 3px rgba(34,197,94,.1) !important; }
.atv-input-invalid { border-color: #ef4444 !important; box-shadow: 0 0 0 3px rgba(239,68,68,.1) !important; }
.atv-input-checking { border-color: #9ca3af !important; }
.atv-feedback { font-size: .8125rem; margin-top: .25rem; font-family: inherit; }
.atv-valid { color: #22c55e; }
.atv-invalid { color: #ef4444; }
.atv-checking { color: #9ca3af; }
.atv-suggestion { color: #d97706; cursor: pointer; text-decoration: underline; }
.atv-suggestion:hover { color: #b45309; }