form.js

Help peopleget it right.

Validation. Autofill. Connected dropdowns. One script for the form you already have.

Try form.js

Add to your form

Stay in the loop.

Live results

What you get.

An email with useful context.

Email

Waiting for input
Format
—
Mail domain
—
Disposable
—
Role address
—

Loading lookups...

Newsletter starter · HTML
<script src="https://cdn.parseapi.com/v1/form.js"
        data-key="parse_public_YOUR_KEY" defer></script>

<label for="newsletter-email">Email</label>
<input id="newsletter-email" name="email" type="email"
       autocomplete="email" data-parse="email">
Complete examples

A better answer
than “invalid.”

Catch email typos. Format phone numbers. Separate first and last names.

Email

Catch mistakes before they become missed connections.

data-parse="email"
  • Guide incomplete input without a request.
  • Offer a typo correction people can choose.
  • Check mail routing and disposable providers.
  • Identify shared inboxes and consumer mailboxes.
Ready for your form

Domain · Disposable status · Role inbox

Email reference

Phone

A familiar input. A consistent number for your backend.

data-parse="phone"
  • Accept international numbers with a +country code.
  • Use explicit country context for national numbers.
  • Return E.164, national and international formats.
  • Identify the country and numbering-plan type.
Ready for your form

E.164 · National format · Number type

Phone reference

Name

Let people give their name. Get the parts you need.

data-parse="name"
  • Accept Unicode letters and single-word names.
  • Separate first, middle and last names.
  • Keep titles and suffixes in their own fields.
  • Add initials and display formats on paid plans.
Ready for your form

First · Middle · Last · Prefix · Suffix

Name reference

Less typing.
More complete forms.

One answer can fill the next three. Choose a field and see it happen.

A ZIP code. The rest follows.

Fill city, state and timezone from a postal code. This example uses US ZIP codes.

Ready to try
Postal code autofill · HTML
<input aria-label="ZIP code" name="postal"
       data-parse="postal" data-parse-country="US">

<input aria-label="City" name="city" data-parse-fill="city">
<input aria-label="State" name="state" data-parse-fill="state">
<input aria-label="Timezone" name="timezone" data-parse-fill="timezone">
Include form.js once
Australian postcode and suburb choices

Bind your editable suburb input to city and its native suggestion list to localities. One clear API city fills automatically; otherwise the visitor chooses or types a suburb.

Australian postcode · HTML
<label for="postcode">Australian postcode</label>
<input id="postcode" name="postcode" type="text" inputmode="numeric"
       data-parse="postal" data-parse-country="AU">

<label for="suburb">Suburb</label>
<input id="suburb" name="suburb" list="suburbs"
       data-parse-from="postcode" data-parse-fill="city">
<datalist id="suburbs" data-parse-from="postcode"
          data-parse-fill="localities"></datalist>

<label for="state">State</label>
<input id="state" name="state"
       data-parse-from="postcode" data-parse-fill="state">

A choice fills only your bound city and state fields. The parse event keeps the API response in answer and the chosen suburb separately in selection. Keep manual entry available. This is geographic lookup, not mailing-address confirmation.

Retain the Australian data source notice and reuse terms with this data.

Put answers
where they belong.

Text fields. Dropdowns. Textareas. Hidden fields. Connect the controls you already have.

Suggested from your IP address. Always editable.

Text input

Fill an editable field.

Dropdown

Select an existing option.

Textarea

Start with an answer. Edit it freely.

Display text

Show the answer right on the page.

Hidden fields

Send the country code with the form.

Connected controls · HTML
<button id="detect-country" type="button" data-parse="ip">Use my country</button>
<input id="country-code" aria-label="Country code" name="country" data-parse="/country/{code}"
       data-parse-from="detect-country" data-parse-fill="country">
