HTML form
Build the form with InvoyForm, then post to it from a form you wrote yourself. You control the markup and the CSS. InvoyForm checks the answers and stores them.
The form
Section titled “The form”Publish the form, open Share, and copy the HTML form. It looks like this:
<form action="https://form.invoy.in/api/public/forms/YOUR_FORM_ID" method="POST"> <label> Full name <input type="text" name="full_name" required> </label> <label> Email <input type="email" name="email" required> </label> <button type="submit">Submit</button></form>It has your questions’ help text, their starting values and the button text you chose in Settings. It is a starting point. Change the markup and style it as you like, but keep each field’s name.
Allowed websites
Section titled “Allowed websites”Your form’s id is in the HTML code you put on your page, so anyone who sees it could use your form from their own site. To stop that, a form works only on websites you allow. Your form’s own link always works.
Open Settings in the builder, add the websites where you use the form, and publish. Only those websites can show the form in a frame (an embed) or send answers from their own HTML form or script. Posts from anywhere else, including a script with no website behind it, are refused with a 403.
my-site.comallows that site only.www.my-site.comis another site: add it too, or add*.my-site.comfor all its subdomains.- The site must use
https.localhost(to test on your machine) always works. - The list takes effect when you publish.
The script
Section titled “The script”The code from Share also has a <script> line and data-ivf on the form:
<form action="https://form.invoy.in/api/public/forms/YOUR_FORM_ID" method="POST" data-ivf> ...</form><script src="https://form.invoy.in/v1/embed.js" defer></script>With it the page does not reload. The script sends the form, turns the button off while it works, shows each answer that is not accepted under its field, and shows a thank-you when it is done. Without it the form still works as a normal post.
You can shape it with attributes. None are needed.
| Attribute | What it does |
|---|---|
data-ivf-error="email" on any element in the form |
Shows the message for the field email there, instead of adding one under the field |
data-ivf-form-error on an element |
Shows messages that are about the whole form (too many attempts, no connection) |
data-ivf-success on a hidden element |
Shown instead of the default thank-you |
data-ivf-redirect="https://..." on the form |
Goes to that address after a successful send. Without it, the form’s own redirect address (if you set one for the form) is used |
data-ivf-state on the form (set by the script) |
idle, submitting, error or success, for your CSS |
Added messages have the class ivf-error (the thank-you has ivf-success) and a plain default look. Style them with your own CSS. A field with a message has aria-invalid="true".
The script uses the browser’s own checks (required, type, min, max…) and shows them in the same place. Every other rule is checked by InvoyForm after the send.
Events
Section titled “Events”The form tells your page what happened, so your code can close a dialog, track a conversion or show its own message. Both events bubble.
| Event | When | event.detail |
|---|---|---|
ivf:success |
The answers were accepted | { redirectUrl }, where the person is sent next, if anywhere |
ivf:error |
The answers were not accepted | { errors: [{ field, message }] }, or { message } for the whole form |
form.addEventListener('ivf:success', () => closeDialog());React, Vue and other frameworks
Section titled “React, Vue and other frameworks”The script also finds forms that appear after the page has loaded, like a form in a dialog or on a page your router shows later. Load the script once, render the form with data-ivf, and let it submit natively: no onSubmit handler and no state for the values. To have your agent do it for you, see Build it with your AI agent.
If your site sends a Content Security Policy, allow https://form.invoy.in in script-src (the script) and connect-src (where it sends the answers), and in frame-src if you use the embed.
Field names
Section titled “Field names”Every field that takes an answer has a name, made from its label as you build (“Full name” becomes full_name). A repeated name gets _2, _3. A field with no label uses its placeholder, then its type. You can change a name in the field’s Advanced tab.
- Post each answer under its field’s
name. - A group of checkboxes shares the field’s name with
[]:name="interests[]". - A group of radio buttons shares the field’s name.
- Once the form is published a name stays as it is, even if you edit the label. Change it yourself in the Advanced tab if you must, and update the HTML forms that use it.
Names that start with _ivf_ are InvoyForm’s own, never a field’s. They are not kept with the answer. Any other name that starts with _ is refused.
| Name | What it is |
|---|---|
_ivf_password |
The form’s password, when it has one. Let the respondent type it: <input type="password" name="_ivf_password">. Never put it in the page’s HTML, where anyone can read it. A script that sends the answers itself can send it this way too. |
After you submit
Section titled “After you submit”- A browser that posts the form lands on the form’s thank-you page, in the form’s theme, or on the form’s redirect address if you set one.
- If an answer is not accepted, the browser is sent back to the form page with the questions that need another look marked. The form is empty again (what was typed is never kept in the address), so the respondent fills it in again.
- A script (
fetch,curl) gets JSON back instead.
For a script, an answer that is not accepted is a 400, and details says which field:
{ "success": false, "message": "Some of the answers need another look.", "details": [ { "field": "email", "message": "Please enter a valid email address." } ]}field is the field’s name.
A form with a File Upload question gives you an <input type="file">. Only the Invoy script can send it (the HTML from the Share page includes it): it sends each chosen file first, then posts the form with the files’ ids in their place. A plain form without the script cannot send files.
If a file is not accepted (too big, a kind the question does not take), the message shows next to its field.
Limits
Section titled “Limits”- The generated HTML is a copy. If you add a required field to the form later, copy the HTML again, or posts without that field are rejected.
- Logic (showing a field only when another has a value) and widgets that need JavaScript are not part of the plain HTML.
- Your plan sets how many HTML posts a month a workspace can receive.