An embedded form is a generated, hosted form for a catalog endpoint that you paste into your own page. A visitor fills it in, it calls the API, and the result renders — with no backend of yours in the middle and, crucially, no API key in the browser.
It is the fastest way to put a lookup tool on a site: a VIN decoder on a dealership page, an email checker on a signup landing page, a currency converter in a help article.
| Plan | Embedded forms |
|---|---|
| Free | Not included |
| Starter | Not included |
| Pro | 10 |
| Mega | 30 |
How it works
The form is served from forms.apiverve.com in an iframe and authenticates with a form token
(avf_…), not your API key. Submissions are proxied server-side to the real endpoint using your
key, which never reaches the page.
Three things happen between the visitor pressing submit and the answer appearing, and they are worth knowing because they explain the failure modes further down:
- The token is handed over out of band. It is never in the iframe URL. The frame announces itself when it loads, and the embed script posts the token to it — so the token is not in the page's address bar, in a referrer header, or in anything a proxy logged.
- The page proves which domain it is. The embed script signs the parent domain with a timestamp, and the server checks that signature against your allowed-domain list. A submission that did not come through the official embed script has no valid proof and is refused.
- The submission is proxied. The server attaches your API key, calls the endpoint, and returns the result to the frame. Your key is never on the client at any point.
That is the whole security argument for using this rather than calling the API from your own JavaScript. See CORS for why a browser-side key is a bad idea.
Setting one up
VerveKit → Embedded forms in the dashboard.
- Pick the endpoint. Search the catalog; the preview shows the form that endpoint generates from its published parameters, so required and optional fields are already right.
- Enable the form. That creates its token and unlocks the embed snippet.
- Configure it — see below.
- Copy the snippet into your page.
The fields come from the endpoint's schema, so nothing needs describing by hand and the form cannot drift from what the endpoint accepts. When an endpoint gains a parameter, the form gains the field.
The snippet
<div id="apiverve-form"
data-api-id="emailvalidator"
data-token="avf_your_form_token"
data-captcha="true"
data-layout="compact"
data-color="light"
data-primary="#0070f3">
</div>
<script src="https://forms.apiverve.com/embed.js"></script>Two lines: a container and a script. No framework, no build step, nothing to install — it works in a static site, a CMS block or a landing page builder.
Only data-api-id and data-token are required. Everything else has a default.
| Attribute | Default | |
|---|---|---|
data-api-id | Which endpoint the form calls | required |
data-token | The form token. Not your API key | required |
data-captcha | Whether the CAPTCHA is enforced | true |
data-layout | compact, standard or relaxed — how much room the fields get | standard |
data-color | light, dark or auto | auto |
data-primary | Buttons and accents, as a hex colour | #635bff |
data-showjson | Adds a raw JSON tab to the result, for a developer audience | false |
data-width | 100%, or a pixel value | 100% |
data-height | auto, or a pixel value | auto |
data-max-height | A ceiling for auto height; scrolls beyond it | none |
data-param-* | Pre-fills a field — data-param-email="a@b.com" | none |
Sizing
By default the frame resizes itself as the form does — a short form is short, and a long result does not sit in a scrollbox. The starting height is 400px and it grows from there, restoring your scroll position as it goes so the page does not jump under the reader.
Two ways to constrain it. data-max-height keeps auto-sizing but caps it, scrolling inside the
frame beyond that point — the right choice for an endpoint whose results vary wildly in length.
data-height="600" fixes the height outright and always scrolls, which is what you want in a
layout that cannot tolerate a moving element.
Pre-filling fields
Any data-param-* attribute becomes a value in the form:
<div id="apiverve-form"
data-api-id="currencyconverter"
data-token="avf_your_form_token"
data-param-from="USD"
data-param-to="EUR">
</div>Useful for a form that should start on a sensible default, and for a page that already knows part of the answer — a country page that pre-fills its own country, a docs page that pre-fills the example from the endpoint reference.
More than one form on a page
The script picks up every container whose id starts with apiverve-form, so give each one its
own: apiverve-form-vin, apiverve-form-email. Ids have to be unique in a document anyway, and
this is the naming that makes both forms initialise.
The embed script scans the page once, when the DOM is ready. A container that a framework renders later — after a route change, inside a component that mounts on demand — will not be found, and the console says as much: No form containers found.
In React, Vue or Svelte, render the div first and load embed.js after the component mounts,
rather than putting the script tag in the document head.
Configuration that matters
Allowed domains
A comma-separated list of the domains this form may be embedded on. Domains, not URLs — the
dashboard rejects anything with a scheme or a www. prefix and tells you so.
The rules, all enforced when you save:
- Up to 10 domains, plus
localhost, which does not count against the limit. - A dot is required —
example.com, notexample.localhostis the exception. - Wildcards are written
*.example.com, which covers subdomains. - 500 characters total across the whole list.
This is the restriction that stops someone lifting your snippet onto their own site and spending
your credits. Set it as soon as you know where the form lives, and include localhost while you
are still building.
CAPTCHA
On by default, and the dashboard is blunt about why: Disabling CAPTCHA exposes your API key to bots. Only turn it off for internal sites you control.
The form is a path to your API key that anyone visiting the page can use. The CAPTCHA is what makes that path cost a human being's attention rather than a script's loop. Turn it off only for something behind your own authentication.
The domain list and the CAPTCHA solve different halves of the same problem: the list stops the form being used somewhere else, and the CAPTCHA stops it being used by something else on the page where it belongs. Neither substitutes for the other.
Appearance
Layout, colour scheme and primary colour, all previewed live. The defaults are neutral enough to
sit on most sites; the primary colour is usually the only change worth making. auto follows the
visitor's system theme, which is the right default for a page that has its own dark mode.
File uploads
Endpoints that take a file work here, and are one of the few places embedded forms do something the integration connectors cannot — those filter file-upload endpoints out of their dropdowns entirely. A form for an OCR or face-detection endpoint gets a real file picker and the upload is proxied through as multipart, with a longer timeout than an ordinary submission.
Worth remembering that those endpoints are also the ones with per-endpoint size limits, so check the reference page for the ceiling before you point visitors at one.
What it costs
Embedding is free. Submissions cost the endpoint's normal credits — one credit for most, more for the heavier ones, from the same monthly allowance as everything else. A form nobody submits costs nothing.
Two consequences worth planning around:
A public form is a public spend. Anyone who can load the page can spend a credit. The allowed-domains list and the CAPTCHA are what bound that, and they are worth getting right before you link to the page from anywhere popular.
Watch it like traffic. Analytics shows the endpoint's usage; a form on a page that unexpectedly does well shows up there first. The 80% usage alert in settings is worth leaving on for exactly this.
The forms key
Forms authenticate through a separate credential from your API key, and it can be rotated independently on the API keys page. Rotating your API key does not affect forms, and rotating the forms key does not affect your integration.
Rotating the forms key does invalidate embeds already on your pages, with no grace period — so if a form is embedded somewhere you cannot easily edit, that is a rotation to plan rather than do on impulse. Update the snippet everywhere first, then rotate.
Troubleshooting
Nothing renders and the console says no containers were found. The container did not exist
when the script ran — see the single-page-app note above — or its id does not start with
apiverve-form.
"Missing required attribute." Either data-api-id or data-token is absent. A templating
system that strips unknown attributes is the usual culprit in a CMS.
The form renders but submissions fail. Almost always the domain list: the page's hostname is not on it, or it was entered as a URL and rejected at save time. Check the exact hostname the page is served on, including the subdomain.
It works locally and not in production. Same cause, one step later — localhost is on the
list and the real domain is not.
Submissions fail after a key rotation. The snippet still carries the old token. Copy the current one from the dashboard.
Where forms fit
Good fits: a single-purpose lookup on a marketing page, a self-service checker in a help centre, a demo of what an endpoint returns, an internal tool nobody wants to build a UI for.
Not a fit: anything multi-step, anything that needs to store the submission, anything that needs to happen after the response (send an email, create a record), and anything that needs to combine two endpoints. A form calls one endpoint and shows you what came back. When you need more than that, call the API from your own backend — see making requests — or drive it from an integration platform that has somewhere to put the result.
Next
Mock endpoints and JSON bins are the other two VerveKit tools. CORS explains the browser constraint embedded forms exist to solve, and security covers the rest of the key-handling picture.