<input aria-label="Calling code" name="calling_code" data-parse-from="country-code" data-parse-fill="calling_code">
<select aria-label="Currency" name="currency" data-parse-from="country-code" data-parse-fill="currency">
  <option value="">Choose a currency</option>
  <option>USD</option><option>CAD</option><option>GBP</option><option>AUD</option>
</select>
<textarea aria-label="Country name" name="country_name" data-parse-from="country-code" data-parse-fill="name"></textarea>
<output aria-label="Country" data-parse-from="country-code" data-parse-fill="name"></output>
  <input type="hidden" name="country_code" data-parse-from="country-code" data-parse-fill="country">
Include form.js once

Speak their
language.

Built-in feedback in six languages. Pick one and try the example.

Sigamos en contacto

Language settings
Page or form language
lang="es"
Form.js feedback only
data-parse-lang="es"

Switching language? Call parseform.scan(). Translate your labels and buttons as usual.

Familiar names. Stable codes.

Choose from 41 display languages and regional variants. Country names change for the reader; the country code stays the same.

Try a country to see its translated name.

Display name
Native name
Country code

More context.
Fewer questions.

Optionally attach country, network, browser and device details to a submission.

Visit details attach after you start typing. Your message stays on this page.

Know the visit.

Country, connection and device details, ready to travel with your form.

Country
Network (ASN)
Browser
Device
Operating system

Start typing to see visit details.

More context with paid plans. Approximate city and region, VPN, Tor, relay and datacenter signals, plus richer browser and bot details. Unavailable values stay blank.

Visit details · add inside your form
<input id="visit-ip" type="hidden" data-parse="ip">
<input type="hidden" name="country" data-parse-fill="country">
<input type="hidden" name="asn" data-parse-fill="asn">

<input id="visit-browser" type="hidden" data-parse="useragent">
<input type="hidden" name="browser" data-parse-fill="browser">
<input type="hidden" name="device" data-parse-fill="device">
<input type="hidden" name="os" data-parse-fill="os">

Suggest their country.

One click uses the connection to fill a country. People can edit it.

Add context to your form

Paste these fields inside your form. Keep the outputs you need and use unique input ids.

Optional visit details · HTML
<!-- Visit details run once after someone starts filling out this form. -->
<!-- Deep data is included with paid plans. -->
<input id="visit-ip" type="hidden" data-parse="ip" data-parse-deep="true">
<input id="visit-useragent" type="hidden" data-parse="useragent" data-parse-deep="true">

<input type="hidden" name="ip" data-parse-fill="ip" data-parse-from="visit-ip">
<input type="hidden" name="ip_country" data-parse-fill="country" data-parse-from="visit-ip">
<input type="hidden" name="ip_asn" data-parse-fill="asn" data-parse-from="visit-ip">
<input type="hidden" name="ip_state" data-parse-fill="deep.state" data-parse-from="visit-ip">
<input type="hidden" name="ip_city" data-parse-fill="deep.city" data-parse-from="visit-ip">
<input type="hidden" name="ip_vpn" data-parse-fill="deep.vpn" data-parse-from="visit-ip">
<input type="hidden" name="ip_tor" data-parse-fill="deep.tor" data-parse-from="visit-ip">
<input type="hidden" name="ip_relay" data-parse-fill="deep.relay" data-parse-from="visit-ip">
<input type="hidden" name="ip_datacenter" data-parse-fill="deep.datacenter" data-parse-from="visit-ip">
<input type="hidden" name="device" data-parse-fill="device" data-parse-from="visit-useragent">
<input type="hidden" name="os" data-parse-fill="os" data-parse-from="visit-useragent">
<input type="hidden" name="browser" data-parse-fill="browser" data-parse-from="visit-useragent">
<input type="hidden" name="bot" data-parse-fill="bot" data-parse-from="visit-useragent">
<input type="hidden" name="bot_name" data-parse-fill="deep.bot.name" data-parse-from="visit-useragent">
Use context on your server

For server decisions, look up context from the incoming request. Download the Node.js helper, set your secret PARSEAPI_KEY on the server, then call:

