Email validation widget for sign-up forms
Add one script tag and a data-simpleverifier attribute to your email field, and the widget catches format errors, typos such as gmial.com, throwaway addresses and role inboxes before the form is sent. It is free, needs no API key and runs entirely in the visitor's browser.
Try it
This form runs the same widget.js you embed. Type an address and leave the field, or pick a sample.
Add it to your form
Paste the script once per page, then add data-simpleverifier to each email input you want checked. Fields added later, such as in a popup or a single-page app, are picked up automatically.
<script src="https://simpleverifier.com/widget.js" defer></script>
<input type="email" name="email" required data-simpleverifier>What it checks
| Check | Example | What happens |
|---|---|---|
| Format | jane@, jane@acme | Error. Blocks the form until fixed. |
| Typo | jane@gmial.com | Suggests jane@gmail.com as a one-click fix. Never blocks. |
| Disposable domain | x@mailinator.com | Error by default. Checked against 262 common throwaway domains. |
| Role address | info@acme.com | Warning by default (52 prefixes such as info@, sales@, noreply@). |
The widget can't tell whether a mailbox exists, and its disposable list is the common providers and their alternate domains, not the full 9,913-domain list the API checks. For both, add the server-side check below.
Options
| data-sv-block="disposable role" | Which findings block the form. Default: disposable. Use "none" to only show hints. Format errors always block. |
| data-sv-badge="off" | Hides the small “Validated by SimpleVerifier” link under the field. |
| data-sv-msg-syntax, -typo, -disposable, -role | Your own wording for each message. In -typo, {suggestion} is replaced by the fix. |
Messages appear under the field in an aria-live region linked to the input with aria-describedby, and blocking errors set aria-invalid and the browser's own validation message. Style them with the .sv-hint, .sv-hint--error, .sv-hint--warn and .sv-badge classes, or set the --sv-error and --sv-warn colours.
// Check any value yourself
SimpleVerifier.check("jane@gmial.com");
// → { code: "typo", email: "jane@gmial.com", suggestion: "jane@gmail.com" }
// Attach to a field added later (fields added to the page are picked up automatically)
SimpleVerifier.attach(document.querySelector("#email"), { block: ["disposable", "role"], badge: false });
// React to results, e.g. to disable your own submit button
document.addEventListener("simpleverifier:check", (e) => {
console.log(e.detail.code, e.detail.blocking); // ok | empty | syntax | typo | disposable | role
});Add live mailbox checks from your backend
Your API key must never be in a web page, so the widget doesn't use one. To also confirm the mailbox exists and check against the full disposable list, call the API from the server that receives the form. Reject only invalid, and let the sign-up through if the check times out. API access comes with the paid plans, from $29.99/month.
Node.js (Express)
// npm i express · SIMPLEVERIFIER_KEY stays on your server
app.post("/signup", async (req, res) => {
const email = String(req.body.email || "").trim();
let status = "unknown";
try {
const r = await fetch(
"https://simpleverifier.com/api/v1/verify?email=" + encodeURIComponent(email),
{ headers: { Authorization: `Bearer ${process.env.SIMPLEVERIFIER_KEY}` },
signal: AbortSignal.timeout(10000) }
);
if (r.ok) status = (await r.json()).status; // valid | risky | invalid
} catch {
// Timeout or network error: let the sign-up through rather than lose it.
}
if (status === "invalid") {
return res.status(422).json({ error: "That email address can't receive mail." });
}
// ...create the account
});PHP
<?php
// SIMPLEVERIFIER_KEY stays on your server
$email = trim($_POST['email'] ?? '');
$ch = curl_init('https://simpleverifier.com/api/v1/verify?email=' . urlencode($email));
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('SIMPLEVERIFIER_KEY')],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
$body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$status = ($body !== false && $code === 200) ? (json_decode($body, true)['status'] ?? 'unknown') : 'unknown';
if ($status === 'invalid') {
http_response_code(422);
exit(json_encode(['error' => "That email address can't receive mail."]));
}
// ...create the accountPython (Flask)
# pip install flask requests · SIMPLEVERIFIER_KEY stays on your server
import os, requests
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.post("/signup")
def signup():
email = (request.form.get("email") or "").strip()
status = "unknown"
try:
r = requests.get(
"https://simpleverifier.com/api/v1/verify",
params={"email": email},
headers={"Authorization": f"Bearer {os.environ['SIMPLEVERIFIER_KEY']}"},
timeout=10,
)
if r.ok:
status = r.json().get("status", "unknown") # valid | risky | invalid
except requests.RequestException:
pass # let the sign-up through rather than lose it
if status == "invalid":
return jsonify(error="That email address can't receive mail."), 422
# ...create the accountCommon questions
- Is the sign-up form widget free?
- Yes. The widget runs entirely in your visitor's browser, needs no account or API key, and has no usage limit. Live mailbox checks are separate: they use the SimpleVerifier API from your own server, which comes with the paid plans.
- Why doesn't the widget check whether the mailbox exists?
- A mailbox check needs your API key, and anything in a web page can be read by anyone who visits it. So the widget does the checks that need no key, and the live check runs on your backend, where the key stays private.
- Can I remove the “Validated by SimpleVerifier” link?
- Yes. Add data-sv-badge="off" to the input, or pass badge: false to SimpleVerifier.attach. It is on by default and we appreciate it when you keep it, but it is your form.
- Does the widget send the email address anywhere?
- No. The script is loaded from simpleverifier.com, and every check runs in the browser against lists inside the script. No address, keystroke or page data is sent to us or anyone else.
- How big is the script and does it need a framework?
- It is a single file with no dependencies that works with plain HTML, React, Vue, WordPress or any form builder that lets you add a script tag and an attribute on the email input.
Verifying addresses while you browse instead? Try the Chrome extension, or see all integrations.