AI app builders
Connect forms built by Lovable, Bolt, v0, Replit, Base44 or an AI code editor to Ikiform with one prompt, then check the code, test before a plan and set allowed domains.
Lovable, Bolt, v0, Replit and Base44 build the form you ask for, and AI code editors such as Cursor, Claude Code and Windsurf, now Devin Desktop, write one into your project. Where the submission goes is often left out: the button does nothing, or the tool offers to build a backend, a database table and an email service for it. One prompt points every form at your Ikiform endpoint instead, and Ikiform validates, filters spam, stores, emails and sends webhooks.
Prompts by tool
Each page has the prompt tuned for that tool, such as no Supabase function for Lovable or no Server Action for v0. The prompt below works in all of them.
- LovableNo Supabase function or table.
- BoltNo database or server function.
- v0A client component, no Server Action.
- ReplitNo server route or Replit Secret.
- Base44No entity, backend function or SendEmail.
- CursorFinds every form in the project.
- Claude CodeFinds every form in the repository.
- WindsurfAlso works in Devin Desktop.
The prompt
Copy your endpoint from the form's overview in the dashboard and paste the prompt into the tool's chat with your endpoint in it. It works with any framework and names what the tool shouldn't build.
Connect every form in this project to Ikiform so that each submission reaches me. The forms send straight from the browser. Do not build a backend, server route, API route, Server Action, database table, Supabase or edge function, email service or secret for this.
Endpoint: https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx
Find every form (contact, waitlist, signup, newsletter or any other). Check which framework and form library each one uses. Then, for each form:
1. Keep the form library, validation and components it already uses, such as react-hook-form or zod. Do not add a new dependency.
2. On submit, stop the page from reloading and send a POST request with fetch from the browser to the endpoint. If the framework renders on the server, put this in client-side code.
3. Send the form's fields as a JSON object with the headers "Content-Type: application/json" and "Accept: application/json". Keep every field the form already has and give each one a clear name, such as name, email and message.
4. If the form has an email field, also send its value as _replyto, so I can reply straight from the notification email.
5. Add a hidden text input named _gotcha as a spam trap. Move it off-screen instead of using display: none, give it tabindex="-1", autocomplete="off" and aria-hidden="true", and send it with the other fields. Real visitors leave it empty.
6. While the request is sending, disable the submit button and show a loading state.
7. The response is JSON. Only when it has "ok": true, clear the form and replace it with a short thank-you message. Never show a success message before that.
8. If "ok" is false, show error.message near the submit button, and show each message in error.fields next to the field with that name. If the request fails or the response is not JSON, show "Something went wrong. Please try again."
9. Only put the endpoint in a public environment variable if the project already uses them in browser code. Otherwise keep it as a constant next to the form. Do not add a captcha, an API key or any secret. The endpoint is public and safe to use in the browser.
Keep my design, text and layout exactly as they are. Only change how the forms send. When you are done, list every form you changed.What to check in the code it writes
Open the code view, or the diff in your editor, and read each form's submit handler. It should match this:
| Look for | Why |
|---|---|
A POST with fetch to your endpoint, from browser code | The post comes from the visitor's browser, so Ikiform sees your site as the origin. Ikiform allows CORS from any site, so no proxy is needed. |
Content-Type: application/json and Accept: application/json | Ikiform answers with JSON the code can read, not a redirect or a hosted page. |
_replyto set to the email field's value | Replying to the notification email reaches the visitor. |
An empty _gotcha input moved off-screen, not hidden with display: none | It's the honeypot. Some bots skip inputs that are hidden. Names starting with _ are never stored. |
The thank-you message only when the JSON has "ok": true | Otherwise a held, refused or failed post still shows thanks. |
error.message near the button, and error.fields next to each field | Visitors see why a post was refused, such as a missing required field. |
| No new API route, Server Action, database table, Supabase or edge function, email SDK or secret | None of them are needed, and each is code you'd have to host and maintain. |
The endpoint as a constant, or in a public variable such as VITE_ or NEXT_PUBLIC_ | A server-only variable or a Replit Secret is undefined in the browser, so every post fails. |
To compare against working code, see Plain JavaScript and React. JavaScript and fetch shows the response format.
Test before you pick a plan
Setting up is free, and Ikiform treats a builder's preview as a live site. Until you pick a plan, only posts from your own machine and Send test submission are delivered:
| Where you test | Before a plan |
|---|---|
| Send test submission on the form's page in the dashboard | Always delivered, and doesn't count toward usage |
Your machine: localhost, 127.0.0.1, [::1], *.localhost or *.local, any port | Delivered, the first 50 each month; then 402 test_limit_reached |
| The builder's preview, or the published site | Held for 30 days, up to 100 a month. Visitors are told the form isn't live yet. Picking a plan releases them. |
- Cursor, Claude Code and Windsurf run the project on your machine, so posts from the dev server's
localhostaddress are delivered. - A Bolt or v0 project you download or push to GitHub runs locally the same way, with the project's dev command.
- Agents that test the app by clicking through it can submit your forms. Each of those posts is held like a visitor's. Ask the tool not to submit forms while it tests.
See Testing without a plan for the full rules.
Allowed domains
Allowed domains are empty by default, which accepts posts from any site. If you set them, list every host the form runs on. A listed domain also matches its subdomains, but a builder's preview host is usually a sibling of your published address, not a subdomain of it.
| Where the form runs | Add to Allowed domains |
|---|---|
| Lovable, published | your-app.lovable.app, and your custom domain if you have one |
| Lovable preview | Its own host, such as id-preview--<project-id>.lovable.app or <project-id>.lovableproject.com. Leave allowed domains empty until you publish, or add the exact host from the preview's address bar. |
| Bolt, published | your-site.bolt.host, and your custom domain if you have one |
| Bolt preview | Nothing. The preview runs inside your browser tab on a random webcontainer-api.io host that changes between sessions. |
| v0, deployed | your-project.vercel.app. Preview URLs such as your-project-git-branch-team.vercel.app don't match it; add the exact preview host while you test one. |
| v0 preview | Nothing. It runs on a vusercontent.net host that Vercel doesn't document and may change. |
| Replit, published | your-app.replit.app, and your custom domain if you have one |
| Replit development URL | Nothing. It has the form <id>.<server>.replit.dev and can change each time you reopen the app. |
| Base44, published | your-app.base44.app, and your custom domain if you have one |
| Base44 preview | The exact host from the preview's address bar, such as preview--your-app.base44.app, while you test there |
| Cursor, Claude Code or Windsurf, running locally | localhost. Ikiform compares the host name only, never the port. |
| Wherever you deploy a project from a code editor | The host your hosting gives you, and your custom domain |
- Never add
lovable.app,lovableproject.com,bolt.host,webcontainer-api.io,vercel.app,vusercontent.net,replit.app,replit.devorbase44.appon its own. Every site on that host would match, including other people's. - Before a plan, a post from a host that isn't listed is spam, and spam isn't held. It's dropped, not released when you pick a plan. Leave allowed domains empty while you test on a preview.
fetch, so a form whose check is set to Ikiform answers 403 challenge_required instead of showing the check page. The honeypot and spam scoring still run on every post.Test checklist
- Paste the prompt with your endpoint, and read the list of forms the tool changed.
- Check each submit handler against the table in What to check.
- Click Send test submission on the form's page and confirm it reaches your dashboard and inbox.
- Run the project locally if you can, submit each form, and confirm the submissions are listed in Ikiform.
- Submit a form with an email that isn't valid while the form has fields defined, and confirm the message appears next to the field.
- Pick a plan, publish, and submit once from the published site.
Troubleshooting
| What you see | Why | Fix |
|---|---|---|
| The tool built an API route, database table, Supabase or edge function anyway | It fell back to its own backend for saving data | Send the prompt's first paragraph again, with its "Do not build" line, and ask it to remove what it added. |
Visitors see This form isn't live yet | The workspace has no plan, so posts from the preview and the published site are held | Pick a plan to release them, or test with Send test submission or on localhost. |
Submissions arrive under the spam filter with origin_mismatch | The page that posted isn't on the form's allowed domains | Add the host from the table above. With Reject chosen, the same posts get 403 origin_not_allowed instead. |
Nothing arrives, and the browser console shows a request to undefined | The endpoint is in a server-only environment variable or a Replit Secret, which the browser can't read | Put the endpoint in the code as a constant, or in a variable with your framework's public prefix. |
| The form says thanks, but nothing arrives | The thank-you message isn't gated on "ok": true, so it shows when a post fails or is held | Ask the tool to show thanks only when the response has "ok": true, and error.message otherwise. The browser's Network tab shows the real answer. |
402 test_limit_reached on localhost | The workspace has no plan and already received 50 local test submissions this month | Pick a plan, or keep testing with Send test submission, which still works. |
403 challenge_required | The form's spam check is set to Ikiform, which fetch posts can't show | Turn the check off for this form. |
Related
- HTML formsRedirects, reserved fields and the honeypot.
- Plain JavaScript
fetchwith inline errors. - Allowed domainsHow origins are matched, and what a mismatch does.
- TroubleshootingCORS, origin mismatches and 429s.
- Spam protectionHoneypot, scoring and the human check.
- Site buildersThe embed that works in any builder.