Your server · Node.js
import { getFormContext } from './form-context-server.node.mjs';

const context = await getFormContext({ visitorIp, userAgent });

Download Node.js helper ↓

Get visitorIp from your framework's trusted proxy configuration, never a submitted hidden field or an unchecked forwarded header. Pass the request's User-Agent as userAgent; it is still client-controlled. Missing answers are null. Your backend decides what needs review.

IP reference · Browser reference

One script.
A whole API behind it.

31 lookup families. Connect an input to ParseAPI and put the answers straight into your form.

Your fields.
More to work with.

Enter a currency code. Fill its name on the page and its symbol in your submitted data.

Include form.js once, then connect the values you need.

Currency details · HTML
<label for="billing-currency">Currency code</label>
<input id="billing-currency" name="currency"
       data-parse="/currency/{code}" placeholder="EUR">
<output data-parse-from="billing-currency" data-parse-fill="name"></output>
<input type="hidden" name="currency_symbol"
       data-parse-from="billing-currency" data-parse-fill="symbol">

Custom lookups fill your fields. Your existing validation decides what to accept.

Simple to start.
Room to make it yours.

Keep the form you built. Add the help it was missing.

Your design.
Native controls and your CSS. Style the helpers or render results in your own components.
Your rules.
Keep required fields, schema validation and your submit handler. Choose which answers your business accepts.
Your stack.
Plain HTML or a framework. Attach new fields with parseform.scan() and respond to field events.
Ready for real people.
Keyboard-friendly suggestions and editable answers. Old results never replace newer input.
Choose what goes to your backend

Your input's name is what your backend receives. data-parse-fill chooses the returned value; data-parse-from connects it to a source input. Use hidden inputs for extra details or visible, editable fields. Dotted keys read nested answers.

Your fields · HTML
<!-- Include form.js once, then add your own fields. -->
<input id="billing-country" name="country"
       data-parse="/country/{code}" placeholder="US">

<input type="hidden" name="billing_currency"
       data-parse-from="billing-country" data-parse-fill="currency">

<input type="hidden" name="calling_code"
       data-parse-from="billing-country" data-parse-fill="calling_code">

Without data-parse-from, an output uses the preceding marked input. Keep input ids unique. Missing answers stay empty; browser-filled fields remain client-controlled.

Use your design and validation rules

Form adds no stylesheet or inline styles. Style the default helpers with .parse-hint, .parse-hint-suggestion and .parse-address-suggestions. Use data-parse-status and data-parse-reason for field states.

For your own components, set data-parse-ui="none". To own validation too, set data-parse-validation="manual". Native HTML rules still apply. Set these options before attachment.

Custom UI · HTML
<!-- Include form.js once. Your markup, CSS, and messages. -->
<input id="contact-email" type="email" name="email"
       data-parse="email" data-parse-ui="none"
       data-parse-validation="manual" aria-describedby="email-help">
<p id="email-help" role="status"></p>
<button id="email-correction" type="button" hidden></button>

<script>
  const email = document.getElementById("contact-email");
  const help = document.getElementById("email-help");
  const correction = document.getElementById("email-correction");
  const copy = {
    invalid: "Check the email format.",
    domain_invalid: "Check the domain after @.",
    disposable: "Use an email you plan to keep.",
    unavailable: "Email check unavailable. You can still send the form."
  };
  email.addEventListener("parse", ({ detail }) => {
    const invalid = ["invalid", "disposable"].includes(detail.status);
    const message = copy[detail.reason] ?? detail.message ?? "";
    help.textContent = message;
    email.setCustomValidity(invalid ? message : "");
    email.setAttribute("aria-invalid", String(invalid));
    correction.hidden = !detail.suggestions.length;
    correction.textContent = detail.suggestions[0]?.label ?? "";
    correction.onclick = () => detail.select?.(0);
  });
</script>

