Your form on your own site
Put a Zanfia signup form on any website (WordPress, Webflow, plain HTML) with your own markup and styling: the native form contract, the script, the payload and the error codes.
A Zanfia signup form does not have to live on a Zanfia page or in an iframe. The same native form that Zanfia pages use works on any site you host yourself: you write the HTML and the styles, one script wires the form to your workspace, and the tags, opt-in mode and thank-you redirect come from the form's settings.
1. Get the snippet
The quickest way is the CLI, which prints ready-made markup for a form:
zanfia forms snippet <formId> --lang pl --first-name
Or write it by hand. The minimum is a form tagged with your workspace id and the form id, an e-mail field, a submit button and the script:
<form data-zanfia-form="{workspaceId}/{formId}">
<label>E-mail<br /><input name="email" type="email" required autocomplete="email" /></label>
<input name="website" type="text" tabindex="-1" autocomplete="off" aria-hidden="true" style="position:absolute;left:-9999px;opacity:0" />
<button type="submit">Sign me up</button>
<div data-zanfia-success hidden>Thank you! Check your inbox to confirm.</div>
<div data-zanfia-error hidden>Something went wrong. Please try again.</div>
</form>
<script src="https://zanfia.co/zanfia-page-forms.js" defer></script>
Your workspace id comes from GET /workspace (or zanfia workspace get), the form id from GET /forms (or zanfia forms list).
2. The contract
The script looks for every form[data-zanfia-form] on the page and takes over its submit. Everything else about the form is yours: tags, classes, layout, CSS.
| Element | Required | What it does |
|---|---|---|
data-zanfia-form="{workspaceId}/{formId}" | yes | Which form receives the signup. |
input[name="email"] | yes | The address. The form does nothing when it is empty. |
input[name="firstName"] | no | Stored on the client. |
input[name="trackingConsent"] (checkbox) | no | Engagement-tracking consent. Only a ticked box grants it. |
input[name="website"] | no | Honeypot. Keep it visually hidden; a filled value means a bot and nothing is sent. |
button[type="submit"] | yes | Gets aria-busy="true" and is disabled while the request runs. |
[data-zanfia-success] | no | Shown after a successful signup when there is no redirect; the fields are disabled and the button hidden. |
[data-zanfia-error] | no | Shown when the request fails; the button is re-enabled. |
data-zanfia-redirect="url" (on the form) | no | Sends the visitor to that URL after a successful signup instead of showing the success state. Absent = the form's own redirectUrl is NOT applied here; set the attribute when you want a redirect. |
The script posts to the origin it was loaded from (https://zanfia.co), never to your domain, so nothing has to be proxied. The endpoint answers the browser's cross-origin preflight and accepts any origin: the call is anonymous, carries no cookies, and the ids in the markup are public anyway. Abuse is limited per IP on the platform side.
3. What is sent
POST https://zanfia.co/api/submitForm with a JSON body:
{
"workspaceId": "work_…",
"formId": "form_…",
"email": "reader@example.com",
"firstName": "Anna",
"trackingConsent": false,
"language": "pl"
}
language is the page's <html lang> (or the browser language) and picks the language of the confirmation e-mail. A 200 means the signup was recorded. For a double opt-in form the subscription, the tags and the consent apply only after the reader confirms from the e-mail; a single opt-in form subscribes immediately.
Other responses: 400 invalid payload (e-mail format, unknown form), 404 form not found, 429 too many requests from one IP, 5xx platform error. The script treats anything but 2xx as an error state.
4. After the signup
- Thank-you page. Put
data-zanfia-redirecton the form to send the reader to your own page. The script also stores the address insessionStorageso a second page carrying adata-zanfia-phone-form(the SMS reminder step) can attach a phone number to the same signup. - Pixels. On a successful signup the script dispatches a
zanfia:form-submittedevent onwindowwith{ workspaceId, formId }, so your own tracking can fire a lead. - Confirmation e-mail. The sender name and the subject come from the form's confirmation e-mail settings (
forms update --confirmation-subject …or the full copy throughconfirmationEmailOverride).
5. Webinar sessions
A form attached to a live room with rolling sessions can offer a session picker. Add data-zanfia-sessions="{workspaceId}/{roomId}" to the form; the script loads the next sessions from the platform and inserts a select before the submit button.
Was this article helpful?

