Tally Forms Alternative: Custom Forms With a Submission API (2026)
Forminit is a Tally Forms alternative for teams who want to build the form themselves. You own the markup, the styling and the logic; Forminit gives you an endpoint to POST to, validation, storage, notifications and an inbox.
On this page
The difference is one request. Tally gives you a form. Forminit gives you an endpoint.
If you want a form on a page and you do not want to write code, Tally is a good product and it is free for a lot of what people need. This page is not for that case. It is for the one where you have already built the interface — the multi-step flow, the configurator, the three emoji buttons under an article, the onboarding wizard inside your app — and now you need somewhere for the data to go.
What a form builder can’t give you
Every form builder, Tally included, owns the last mile. The form is rendered by the builder, on the builder’s page or inside an embed, and your job is to configure it. Custom CSS and custom domains change how that rendering looks. They do not change who does the rendering.
That creates a ceiling. You cannot put a builder’s form inside a native mobile app without wrapping it in a webview. You cannot make a single tap on a reaction button into a submission, because the unit of interaction is a form, not a tap. You cannot run a pricing rule against your own database mid-flow. And you cannot send data the user is not allowed to change: Tally’s hidden fields arrive as URL parameters, which means the person filling the form can read and edit them.
Most importantly, you cannot submit from your own code. Tally’s public API is a management API. It lists and creates forms, reads and deletes submissions, returns analytics and manages webhooks and workspaces. There is no documented endpoint that creates a submission. Responses have to come in through a page Tally renders.
The why Forminit page walks through the rest of that ceiling in detail.
The programmatic approach
Forminit inverts the relationship. There is no form to render, no embed to style and no builder to fight. There is an endpoint:
POST https://forminit.com/f/{formId}
It accepts application/json, multipart/form-data for file uploads, and application/x-www-form-urlencoded for a plain HTML form post. The body is a list of typed blocks:
await fetch(`https://forminit.com/f/${FORM_ID}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
blocks: [
{ type: 'sender', properties: { email, firstName, lastName } },
{ type: 'select', name: 'plan', value: selectedPlan },
{ type: 'rating', name: 'urgency', value: 4 },
{ type: 'text', name: 'message', value: message },
],
}),
});
That is the whole integration. Forminit validates each block server-side against its type, stores the submission, sends the notifications, runs spam protection and drops the result into an inbox. What produced those values — a React form, a canvas, a keyboard shortcut, a Swift view, a cron job — is entirely your business.
Because the submission is just a request, it can also come from your server, and that is where it stops being a nicer form endpoint and starts being something a builder cannot do at all:
// app/api/onboarding/route.js
export async function POST(req) {
const session = await auth(); // you decide who they are
const { goal, teamSize } = await req.json(); // they decide the rest
await fetch(`https://forminit.com/f/${FORM_ID}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-KEY': process.env.FORMINIT_API_KEY, // Protected mode
},
body: JSON.stringify({
blocks: [
{ type: 'sender', properties: { email: session.user.email } },
{ type: 'text', name: 'user_id', value: session.user.id },
{ type: 'text', name: 'org_id', value: session.org.id },
{ type: 'select', name: 'plan', value: session.org.plan },
{ type: 'select', name: 'goal', value: goal },
{ type: 'number', name: 'team_size', value: teamSize },
],
}),
});
return Response.json({ ok: true });
}
The user filled in two fields. The submission carries six, and the four they did not fill in came from your session rather than from a URL parameter they could have edited. In Protected mode the form only accepts requests carrying your API key, so the browser cannot bypass the route and post whatever it likes.
Ten things you can build this way
Each of these is a normal afternoon’s work against a submission endpoint, and none of them is a form in the sense a builder means it.
-
Onboarding that already knows the user. Ask only what you do not have. Skip the company-size question for anyone who came in through a seat invite, branch on plan or permission, and attach a verified user ID and organization ID to the completed response. Support sees the answers next to the account they belong to.
-
One-tap emoji feedback. Three reaction buttons under a doc page or a feature. A tap posts a
radioblock and the page ID, then swaps itself for a thank-you. No modal, no iframe, no second page load — and it still shows up as counts and percentages in analytics because the block is typed. -
Feedback on individual AI responses. Thumbs up and down on each message, with
conversation_id,message_id, the model and the product area attached. You get a reviewable stream of exactly which answers went wrong, which is not something you can express as a form at all. -
In-app support with real context. Your own support panel, opened in place, carrying an authorized order ID, the subscription plan, the app version, the current route and a screenshot. The customer writes one sentence instead of answering six triage questions.
-
Native mobile feedback. A SwiftUI or Jetpack Compose sheet using native controls, posted through your backend with the release version and screen name. No webview, no browser chrome, no styling that looks borrowed.
-
Quote requests with server-verified numbers. A configurator or visual selector where your backend re-checks availability and recalculates the price before the request is accepted, then submits a quote ID that matches what your system actually offered. A client-side calculation in a builder is a suggestion; this is a commitment.
-
Checkout and post-purchase surveys triggered by events. Nobody fills in a form. Your order webhook fires, your server posts the order value, SKU mix and fulfilment time, and the follow-up survey response lands in the same inbox as the rest.
-
In-app NPS at the right moment. Not on a schedule and not in an email — after the third successful export, or the first invite sent. Your code decides when the prompt appears and what account data rides along with the score.
-
Multi-step and conversational flows that save as they go. Auto-save each step to local state, restore on return, and post once at the end, or post progressively. The pacing, animation and back-button behaviour are yours because the markup is yours.
-
Client sites that match the design exactly. For agencies and freelancers: the form is built from the same components as the rest of the site, in whatever stack the project uses — HTML, React, Next.js, Vue, Astro, Webflow, WordPress — or generated wholesale by Lovable, v0 or Bolt and pointed at an endpoint. No branding to remove, no builder DOM to override, no plan upgrade to unlock custom CSS.
Contact forms, without the compromise
The plain case still works plainly. Keep the markup you have, add the HTML endpoint or the framework-agnostic SDK, and you are done — no key, no server, Public mode.
The difference shows up as the form grows. A contact form that opens with selectable service cards, reveals project-specific questions, checks your calendar for availability before accepting an inquiry and refuses a date you cannot staff is still a contact form. In a builder it is a feature request. Here it is code you already know how to write, ending in one POST.
Where the two products actually differ
| Forminit | Tally Forms | |
|---|---|---|
| Who renders the form | You do | Tally, on its page or in an embed |
| Submission entry point | POST /f/{formId} from any client | Tally-hosted page or embed |
| Documented API for creating submissions | Yes | No — the API manages forms and reads submissions |
| Where logic runs | Your frontend and backend | Builder conditions and calculations |
| Attaching application data | Any supported block, from client or server | Hidden fields via URL parameters |
| Can the user tamper with that data | No, in Protected mode | Yes — the values are in the URL |
| Native mobile | Direct API call | Webview around a hosted form |
| Sub-form interactions (one tap, one emoji) | Yes | No |
| Server-triggered submissions | Yes | No |
Tally is better at the thing it is for. If you want a survey live in ten minutes, a payment or signature collected without code, forty-five languages out of the box, or a form built by someone who does not write any, use Tally — it does that well and its free tier is genuinely generous. Forminit is the answer to a different question: my frontend already exists, where do I POST?
Analytics for a form you designed yourself
A custom interface can still produce structured response analytics. Map your service cards, dropdowns or emoji buttons to select, radio or checkbox blocks and Forminit reports option counts and percentages in submission details and on the Analytics page. Three emoji buttons feed a radio block perfectly well even though nothing about them looks like a form.
Attribution comes along too: submissions broken down by source, medium and campaign, with UTM parameters and click IDs such as gclid, fbclid and msclkid captured automatically by the browser SDK when present. Form Analytics starts on Pro.
What happens after the POST
The endpoint is the interesting part, but it is not the whole product. Submissions land in a real inbox you can search full-text, filter, star, mark read or unread, annotate with notes and move through To do, In progress, Done and Closed.
Workspaces separate clients and teams with Owner, Admin, Editor and Guest roles, their own API keys and their own SMTP. Notification emails are composed in a visual editor with To, CC, BCC and Reply-to; Business adds autoresponders and custom SMTP. Webhooks on Pro are signed with HMAC-SHA256, with delivery attempts and errors visible in Form Settings → Logs and alerts when they fail.
Files are handled for you, up to 25 MB per submission. Data is hosted on AWS in Ireland; submissions stay until you delete them, with optional per-form retention on Pro and a separate 30-day expiry for spam.
Moving over from Tally
Be clear about what this migration is: you are not repointing an embed, you are building a frontend. Budget for that first.
- Build the interface in your own design system and decide which Form Block each value maps to. This is the real work, and it is also the reason you are switching.
- Move the logic into code. Conditions, calculations and skips become ordinary application code. Pick Public mode for a browser-direct form, or Protected mode wherever a value has to be trusted.
- Connect and test. Wire up the HTML endpoint or SDK, recreate notifications, spam protection and integrations, then walk every conditional path and every error state before you switch traffic.
Export your existing Tally responses and download any attachments you want to keep. Historical submissions, form layouts and logic do not transfer.
FAQ
Can I POST submissions to Tally from my own frontend?
Not with the documented public API. Tally’s API creates and manages forms, and reads or deletes submissions, but there is no documented endpoint for creating a submission. Responses enter through a Tally-hosted page or embed. Forminit exposes POST https://forminit.com/f/{formId}, so any frontend, backend or mobile app can submit.
Can I attach a user ID or other application data to a submission?
Yes, and you can make it trustworthy. Send user_id, organization_id, plan, order_id, conversation_id or any other supported Form Block with the response. In Protected mode your backend resolves those values from the session after checking permissions, so the submitter never sees or controls them.
Do I have to rebuild my form to switch from Tally?
Yes, and that is the point. Forminit does not render a form. You build the interface in your own components and connect it to the endpoint. Swapping an iframe URL will not turn a Tally form into your own UI, so plan the frontend work before you migrate.
Can I use Forminit without writing a backend?
Yes. Public mode accepts submissions straight from the browser with no API key, which covers most contact and signup forms. Protected mode is for when a value has to be trusted, such as a user ID or a verified price.
About this comparison
Published by Forminit. Tally’s capabilities were checked against its official developer documentation and help centre on 17 September 2026. Products change; if something here is out of date, tell us.