The bubbling parse event returns status, value, answer, reason, message, suggestions and select(index). Your UI owns focus, keyboard interaction and accessibility. Stale selections are ignored after edits.

Use dynamic or framework forms

Include the script once. Call parseform.scan() after mounting new inputs; existing fields stay attached once. With controlled inputs, keep your framework state in sync with input and change events, or handle the parse event in your own components.

Keep unique input ids across forms. Editing a source clears its old generated answers, and stale requests cannot overwrite newer input. Manual corrections remain yours.

Frequently asked questions.

Getting started

Start with the form you have.

What do I need to add form.js?

Include the script once, add data-parse to the inputs you want to enhance, and supply a public ParseAPI key for your website. Your existing form, field names and submit handler stay in place.

The installation starter prepares the code for your site. Complete Newsletter, Contact and Checkout examples include the extra fields that receive returned data.

Will it work with my website or form builder?

Form works with ordinary HTML inputs. You need a way to include JavaScript on the page and add attributes to the actual form controls. A builder that lets you edit both can use the same integration.

Check your builder's restrictions on scripts, custom attributes and embedded forms. Form does not automatically connect to every builder or reach inputs inside another site's iframe. Test the completed form at your submission destination.

Can I keep React, my schema and my validation library?

Yes. Keep your form state, schema and business rules. Form adds field assistance and ParseAPI results; your library can decide how to display and accept them.

For dynamically mounted inputs, call parseform.scan() after mounting. Controlled inputs must keep framework state in sync with input and change events, or consume Form's parse event in your own components. See framework integration and custom validation.

How do the extra details reach my backend?

You choose the fields and their names. Bind returned values to visible or hidden inputs, and they travel with the rest of your form through its normal submission. For example, one full-name input can fill separate first-name and last-name fields.

Form does not create a new submission destination. Missing answers leave generated outputs empty. The field bindings show how to use the names your backend already expects.

Can I use it for more than contact details?

Yes. The same script supports fields such as postal codes, countries, cities, measurements, NPI, VIN and IBAN. Supported custom API paths can fill additional details into fields you define.

Choose the field for the job: a format or checksum result, a matching record and a selected suggestion have different meanings. Try the live field examples and browse the complete lookup catalog.

Checks and coverage

Know what each answer means.

What does the email check tell me?

Form gives local guidance for incomplete input, then asks the Email API about email format, the domain's mail routing and disposable status. It can offer a typo correction for the visitor to select. Returned domain details can also fill your own fields.

A passing result does not prove that the mailbox exists, that a message will arrive or that the visitor owns it. Run any mailbox verification you need on your backend after submission; Form does not run that metered check while someone types.

Does it handle international phone numbers?

Numbers beginning with + carry their own country calling code. To accept national numbers, supply explicit country context, such as data-parse-country="US". Form never guesses a phone number's country from the visitor's IP address.

The Phone API parses, checks numbering-plan validity and returns standardized formats. That does not establish whether a number is active, can receive a message or belongs to the person entering it. See the Phone reference.

What about international names or people with one name?

Name parsing supports Unicode letters and single-word names. A single name can produce a first-name value with no last name; keep that possibility in your form and backend instead of requiring a surname from the parser.

Parsing uses first-name-first order unless a comma explicitly marks the surname. It cannot reliably infer every naming convention or establish someone's identity. Keep names editable and use your own acceptance policy where needed. Name reference

Which addresses can it suggest?

Address autocomplete offers US address suggestions. Enter enough of the street and location, then select a suggestion to fill the connected street, city, state and ZIP fields. People can still enter an address manually and add an apartment or suite.

A selected match helps complete the form; it does not confirm deliverability or verify an apartment. Postal-code and city lookups have their own coverage. See the Address and Postal references.

Which languages does the feedback support?

Built-in messages support English, Spanish, French, German, Brazilian Portuguese and Japanese. Form can follow your page or field language, with an explicit override when needed. Your labels, buttons and custom messages remain yours to translate.

The language of returned display labels is a separate setting, as are name-formatting rules. Changing feedback language does not change the submitted values. Try the language examples.

Behavior and control

Your form keeps the final say.

How quickly do checks happen?

Local email and phone hints need no request. They appear after the visitor leaves a field and update during correction. API checks start when input is ready, after a short pause in typing, and results arrive as requests complete.

You can measure this browser's connection below. This tests the IP endpoint, not a complete field check; typing pauses and other lookups add time. Worldwide speed and status

From your browser

Five requests to /ip. Full response time, including the body and any connection setup.

Does Form work offline?

Once the script has loaded, its local email and phone readiness hints can run without a network request or API key. They explain incomplete input or missing phone-country context; they are not a verified result.

API checks, formatting and returned data still need a connection to ParseAPI. Form is not a complete offline validation engine, and loading the hosted script also needs a connection unless your site has already made it available. An unavailable lookup adds no submission block.

What can stop someone submitting the form?

By default, an API result marked invalid or disposable adds a native browser validation error. Required fields, input types and your existing validation continue to apply. Local readiness hints leave the field unchecked and add no new block.

A failed request, missing key, malformed response or timeout adds no block. Form never waits for a pending lookup before submission. The same applies if the script fails to load: your form's own submission and validation remain in charge.

Can I allow disposable email or use my own messages?

Yes. Manual validation lets your application decide which results to accept, including disposable email. It leaves your native HTML rules and existing validators in place.

You can style Form's built-in helpers or turn them off and build your own interface from its events. Set these options before the fields attach. The UI and validation controls show how; custom interfaces also own their keyboard and accessibility behavior.

Will suggestions overwrite what someone has entered?

Email typo corrections and address suggestions are applied when the visitor selects them. Returned details fill the fields you have explicitly connected. Those fields remain editable.

Form ignores stale results after the source changes and protects edits made while a request is pending. Changing a source clears its previous generated answers so details from an old value do not remain attached to a new one.

Plans and privacy

Understand the requests behind the fields.

Can I start on Free?

Yes. Local email and phone readiness hints work without a key. API checks and returned core data use your public key and the pooled request allowance of your existing ParseAPI plan, including Free. There is no separate Form subscription.

Paid plans add included deep details where supported. Compare the current allowances and plans before choosing the fields and enrichment your form needs.

Do requests count per field or per submission?

Usage comes from API requests, not completed form submissions. A form with several marked fields can make several requests, and editing a value can trigger another check. The script waits for ready input and a typing pause; local hints do not use API requests.

Form supports included lookups and eligible deep enrichment. Metered mailbox, carrier and similar checks belong on your backend after submission; the script does not run them while a visitor types.

Is the API key meant to be visible in the browser?

Yes: use a public key, restricted to your website's allowed domains. Public keys are designed for browser use and are visible in the page. Form refuses secret keys.

The setup flow prepares a public key for your site and its subdomains. Use a localhost allowance for local testing, and manage allowed domains or revoke keys in API keys. Keep your secret server key on your server.

What data is sent to ParseAPI?

Configured field values and their lookup context are sent to ParseAPI for the requested checks. For example, a phone lookup can include its configured country. Your complete form submission goes through your existing backend or form destination.

IP and browser enrichment is a separate opt-in. When enabled for a form, those lookups run after its first non-empty edit, rather than on page load or focus. See optional visit details, the Privacy Policy and Security.

Can my backend trust a hidden field or a passing status?

All browser values remain editable by the client, including hidden inputs and Form's status attributes. Use them to assist the visitor and carry useful details; validate the data your backend relies on before making an acceptance or security decision.

When a server decision needs fresh API evidence, request it on the server with your secret key. For visitor context, use the incoming request and trusted proxy configuration; a submitted IP field is not proof of the connection. The server example shows that boundary.

One script.
A better form.

Start with the fields you have. Free includes 100k API requests a month.