# Formbold
> Formbold is a form backend and form API for HTML, React, Next.js, Vue, Webflow and static websites. Point any form at a Formbold endpoint and it stores each submission, filters spam and forwards it to email, Slack, Google Sheets, Notion, webhooks and other apps, with no server code to write or host.
Key facts:
- Each form gets an endpoint like `https://formbold.com/s/YOUR_FORM_ID`. Set it as the form's `action` with `method="POST"`, or send a `fetch` request to it.
- Every input needs a `name` attribute; fields without one are dropped.
- Works the same on plain HTML pages and in React, Next.js, Vue, Angular, Svelte, Astro and other frameworks.
- Submissions are visible in the Formbold dashboard and can be forwarded to email, Slack, Discord, Telegram, Google Sheets, Notion, HubSpot, Mailchimp, Zendesk, Zapier, Make and webhooks.
- Formbold has a REST API and an MCP server for AI assistants.
- GDPR compliant: Formbold acts as a data processor, and every account is covered by a Data Processing Agreement with EU Standard Contractual Clauses (https://formbold.com/FormBold-DPA.pdf). Submissions are encrypted in transit and at rest and are never sold or used to train AI.
- Plans and limits: https://formbold.com/pricing
Quick start:
```html
```
---
# Getting Started with Formbold
Source: https://formbold.com/docs
Section: Docs / Introduction
Connect a static HTML form or a frontend app to Formbold and start receiving submissions in a few minutes.
## What is Formbold?
Formbold is a form backend: point any HTML or JavaScript form at your Formbold endpoint, and it stores each submission, filters spam and sends it to email, Slack, Google Sheets, webhooks and 8 other apps, with no server to run.

It works the same way on a static HTML page as in a Next.js, React, Vue or Angular app, and the Free plan covers 250 submissions a month across 10 forms.
## How do I connect my first form?
It takes five steps:

1. Log in to the dashboard, open **All Forms** and click **Create New Form**.
1. Give the form a name you'll recognise, like "Website contact", and create it. Only you see this name.
1. Open the form and go to the **Form Setup** tab. Copy your endpoint, which looks like `https://formbold.com/s/YOUR_FORM_ID`.
1. Set your form's `action` to that endpoint and its `method` to `POST`.
1. Submit a test entry on your site and check that it shows up under **Submissions**.

The [Form Setup guide](/docs/form-setup) walks through that tab in more detail, including the prompt builder for AI tools like Lovable and v0.dev.
## What does a working HTML form look like?
Here's a complete contact form wired to Formbold:
```html
```
## How do I test it before launch?
Use the **Test Form** tab on your form. It sends a real submission with four fields (Full name, Email, Subject and Message), so you can check your email and connected apps without touching your site.
Test submissions count toward your monthly limit, so a few are fine but don't overdo it. More in [Test Your Form](/docs/test-form).
## Why are some fields missing from my submissions?
Almost always because the input has no `name` attribute. Formbold keys each value by its `name`, so `name="email"` becomes the Email field in your submission. An input without one is ignored.
Two more things to check:
- Use HTML5 validation like `required` and `type="email"` so people fix typos before they submit.
- If the form takes files, add `enctype="multipart/form-data"` to the `
```
Use real names like `email` and `message`, not `field_1`. Those names become the labels in your notification emails and in the **Submissions** table, so you'll thank yourself later.
## Which code examples are on the Form Setup tab?
The tab has copy-ready examples for **HTML**, **React**, **Vue**, **Next.js**, **Angular** and **Ajax**. Pick your stack, copy the snippet, and your endpoint is already filled in.
The longer versions, with loading states and error handling, are in [Code Examples](/docs/code-examples).
## How do I send a test submission?
Click **Send Test Submission** on the Form Setup tab. Formbold sends a sample entry to your form, so you can check your inbox and connected apps before your site is live.
For a fuller test with your own values, use the [Test Form tab](/docs/test-form).
> Test with a real inbox first. Send one test, open the email on your phone, and make sure it didn't land in spam. It's much easier to fix that now than after launch.
## Did an AI tool build your site?
Use **Built with an AI Tool?** on this tab. Pick Lovable, Bolt.new, v0.dev, Cursor, ChatGPT or General, and Formbold writes a prompt with your endpoint in it. The full walkthrough, with the mistakes to check for, is in [Connect AI-Built Forms](/docs/ai-form-builders).
## Where do I go from here?
Once a test submission shows up in **Submissions**, set up where it goes: email recipients on the Settings tab, or apps on the Integrations tab. The **Visit Docs** link on Form Setup brings you back here any time.
---
# Test Your Form Before Going Live
Source: https://formbold.com/docs/test-form
Section: Docs / Introduction
Send a real submission from the dashboard and check that email and your apps receive it, without touching your website.
## What is the Test Form tab for?
It's the quickest way to check your setup end to end. You fill in a short form inside the dashboard, Formbold processes it like any other submission, and you see what your team will see.
Open your form from **All Forms** and click the **Test Form** tab.
## Which fields does the test form send?
Four: **Full name**, **Email**, **Subject** and **Message**. Fill them in with values you'll recognise, like your own name and "Test from dashboard".
If your real form has other fields, such as phone or company, those won't be in the test. To test those, submit the form on your site, even if it's on a staging URL.
## What should I check after sending a test?
Go through this list once, in this order:
1. The entry appears in **Submissions**, in the **Inbox** folder.
1. The notification email arrives at every address in **Recipient (TO)**, plus **CC** and **BCC** if you set them.
1. The email isn't in spam. If it is, mark it as not spam in your mail app so future ones come through.
1. Each connected app on the **Integrations** tab got the entry, for example a new Slack message or a new Google Sheets row.
If the email doesn't arrive, open the Settings tab and check that **Email Notifications** is on in **Email Configuration**.
## Do test submissions count toward my limit?
Yes. A test submission counts toward your monthly submission limit like any other. On the Free plan's 250 a month that rarely matters, but don't script a hundred tests.
## Should I delete test entries?
It's a good habit before you hand a form to a client. Old "test test" rows make the Submissions inbox and exports look messy, and your client may think they're real leads.
---
# Your Dashboard at a Glance
Source: https://formbold.com/docs/dashboard-overview
Section: Docs / Introduction
Where everything lives in the Formbold dashboard, so you can find a setting in one click instead of five.
## What's on the Overview page?
**Overview** is the first page you see after you log in. The four cards at the top show **total submissions**, **spam blocked**, **total forms** and **active forms**. Below them is a chart of the last 30 days.
Further down are your recent forms and a row of quick links to templates, integrations, help, your forms and these docs.
## Where do I create and open forms?
In **All Forms**. Click **Create New Form**, give it a name, and it's ready to use. You can switch between grid and list view and narrow the list with **All Time** and **Filter**.
Each form card shows its name, when you created it, submissions this month and all time, and its endpoint. Open a form to get these tabs:
| Tab | What you do there |
| --- | --- |
| Submissions | Read, star and export entries |
| Form Setup | Copy your endpoint and code examples |
| Analytics | Daily submissions, spam and countries |
| Settings | Email, spam, domains, retention and more |
| Integrations | Connect Slack, Google Sheets, webhooks and other apps |
| Test Form | Send a test submission from the dashboard |
## What's in the sidebar?
Everything outside a single form lives in the sidebar:
| Sidebar item | What it's for |
| --- | --- |
| Workspace Settings | Name, logo, time zone, ownership |
| Manage Team | Invite people and set their role |
| Additional Emails | Addresses your forms can send to |
| API & MCP | API tokens, MCP setup and the API guide |
| Account Settings | Your name, email, password |
| Billing & Usages | Plan limits, usage and invoices |
| Help & Support | Community, FAQs and contact |
The submission limit widget in the sidebar shows how much of this month's allowance you've used. Keep an eye on it in busy months, because submissions over the limit don't wait for you to notice.
## Is there a faster way to get around?
Press **Cmd+K** (or **Ctrl+K** on Windows) to open search. Type a form name or a page, like "billing", and jump straight there. Once you have more than a handful of forms, it beats scrolling.
---
# Account Management & Security
Source: https://formbold.com/docs/account-security
Section: Docs / Account & Security
Change your name, email, logo and password, or delete your account, from Account Settings.
## Where do I change my account details?
Open **Account Settings** in the dashboard sidebar. This page is about you as a person. Workspace details, like its name and time zone, are under **Workspace Settings** instead.

## What can I change in Account Settings?
Your **logo**, your **name** and your **email**. The email is the one you log in with, so double-check it before you save.
## How do I change my password?
Use **Change password** on the same page. Pick something long that you don't use anywhere else, and store it in a password manager. If teammates need access, invite them from **Manage Team** rather than sharing your login.
## How do I delete my Formbold account?
Use **Delete account** at the bottom of Account Settings. This can't be undone. Export any submissions you need first, and if you own a workspace other people use, transfer it to them in **Workspace Settings** before you delete.
## Where are API tokens and extra email addresses?
They have their own pages in the sidebar:
- **Additional Emails** holds the addresses your forms can send notifications to. See [Additional Emails](/docs/linked-emails).
- **API & MCP** is where you create and revoke API tokens and set up the MCP server. See [API Tokens](/docs/api-tokens).
- **Billing & Usages** shows your plan limits and invoices. See [Billing and Plans](/docs/billing-plans).
---
# Additional Emails
Source: https://formbold.com/docs/linked-emails
Section: Docs / Account & Security
Add the email addresses your forms can send notifications to, so they show up in Recipient (TO), CC and BCC.
## What are Additional Emails?
They're the addresses, other than your own login email, that your forms are allowed to send to. A client's inbox, your sales alias, a shared support address. Once you add one, it shows up in **Recipient (TO)**, **CC** and **BCC** on every form's **Email Configuration** card.

## How do I add an email address?
1. Open **Additional Emails** in the dashboard sidebar. You can also get there from **Manage workspace emails** under Recipient (TO) on a form.
1. Enter the address, like `sales@yourclient.com`, and add it.
1. If Formbold sends a confirmation email, ask the owner of that inbox to click the link in it.
1. Open a form's Settings tab and pick the address in **Recipient (TO)**, **CC** or **BCC**.
Add the address before you hand a form over to a client. It saves a back-and-forth on launch day.
## How many addresses can I add?
The counter at the top of the page shows how many you've used, for example "0/100" on Premium. The limits per plan are:
| Plan | Additional emails |
| --- | --- |
| Free | 2 |
| Starter | 50 |
| Premium | 100 |
| Business | 300 |
Sending one form to more than one recipient needs **Starter or higher**.
## How do I remove an address?
Delete it from the **Additional Emails** page. Do this when someone leaves a client team or a project ends, so form data stops going to an inbox nobody watches. Then check the forms that used it still have a recipient.
---
# API Tokens & Authentication
Source: https://formbold.com/docs/api-tokens
Section: Docs / Account & Security
Create, use and revoke the API tokens that authenticate your requests to the Formbold REST API and MCP server.
## What are Formbold API tokens for?
An API token lets your code or AI assistant act on your Formbold account without your password. You send it with each request to the [REST API](/docs/api-reference) or the [MCP server](/docs/mcp-server).
You might give one to a backend job that copies new submissions into your database, or to Cursor so it can create and manage your forms through MCP. API access is included on **every plan, including Free**.
Treat tokens like passwords. Anyone who has one can read your submissions.
## How do I create an API token?
1. Open **API & MCP** in the dashboard sidebar.
1. Go to the **API Tokens** tab.
1. Create a new token and give it a name that says where it's used, like "Production CRM sync".
1. Copy the token right away and store it in a password manager or your server's environment variables.
Make one per app or machine. Then, when you retire a server, you revoke its token and nothing else breaks.
## How do I use the token in a request?
Send it in the `Authorization` header with the `Bearer` scheme:
```bash
Authorization: Bearer YOUR_TOKEN
```
A quick way to check that a token works is to fetch a form's submissions. Replace 3Vy25 with your own form ID:
```bash
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.formbold.com/api/forms/3Vy25/submissions
```
The REST API has one endpoint today:
| Method | Endpoint | What it does |
| --- | --- | --- |
| GET | https://api.formbold.com/api/forms/:formId/submissions | Lists a form's submissions (turn on HTTP API for that form first) |
The full details, with parameters and responses, are in the [API reference](/docs/api-reference).
## How do I use the token with the MCP server?
Send the same header to `https://api.formbold.com/mcp`. Most clients take it in a `headers` field next to the server URL. Setup for Cursor, VS Code, Claude Code, Claude Desktop and Codex is in [MCP Server](/docs/mcp-server).
If the token is missing, the MCP server answers 401 with "Authentication token is required for Formbold MCP access." If it's wrong, expired or revoked, the message is "Invalid or expired Formbold MCP API token."
## How do I revoke a token?
Open **API & MCP**, go to **API Tokens**, and revoke the token you no longer need. Any app still using it gets a `401 Unauthorized` from then on, so update that app with a new token first if it should keep working.
## How do I keep tokens safe?
- Never commit tokens to Git, and never put one in client-side JavaScript. Anyone can read those.
- Store it in an environment variable, like `process.env.FORMBOLD_API_TOKEN`.
- Revoke any token you think has leaked. Then create a new one. It takes a minute.
The **API Guide** tab on the same page has a short version of this, if you want it handy while you work.
---
# Billing, Invoices & Plan Quotas
Source: https://formbold.com/docs/billing-plans
Section: Docs / Account & Security
Compare Formbold plans, check your usage in Billing & Usages and download invoices.
## Which Formbold plans are there?
Four: **Free**, **Starter**, **Premium** and **Business**. Every plan includes the REST API and the MCP server. Paid plans add integrations, file uploads and higher limits.

## What does each plan include?
| Feature | Free | Starter | Premium | Business |
| --- | --- | --- | --- | --- |
| Price | $0 | $8/month, or $6/month billed yearly | $20/month, or $15/month billed yearly | $40/month, or $30/month billed yearly |
| Monthly submissions | 250 | 3,000 | 10,000 | 30,000 |
| Forms | 10 | Unlimited | Unlimited | Unlimited |
| Workspaces | 1 | 1 | 5 | Unlimited |
| Team members | 1 | 2 | 5 | 20 |
| Additional emails | 2 | 50 | 100 | 300 |
| File uploads | No | 5 files, 10 MB each | 10 files, 25 MB each | 10 files, 50 MB each |
| API and MCP access | Yes | Yes | Yes | Yes |
| Integrations and webhooks | No | Yes | Yes | Yes |
| Custom redirect | No | Yes | Yes | Yes |
| Auto Responder | No | No | Yes | Yes |
| Allowed domains, custom subject, multiple recipients | No | Yes | Yes | Yes |
| Export submissions (CSV) | No | Yes | Yes | Yes |
| Remove Formbold branding | No | No | Yes | Yes |
| Priority support | No | Yes | Yes | Yes |
## How do I check my usage?
Open **Billing & Usages** in the sidebar. **Current Plan Limits** shows three meters: monthly submissions, form creation and additional (target) emails. The submission limit widget in the sidebar shows the same monthly count on every page.
If you're close to the limit near the end of a month, upgrade before it runs out rather than after. It's one less thing to explain to a client.
## How do I upgrade my plan?
Click **Upgrade Plan** in the dashboard header, or compare plans on the [pricing page](/pricing). Payments are handled by Paddle.
## How do I download invoices?
Your invoices are listed on **Billing & Usages**. Click download next to any invoice to save a copy for your records or your accountant.

## Is yearly billing cheaper?
Yes, by 25% on every paid plan: $6 instead of $8 a month on Starter, $15 instead of $20 on Premium, and $30 instead of $40 on Business.
---
# Workspaces & Team Collaboration
Source: https://formbold.com/docs/workspaces-teams
Section: Docs / Workspaces & Teams
Keep each client or project in its own workspace, with its own forms, settings and team.
## What is a Formbold workspace?
A workspace is a separate space for one client, project or department. Each one has its own forms, submissions, settings and team. If you build sites for clients, make one workspace per client and you'll never send Client A's leads to Client B.

## How many workspaces and team members do I get?
| Plan | Workspaces | Team members |
| --- | --- | --- |
| Free | 1 | 1 |
| Starter | 1 | 2 |
| Premium | 5 | 5 |
| Business | Unlimited | 20 |
The **Manage Team** page shows how many seats you've used, like "01/05" on Premium.
## How do I move a form to another workspace?
Open the form, go to **Settings**, and use **Move Form** in the **General** card. Pick the target workspace and confirm. Afterwards, open the form's **Form Setup** tab and check that the endpoint matches what your website posts to.
## How do I work with my team?
Invite people from **Manage Team** with their email address and a role, **Admin** or **Member**. Everyone logs in with their own account, so nobody shares passwords. Details are in [Team Roles](/docs/team-roles).
## What can I change for each workspace?
Name, logo, description and time zone, plus Workspace Activation, Transfer Ownership and Delete Workspace. See [Workspace Settings](/docs/workspace-settings).
---
# Workspace Settings & Configuration
Source: https://formbold.com/docs/workspace-settings
Section: Docs / Workspaces & Teams
Set your workspace's name, logo, description and time zone, switch it on or off, transfer ownership, or delete it.
## Where are workspace settings?
Open **Workspace Settings** in the dashboard sidebar. Everything here applies to the workspace you're in right now, so check the workspace name at the top before you change anything.

## How do I change the workspace name, logo and description?
Edit them at the top of Workspace Settings. Your team sees the **name** and **logo** when they switch workspaces, so use the client's or project's real name and logo. That makes it hard to open the wrong one.
The **description** is a short note for your team, like "Acme marketing site forms, owned by Sara".
## How do I set the workspace time zone?
Pick your zone in **Time zone** and click **Save timezone**. It has its own save button, separate from the rest of the page, so don't skip it.
Set it to where the people reading the submissions are. "Submitted at 3:00" is only useful if everyone agrees which 3:00.
## What does Workspace Activation do?
**Workspace Activation** switches the whole workspace on or off. Read the note next to the control before you switch off a workspace that has live forms on a website.
## How do I transfer workspace ownership?
Use **Transfer Ownership**. Pick the teammate who should own the workspace and confirm. This is the right move when you hand a finished project to a client: invite them, transfer ownership, and they get full control.
## How do I delete a workspace?
Use **Delete Workspace** at the bottom of the page. It deletes the workspace's forms and submissions for good. Export what you need first, or move individual forms to another workspace with **Move Form** in each form's General settings.

---
# Team Roles & Permissions
Source: https://formbold.com/docs/team-roles
Section: Docs / Workspaces & Teams
Invite teammates and clients to a workspace as an Admin or a Member, without sharing your login.
## How do I invite someone to my workspace?
Open **Manage Team** in the dashboard sidebar.

1. Enter the person's email address.
1. Choose a role: **Admin** or **Member**.
1. Send the invite.
They join with their own Formbold account. The **Members** list shows everyone in the workspace, with a counter like "01/05" for the seats you've used.
## Which roles are there?
Two you can invite people as, plus the owner.
The **owner** is the person who created the workspace, or who received it through **Transfer Ownership**. The owner controls ownership and can delete the workspace.
An **Admin** is for people who help you run the workspace, like a project lead or an agency partner.
A **Member** is for people who work with forms and submissions day to day, like a client's sales team.
When in doubt, start someone as a Member. It's easy to promote a person later, and awkward to take access back.
## How many people can I add?
It depends on your plan: 1 team member on Free, 2 on Starter, 5 on Premium and 20 on Business. Need more seats? Upgrade from the **Upgrade Plan** button.

## How do I find a teammate in a long list?
Use the filters above the **Members** table. On a busy agency workspace, filtering by role is the quickest way to check who still has Admin access.
---
# Form Settings
Source: https://formbold.com/docs/form-settings
Section: Docs / Form Settings
A tour of your form's Settings tab, card by card: General, Email Configuration, Spam & Security, Allowed Domains, Auto Responder, Advanced Options and Danger Zone.
## Where are my form's settings?
Open the form from **All Forms** and click the **Settings** tab. Settings are per form, so changing one form never affects another. The cards below appear in the same order as in the dashboard.
## What's in the General card?

**Form name** is for you and your team. Visitors never see it, so name forms by site and purpose, like "Acme: Contact".
**Form Enabled** switches the form on or off. When it's off, Formbold rejects new submissions. Use it to pause an old form instead of deleting it.
**Submission Archive** decides whether Formbold stores submissions. Turn it off and submissions are still sent to email and your apps, but **file uploads are not stored**. More in [Data Retention and Submission Archive](/docs/data-retention).
**Move Form** moves the form to another workspace. Handy when a client project grows into its own workspace. After a move, open **Form Setup** and check the endpoint your site uses.
## What's in Email Configuration?
This is where you set who gets an email for each submission: **Recipient (TO)**, **CC**, **BCC**, **Sender Name**, **Email Subject**, the **Email Branding** logo and a **Preview** button. It also holds **Redirect URL** and the **HTTP API** toggle.

Each field is explained in [Email Notifications](/docs/email). Two quick notes on plans: multiple recipients, custom subjects and redirects need **Starter or higher**, and removing Formbold branding needs **Premium or Business**. The logo can be JPEG, PNG, WebP or SVG, up to 2 MB.
## What's in Spam & Security?
Three toggles: **Basic Spam Filter**, **Automatic reCAPTCHA** and **Custom reCAPTCHA**, which takes your own **Site Key** and **Secret Key**. Turn on the basic filter for every form. The setup steps are in [Spam Protection](/docs/spam-protection).
## How do Allowed Domains work?
Turn on **Allowed Domains** and list the sites that may submit to the form, such as `yourdomain.com` and `staging.yourdomain.com`. Submissions from anywhere else are rejected. It's on **Starter and higher**.

List every domain the form really lives on, including `www` if you use it. A missing staging domain is the usual reason a test "doesn't work".
## How do I send an automatic reply?
Turn on **Auto Responder**. Formbold then emails the person who submitted the form, which is a nice way to confirm you got their message. It's on **Premium and Business**.

Your form needs an input with `name="email"`, or Formbold has nowhere to send the reply. Keep the message short and set expectations, like "We reply within one working day." Turn on spam protection too, so you're not sending replies to bots.
## How do file uploads work?
Add `enctype="multipart/form-data"` to your form and a file input with a `name`:
```html
```
File uploads are on **Starter, Premium and Business**. Starter takes up to 5 files of 10 MB each per submission, Premium up to 10 files of 25 MB, and Business up to 10 files of 50 MB. Files are stored with the submission, so keep **Submission Archive** on for forms that take uploads.
## What's in Advanced Options?

**Email Grouping** puts notifications with the same subject into one thread in your mail app.
**Intro text** adds a line to the top of each notification email. You can use `+name`, `+email` and `+form` in it.
**Data retention** sets how long submissions are kept: 7 days, 30 days, 3 months, 6 months, 1 year, 2 years, 3 years or Never. See [Data Retention](/docs/data-retention).
## How do I delete a form?
Use **Danger Zone** at the bottom of the Settings tab. Deleting a form removes it and all its submissions for good. If you might need the data, export it from **Submissions** first, or just switch **Form Enabled** off.
## Where did submissions and analytics go?
They have their own guides now: [Manage Form Submissions](/docs/submissions) and [Form Analytics](/docs/form-analytics).
---
# Email Notifications
Source: https://formbold.com/docs/email
Section: Docs / Form Settings
Choose who gets an email for each submission and what that email looks like. It's all in the Email Configuration card on your form's Settings tab.
## Where do I set up email notifications?
Open your form, click the **Settings** tab and find the **Email Configuration** card. Email is built in. You don't connect it as an app, and it works on every plan.

Make sure the **Email Notifications** toggle is on. If it's off, submissions are still saved and still go to your connected apps, but nobody gets an email.
## How do I choose who receives each submission?
Use **Recipient (TO)**. It's a multi-select, so you can pick more than one address. Sending one form to several recipients needs **Starter or higher**.
The list only shows addresses you've added to your account. To add a new one, click **Manage workspace emails** under the field, or open **Additional Emails** in the sidebar. See [Additional Emails](/docs/linked-emails).
## How do CC and BCC work?
**CC** sends a visible copy to another address. **BCC** sends a hidden copy, which is handy for an archive inbox or a manager who wants to see volume without being on every reply thread.
My advice: put the person who actually replies in TO, and everyone else in CC or BCC. When three people are all in TO, nobody is sure who should answer.
## Can I change the sender name and subject line?
Yes. **Sender Name** is the name people see in their inbox, like "Acme Website". Use something your team will recognise at a glance.
**Email Subject** sets the subject line of each notification. Custom subjects are available on **Starter and higher**. A subject that names the form, like "New demo request (website)", makes inbox filters easy to set up.
## What is the intro text, and which tokens can I use?
**Intro text** is a short line at the top of each notification email. You'll find it under **Advanced Options** on the Settings tab. You can insert three tokens:
- `+name` adds the submitter's name
- `+email` adds the submitter's email
- `+form` adds the form name
For example: "New message from +name (+email) on +form". This only works if your form fields are actually called `name` and `email`.
## Can I group notification emails into threads?
Turn on **Email Grouping** under **Advanced Options**. Emails with the same subject are grouped into one thread in your mail app. That's tidy for a busy form, but if you triage each lead separately, leave it off.
## How do I add my logo to notification emails?
Upload it under **Email Branding** in Email Configuration. The logo can be a **JPEG, PNG, WebP or SVG** file, up to **2 MB**. A wide, short logo on a transparent background looks best in most mail apps.
Removing Formbold branding from emails is part of the **Premium and Business** plans.
## How do I preview the email before going live?
Click **Preview** in Email Configuration to see the email with your current settings. Then send a real one from the [Test Form tab](/docs/test-form) and open it on your phone. Mobile mail apps are where layouts usually break.
## What else is in Email Configuration?
Two settings that aren't about email but sit in the same card:
- **Redirect URL** sends people to your own thank-you page after they submit a plain HTML form. Available on **Starter and higher**.
- **HTTP API** allows programmatic access to this form's submissions. Turn it on if you'll read submissions with the [REST API](/docs/api-reference) or the MCP server.
## Why didn't my notification email arrive?
Check these in order. First, that **Email Notifications** is on. Second, that the address is in **Recipient (TO)**. Third, your spam folder. Most missing emails are in one of those three places. If the submission isn't in **Submissions** either, the problem is on the form side, so check your `action` URL.
---
# Manage Form Submissions
Source: https://formbold.com/docs/submissions
Section: Docs / Form Settings
Read, sort and export the entries your form receives, and keep spam out of your way.
## Where do I see my form submissions?
Open **All Forms** and click **View Submissions** on a form card. Or open the form and pick the **Submissions** tab. A **New** badge on the card, like "1 New", tells you there's something you haven't read.

## What do the Inbox, Unread, Starred and Spam folders mean?
Every form has four folders on the left of the Submissions tab.
- **Inbox** holds every submission that passed the spam check.
- **Unread** shows only the ones nobody has opened yet. It's the best place to start your day.
- **Starred** is your shortlist. Star the leads you need to follow up on and they stay here.
- **Spam** holds what Formbold's spam check caught. Look through it now and then, especially in the first week after launch, in case a real message got caught.
## How do I read the submissions table?
Each row shows **#**, **Date**, **TID**, **Name**, **Message** and **Action**. The Action column holds what you can do with that row. The table is paginated, so use the page controls at the bottom on busy forms.
The submission count on a form card in **All Forms** adds up Inbox and Spam. If that number looks high next to your Inbox, check the Spam folder before you worry.
## How do I filter submissions by date?
Use the **All Time** control above the table to narrow the date range, and **Filter** for other conditions. Click **Refresh** to load anything that came in while the page was open. The table doesn't update on its own.
If you see "No submissions to display" for a moment, wait a second. That message can flash while the table loads.
## How do I export submissions to CSV?
Click **Export** above the table. You get a CSV file you can open in Excel, Numbers or Google Sheets.
Export is available on **Starter, Premium and Business**. On Free you can still read every submission in the dashboard.
Set the date range before you export. A client who asks for "last month's leads" doesn't want three years of data.
## Can I get submissions somewhere else automatically?
Yes, and it's usually better than exporting by hand every week. Send each entry to Google Sheets, Slack, Notion or your own server from the **Integrations** tab. See [Connecting Apps](/docs/connecting-apps).
How long Formbold keeps submissions is up to you. That's set per form under [Data retention](/docs/data-retention).
---
# Data Retention and Submission Archive
Source: https://formbold.com/docs/data-retention
Section: Docs / Form Settings
Decide whether Formbold stores your submissions, and for how long.
## How long does Formbold keep my submissions?
As long as you tell it to. Each form has its own **Data retention** setting. Open the form, go to **Settings**, and find it under **Advanced Options**.
You can pick one of these:
| Option | What happens |
| --- | --- |
| 7 days | Submissions older than 7 days are deleted |
| 30 days | Older than 30 days are deleted |
| 3 months | Older than 3 months are deleted |
| 6 months | Older than 6 months are deleted |
| 1 year | Older than 1 year are deleted |
| 2 years | Older than 2 years are deleted |
| 3 years | Older than 3 years are deleted |
| Never | Submissions are kept until you delete them or the form |
Check what your form is set to before you assume anything. The forms we looked at were on 3 years.
## Which retention period should I pick?
Keep data only as long as you need it. A contact form that feeds a CRM or Google Sheets rarely needs more than 30 days in Formbold, because the real record lives elsewhere. A job application form might need 6 months or a year.
If you have a privacy policy that promises a deletion window, set the form to match it. It's an easy thing to get right, and it's awkward to explain if it's wrong.
> Export what you need before you shorten the retention period. Older entries are deleted once they fall outside the new window, and you can't undo that.
## What does Submission Archive do?
**Submission Archive** sits in the **General** card on the Settings tab. It controls whether Formbold stores submissions at all.
With it on, every entry is saved and shows up in **Submissions**. With it off, Formbold still sends each submission to your email and connected apps, but doesn't keep a copy.
The dashboard's own warning matters here: **if Submission Archive is off, file uploads are not stored.** If your form takes attachments, like CVs or invoices, leave the archive on.
## When should I turn Submission Archive off?
When you never want the data to sit on Formbold. A common case is a form that sends straight to your own server through a webhook, where your database is the only copy you want.
Test it first. Send one submission with the archive off and make sure it arrives everywhere it should, because there's no copy in the dashboard to fall back on.
---
# Form Analytics
Source: https://formbold.com/docs/form-analytics
Section: Docs / Form Settings
See how many submissions a form gets each day, how much of it is spam, and which countries it comes from.
## What does the Analytics tab show?
Open a form and click **Analytics**. You'll see two things:
1. A chart of **daily submissions over the last 30 days**, with spam shown separately from real submissions.
1. **Submissions by country**, so you can see where your entries come from.
It counts submissions, not page views. Formbold only sees the form when someone sends it, so there's no conversion rate here. If you need views and conversions, use your site analytics tool alongside it.
## How can I use the daily chart?
The chart is most useful for spotting changes. A few patterns to watch for:
A sudden drop to zero usually means something broke on your site, like a changed field name or a deploy that removed the form. Send a test from the [Test Form tab](/docs/test-form) to rule out Formbold, then check your site.
A spike in spam means a bot found the form. Turn on **Custom reCAPTCHA** in **Spam & Security** if you haven't already. See [Spam Protection](/docs/spam-protection).
A steady rise after a campaign is the good kind. Compare it with the campaign dates.
## What is "submissions by country" good for?
It shows where your entries come from. It's a quick sanity check: if you sell only in Germany and most submissions come from somewhere you don't serve, look at the Spam folder and your spam settings.
## Where are the totals for all my forms?
On **Overview**, the first page in the sidebar. It shows total submissions, spam blocked, total forms and active forms across your workspace, plus a 30-day chart. See [Your Dashboard at a Glance](/docs/dashboard-overview).
---
# Spam Protection
Source: https://formbold.com/docs/spam-protection
Section: Docs / Spam Protection
Block spam with Formbold's Basic Spam Filter, Automatic reCAPTCHA or your own Google reCAPTCHA keys. All three live in Spam & Security.
## Where are the spam settings?
Open your form, click **Settings** and scroll to **Spam & Security**. You'll find three toggles there: **Basic Spam Filter**, **Automatic reCAPTCHA** and **Custom reCAPTCHA**.

Anything Formbold flags as spam goes to the **Spam** folder in **Submissions**, not your Inbox. Check that folder once in a while, especially in the first week after you change these settings.
## What does the Basic Spam Filter do?
It checks each submission on our servers, so your visitors don't see a puzzle or a checkbox. Turn it on for every form. There's no downside, and it catches a lot of the obvious junk.
## When should I use Automatic reCAPTCHA?
When you want a reCAPTCHA check without setting anything up. Formbold adds the check itself, with no keys and no code changes. It's designed for standard HTML forms that post straight to your endpoint.
If your form submits with `fetch()` or Ajax, use Custom reCAPTCHA instead.
## How do I set up Custom reCAPTCHA with my own keys?
The dashboard marks Custom reCAPTCHA as **recommended**, and it's the option I'd pick for any form that gets real traffic. It works with plain HTML posts and with `fetch()` requests.

1. Go to the Google reCAPTCHA Admin Console at https://www.google.com/recaptcha/admin.
1. Register your site. Choose **reCAPTCHA v2**, the "I'm not a robot" checkbox, and add your domain. Add `localhost` too if you test locally.
1. Copy the **Site Key** and the **Secret Key**.
1. In Formbold, open **Settings > Spam & Security** and turn on **Custom reCAPTCHA**.
1. Paste the **Site Key** and **Secret Key** into their fields and save.
1. Add the reCAPTCHA script and widget to your form, as below.
The **Learn How** link next to the toggle brings you back to these steps.
```html
```
The Site Key goes in your HTML. The Secret Key goes only into Formbold. Never put the Secret Key in your page.
## Why are real submissions failing after I added reCAPTCHA?
Usually the domain isn't registered in the Google console. Add every domain that serves the form, including `www` and staging. The other common cause is pasting the keys the wrong way round, so check that the Site Key and Secret Key are in the right fields.
## Can I limit which websites can use my form?
Yes. **Allowed Domains**, just below Spam & Security, rejects submissions that come from sites you haven't listed. It's on **Starter and higher**. See [Form Settings](/docs/form-settings).
## Do webhooks receive spam?
Not by default. The Webhook dialog has a separate **Receive submissions marked as spam** checkbox, off unless you turn it on. See [Webhooks](/docs/webhooks).
---
# Connecting Apps & Integrations
Source: https://formbold.com/docs/connecting-apps
Section: Docs / Connecting Apps
Send FormBold submissions to chat, spreadsheets, CRMs, automation tools and your own server.
## Which apps can FormBold send submissions to?
Eleven apps are on your form's **Integrations** tab, and email is built in on top of that. Email works on every plan. The apps need **Starter, Premium or Business**.

| App | Category | Good for |
| --- | --- | --- |
| Email | Built in | Notifications, set up in Settings > Email Configuration |
| Slack | Chat | Posting each submission to a team channel |
| Google Sheets | Spreadsheet | A new row per submission |
| Notion | Productivity | A new page in a Notion database |
| Telegram | Chat | Alerts on your phone or in a group |
| Discord | Chat | Messages in a server channel |
| Mailchimp | Email marketing | Adding subscribers to an audience |
| Zendesk | Support | Turning messages into tickets |
| Make | Automation | Multi-step scenarios |
| Zapier | Automation | Thousands of other apps |
| HubSpot | CRM | Creating contacts from leads |
| Webhook | Developer | Sending JSON to your own URL |
## How do I connect an app?
Open your form, click the **Integrations** tab, find the app and click **Connect**. Follow the steps in the dialog that opens. Each app has its own guide in the sidebar.
Then send one submission from the **Test Form** tab and check that it arrived. Five seconds of testing beats finding out a week later that the Slack channel was wrong.
## What happens when a submission comes in?
FormBold runs your spam and domain checks first. If the submission passes, it's saved and sent to every app you've connected on that form. Apps work independently, so if one is down the others still get the submission.
Credentials for connected apps are stored encrypted.
## Should I use a webhook or a built-in app?
Use the built-in app if one exists for your tool. It's less work and nothing to host. Use a [webhook](/docs/webhooks) when the data needs to go into your own system, or through Make or Zapier when you need several steps.
---
# Slack Integration
Source: https://formbold.com/docs/slack
Section: Docs / Connecting Apps
Receive instant notifications in any public or private Slack channel when visitors submit your form.
## Overview
Keep your entire sales, support, or engineering team updated in real time by piping incoming submissions into a dedicated Slack channel.

## Requirements
- An active Formbold form.
- A Slack workspace with administrative or integration permissions to install apps.
- A designated public or private Slack channel (e.g., #contact-leads or #support-tickets).
## Step-by-Step Connection Guide
1. In your Formbold dashboard, navigate to the 'Integrations' tab.
1. Locate 'Slack' in the integrations catalog and click 'Connect'.
1. You will be redirected to the secure Slack authorization screen.
1. Select your Slack workspace in the top right corner.
1. Choose the destination channel where submission alerts should be posted.
1. Click 'Allow' to grant Formbold permission to send messages.
1. You will be returned to Formbold with Slack marked as 'Connected'.
## Testing Your Slack Integration
Submit a test message through your frontend form. Within seconds, a formatted message card displaying all submitted fields will appear in your chosen Slack channel!
## Managing or Disconnecting
To change the target channel or disconnect Slack, click the 'Configure' or 'Disconnect' button on the Slack card in your Integrations tab.
---
# Google Sheets Integration
Source: https://formbold.com/docs/google-sheets
Section: Docs / Connecting Apps
Add every form submission as a new row in Google Sheets, so you can track, filter and report on it.
## Overview
Google Sheets is one of the most flexible tools for analyzing leads, sharing data with non-technical stakeholders, and building lightweight tracking dashboards. Formbold's direct Google Sheets connector synchronizes submissions in real-time.

## Key Benefits
- Automatic Column Matching: Formbold automatically creates column headers matching your form input names.
- Timestamp Tracking: Every entry is timestamped automatically.
- Instant Sync: New submissions appear in your spreadsheet in under 2 seconds.
## Step-by-Step Connection Guide
1. Open your Formbold form and navigate to the 'Integrations' tab.
1. Click on the 'Google Sheets' card.
1. Click 'Sign in with Google' and grant Formbold permission to access Google Drive and Sheets.
1. Choose whether to create a new spreadsheet automatically or select an existing Google Sheet.
1. Click 'Save and Activate'.
## Testing and Verifying
Open the linked Google Sheet in your browser and submit a test entry from your form. A new row will populate immediately containing all the submitted form field values.
---
# Notion Integration
Source: https://formbold.com/docs/notion
Section: Docs / Connecting Apps
Sync web form responses directly into a structured Notion database with customized property mapping.
## Overview
Send contact requests, job applications, bug reports and survey responses straight into a Notion database.
## Step 1: Prepare Your Notion Database
Before connecting, create a database in Notion with properties that correspond to your form fields. For example:
- Title property: 'Name' or 'Submission'
- Email property: 'Email Address'
- Text property: 'Message' or 'Details'
- Phone property: 'Phone Number' (optional)
- Created Date property: 'Submitted At'
## Step 2: Authorize Notion in Formbold
1. In Formbold, go to the 'Integrations' tab and click 'Notion'.

1. Click 'Connect to Notion' to launch the OAuth authorization screen.
1. Select the Notion workspace and grant access to the specific page containing your database.
1. Click 'Allow Access'.
## Step 3: Configure the Field Mapper
1. Select your target database from the dropdown menu.
1. Use the Field Mapper to link each Formbold form input (e.g. name, email, message) to its matching Notion property.
1. Click 'Save Integration'.
## Testing Your Integration
Submit a test entry on your frontend form and verify that a new page row appears instantly in your Notion database.
---
# Telegram Integration
Source: https://formbold.com/docs/telegram
Section: Docs / Connecting Apps
Receive instant push alerts for every form submission directly in your Telegram chat or group.
## Overview
Telegram is a good choice for mobile notifications. Formbold's Telegram bot sends the full submission to your personal chat or a group.
## Step-by-Step Setup Guide
1. In your Formbold form, open the 'Integrations' tab and click 'Telegram'.

1. Open the Formbold Telegram Bot link displayed on screen or start a conversation with the bot in Telegram.
1. Send the '/start' command or follow the on-screen pairing code prompt to authenticate your chat ID.
1. If connecting a Telegram Group, add the Formbold bot to your group and grant permission to post messages.
1. Return to Formbold and click 'Verify Connection'.
## Testing the Alert
Submit a test form on your website. Your Telegram app will ping immediately with a formatted message summary of the submission!
---
# Discord Integration
Source: https://formbold.com/docs/discord
Section: Docs / Connecting Apps
Send clean, rich embed notifications into your Discord server channels using webhooks.
## Overview
Keep your developer or community team in the loop by sending styled rich embeds to any Discord channel whenever a visitor submits a contact form, bug report, or feedback survey.

## Step 1: Create a Discord Webhook
1. Open Discord, navigate to your server, and click the server dropdown menu > 'Server Settings'.
1. Select 'Integrations' from the left sidebar and click 'Webhooks'.
1. Click 'New Webhook' or 'Create Webhook'.
1. Name the bot (e.g., 'Formbold Bot') and choose the destination channel (e.g., #form-leads).
1. Click 'Copy Webhook URL'.
## Step 2: Connect Discord in Formbold
1. In Formbold, navigate to your form's 'Integrations' tab.
1. Locate 'Discord' and click 'Configure'.
1. Paste your copied Discord Webhook URL into the field.
1. Click 'Save & Connect'.
## Step 3: Test the Integration
Submit a test form from your website. You will see an embed appear in your Discord channel displaying the submission fields and timestamp.
---
# Mailchimp Integration
Source: https://formbold.com/docs/mailchimp
Section: Docs / Connecting Apps
Automatically sync newsletter subscribers and lead capture forms with your Mailchimp audiences.
## Overview
Grow your email list from your website forms. Connect Formbold to Mailchimp and each new submission is added to your audience.
## Step 1: Generate a Mailchimp API Key
1. Log in to your Mailchimp account.
1. Click your profile avatar in the bottom left corner > Account & billing > Extras > API keys.
1. Click 'Create A Key', give it a label (e.g. 'Formbold'), and copy the key.
## Step 2: Configure Audience Fields & Merge Tags
In Mailchimp, go to Audience > Audience dashboard > Manage Audience > Settings > Audience fields and *|MERGE|* tags. Verify that your fields match your form inputs (e.g., EMAIL, FNAME, LNAME).
## Step 3: Connect and Map in Formbold
1. In Formbold, go to Integrations > click 'Mailchimp'.

1. Paste your Mailchimp API Key.
1. Select the target Audience list from the dropdown.
1. Map your form fields to the appropriate Mailchimp merge tags.
1. Click 'Save'.
## Testing
Submit an email through your form and check your Mailchimp Audience dashboard to confirm the subscriber was added with 'Subscribed' status.
---
# Zendesk Integration
Source: https://formbold.com/docs/zendesk
Section: Docs / Connecting Apps
Automatically convert form inquiries into Zendesk support tickets with requester email mapping.
## Overview
Turn contact requests, sales inquiries and feedback forms into Zendesk tickets for your support team.
## Step 1: Locate Your Zendesk Subdomain
Look at your Zendesk browser URL: https://your-subdomain.zendesk.com. The subdomain is the prefix (your-subdomain).
## Step 2: Create a Zendesk API Token
1. In Zendesk Admin Center, go to Apps and integrations > APIs > Zendesk API.
1. Enable 'Token Access' toggle.
1. Click 'Add API token', enter description 'Formbold Integration', and copy the generated token.
## Step 3: Connect in Formbold
1. In Formbold, go to Integrations > click 'Zendesk'.

1. Enter your Zendesk Subdomain, your Primary Admin Email, and the API Token.
1. Map the form inputs to Ticket Subject, Requester Email, and Ticket Description.
1. Click 'Save & Connect'.
## Testing
Submit a test message on your frontend form. Check your Zendesk ticketing queue; a new ticket will be opened with the submitter set as the requester!
---
# Make Integration
Source: https://formbold.com/docs/make
Section: Docs / Connecting Apps
Send submissions to Make.com scenarios to trigger multi-app workflows and advanced data processing.
## Overview
Make (formerly Integromat) is a visual automation platform. Send Formbold submissions to Make to branch data, format text, call APIs and connect to thousands of apps.
## Step 1: Create a Custom Webhook in Make
1. Log in to Make.com and click 'Create a new scenario'.
1. Click the '+' circle, search for 'Webhooks', and choose 'Custom Webhook'.
1. Click 'Create a webhook', name it 'Formbold Submissions', and click 'Save'.
1. Make will generate a unique webhook URL (e.g. https://hook.eu2.make.com/xxxx). Click 'Copy address to clipboard'.
## Step 2: Add Webhook to Formbold
1. In Formbold, navigate to Integrations > click 'Make'.

1. Paste the copied Make Webhook URL.
1. Click 'Save & Activate'.
## Step 3: Determine Data Structure
1. In Make, click 'Redetermine data structure' on the webhook module.
1. Submit a test form on your website.
1. Make will display 'Successfully determined'. You can now chain Google Sheets, Airtable, CRM modules, or email services to your scenario!
---
# Zapier Integration
Source: https://formbold.com/docs/zapier
Section: Docs / Connecting Apps
Connect Formbold to thousands of popular apps on Zapier using Catch Hook webhook triggers.
## Overview
Zapier connects Formbold to thousands of apps without code. Create calendar events, add Trello cards, post to Discord or update a CRM from each submission.
## Step 1: Create a Zap with Webhook Trigger
1. Log in to your Zapier dashboard and click 'Create Zap'.
1. In the Trigger step, search for 'Webhooks by Zapier'.
1. Select 'Catch Hook' as the Trigger Event and click 'Continue'.
1. Zapier will generate your unique Webhook URL. Click 'Copy'.
## Step 2: Connect Zapier in Formbold
1. In Formbold, go to your form's 'Integrations' tab and select 'Zapier'.

1. Paste the copied Webhook URL into the field.
1. Click 'Save & Connect'.
## Step 3: Test Trigger and Add Actions
1. Submit a test entry through your website form.
1. In Zapier, click 'Test trigger'. Zapier will confirm that the test submission was received.
1. Add your desired Action app (e.g. Google Sheets, HubSpot, Slack, Airtable).
1. Map the form fields into the action app and turn your Zap on!
---
# HubSpot CRM Integration
Source: https://formbold.com/docs/hubspot
Section: Docs / Connecting Apps
Sync new contacts and form leads directly into your HubSpot CRM sales pipeline.
## Overview
Ensure your sales and marketing teams never miss an inbound lead. Formbold's direct HubSpot integration creates or updates CRM contacts whenever someone fills out your contact, demo request, or consultation form.
## Step 1: Authorize HubSpot Connection
1. In Formbold, open your form and select the 'Integrations' tab.

1. Click on the 'HubSpot' card.
1. Click 'Connect App' to open the secure HubSpot OAuth authorization page.
1. Log in to your HubSpot account and select the target hub/portal.
1. Grant Formbold permissions to create contacts.
## Step 2: Map Contact Fields
1. Return to Formbold where HubSpot is now marked as authenticated.
1. Map your form fields to HubSpot contact properties: First Name, Last Name, Email Address, Phone Number, and Company.
1. Click 'Save Configuration'.
## Testing
Submit a test form from your website. Open your HubSpot Contacts dashboard to verify the new contact has been created with all mapped fields!
---
# Code Examples & Framework Guides
Source: https://formbold.com/docs/code-examples
Section: Docs / Code Examples
Copy-ready examples for HTML, React, Next.js, Vue, Angular and plain JavaScript (Ajax), plus a prompt you can paste into your AI coding tool.
## Which framework examples are here?
Every Formbold form has one endpoint, and it works with any stack. Pick your framework below, copy the example and swap in your own form ID from the **Form Setup** tab. The same snippets, with your endpoint already filled in, are on that tab too.

## 1. Plain HTML Form
The simplest way to use Formbold. Requires no JavaScript libraries or build tools:
```html
```
## 2. Plain HTML with File Upload
To accept file attachments, add enctype='multipart/form-data' to the form element:
```html
```
## 3. Plain HTML with Google reCAPTCHA
Embed the reCAPTCHA v2 widget to filter automated bots on your static form:
```html
```
## 4. Vanilla JavaScript (AJAX / Fetch API)
Submit form data asynchronously without triggering a full page reload, including loading indicators and double-submission guards:
```javascript
const form = document.querySelector("#contact-form");
const submitBtn = document.querySelector("#submit-btn");
const statusMsg = document.querySelector("#status-message");
form.addEventListener("submit", async (e) => {
e.preventDefault();
submitBtn.disabled = true;
submitBtn.textContent = "Sending...";
const formData = new FormData(form);
try {
const response = await fetch("https://formbold.com/s/YOUR_FORM_ID", {
method: "POST",
body: formData,
headers: {
Accept: "application/json",
},
});
if (response.ok) {
statusMsg.textContent = "Thank you! Your message has been sent.";
statusMsg.className = "success";
form.reset();
} else {
const errorData = await response.json();
statusMsg.textContent = errorData.message || "Failed to send message.";
statusMsg.className = "error";
}
} catch (error) {
statusMsg.textContent = "Network error. Please try again.";
statusMsg.className = "error";
} finally {
submitBtn.disabled = false;
submitBtn.textContent = "Submit";
}
});
```
## 5. React (Custom Component)
A clean, functional React component with state management and user feedback:
```tsx
import React, { useState } from "react";
export default function ContactForm() {
const [status, setStatus] = useState({ state: "idle", message: "" });
const handleSubmit = async (e) => {
e.preventDefault();
setStatus({ state: "loading", message: "" });
const formData = new FormData(e.target);
try {
const res = await fetch("https://formbold.com/s/YOUR_FORM_ID", {
method: "POST",
body: formData,
headers: { Accept: "application/json" },
});
if (res.ok) {
setStatus({ state: "success", message: "Form submitted successfully!" });
e.target.reset();
} else {
setStatus({ state: "error", message: "Submission failed. Please try again." });
}
} catch (err) {
setStatus({ state: "error", message: "An unexpected error occurred." });
}
};
return (
);
}
```
## 6. Next.js (App Router Client Component)
Next.js 14 / 15 / 16 compatible App Router component with client-side form submission:
```tsx
"use client";
import { useState } from "react";
export default function NextContactForm() {
const [submitting, setSubmitting] = useState(false);
const [submitted, setSubmitted] = useState(false);
const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setSubmitting(true);
const formData = new FormData(e.currentTarget);
try {
const response = await fetch("https://formbold.com/s/YOUR_FORM_ID", {
method: "POST",
body: formData,
headers: { Accept: "application/json" },
});
if (response.ok) {
setSubmitted(true);
}
} finally {
setSubmitting(false);
}
};
if (submitted) {
return (
Thank you!
Your message has been received. We will get back to you shortly.
);
}
return (
);
}
```
## 7. Vue 3 (Composition API)
Vue 3 single-file component using
```
## 8. Angular (standalone component)
An Angular standalone component that posts with `HttpClient`. Add `provideHttpClient()` to your app config if you haven't already.
```typescript
import { Component, inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
@Component({
selector: "app-contact-form",
standalone: true,
template: `
`,
})
export class ContactFormComponent {
private http = inject(HttpClient);
sending = false;
status = "";
onSubmit(event: Event) {
event.preventDefault();
const form = event.target as HTMLFormElement;
this.sending = true;
this.http
.post("https://formbold.com/s/YOUR_FORM_ID", new FormData(form), {
headers: { Accept: "application/json" },
})
.subscribe({
next: () => {
this.status = "Thanks! Your message has been sent.";
form.reset();
this.sending = false;
},
error: () => {
this.status = "Something went wrong. Please try again.";
this.sending = false;
},
});
}
}
```
If you use `*ngIf`, import `NgIf` (or `CommonModule`) in the component's `imports`. On Angular 17 and newer you can use `@if` instead.
## 9. Prompt for AI coding tools
The quickest route is the **Built with an AI Tool?** section on your form's **Form Setup** tab. Pick Lovable, Bolt.new, v0.dev, Cursor, ChatGPT or General, and Formbold writes the prompt with your endpoint already in it.
If you'd rather write your own, this one works in Cursor, ChatGPT, Claude or v0:
```markdown
I have created a Formbold form with the endpoint:
https://formbold.com/s/YOUR_FORM_ID
Please help me integrate this form into my web application.
My stack is: [Insert stack, e.g. Next.js 15 App Router with Tailwind CSS]
Requirements:
1. Submit the form to the Formbold endpoint using POST.
2. Provide form fields for Name, Email, and Message with proper validation.
3. Use the Fetch API with an 'Accept: application/json' header, so the page doesn't reload.
4. Disable the submit button and show a spinner while submitting.
5. Display accessible success and error state alerts.
6. Reset the form fields after successful submission.
```
Read what the AI gives back before you ship it. Check the URL is your endpoint and every field still has a `name`.
---
# Webhooks Guide
Source: https://formbold.com/docs/webhooks
Section: Docs / Webhooks
Send each form submission to your own server as a JSON POST request. Webhooks are available on the Starter, Premium and Business plans.
## How do Formbold webhooks work?
When someone submits your form, Formbold sends an HTTP POST with the submission as JSON to a URL you choose. It happens in real time, so your server doesn't have to poll for new entries.
Use a webhook when you want submissions in your own database, a serverless function or an internal tool. For Slack, Google Sheets or a CRM, the built-in integrations are less work.
## How do I add a webhook to my form?
Webhooks live with the other apps on your form's Integrations tab.

1. Open your form and click the **Integrations** tab.
1. Find **Webhook** and click **Connect**.
1. Paste your endpoint. It must be an **HTTPS** URL, like `https://example.com/api/formbold-webhook`.
1. Choose which submissions to receive (see the next section) and save.
Send a test from the **Test Form** tab right away and check that your server logged it.
## Which submissions does the webhook receive?
The dialog has two checkboxes:
- **Receive verified submissions (passed spam check)** is on by default. These arrive with `"is_spam": false`.
- **Receive submissions marked as spam** is off by default. Turn it on if you want to review or score spam yourself. These arrive with `"is_spam": true`.
If you turn both on, always check `is_spam` in your handler before you act on a submission. Otherwise a bot can end up in your CRM.
## What does the webhook payload look like?
Every request has `Content-Type: application/json` and a body like this:
```json
{
"event": "submission.created",
"form_id": "YOUR_FORM_ID",
"submission_id": "sub_8f2b1a9c3d4e",
"created_at": "2026-09-10T12:00:00.000Z",
"data": {
"name": "Sarah Connor",
"email": "sarah@example.com",
"message": "Interested in your enterprise solution.",
"budget": "$10,000+"
},
"files": [],
"is_spam": false
}
```
The keys inside `data` are your form's field names, so a field with `name="budget"` arrives as `data.budget`. Rename a field on your site and the key changes too, which is a common way to break a webhook without noticing.
## How do I handle the webhook in Node.js with Express?
A minimal Express endpoint looks like this:
```javascript
import express from "express";
const app = express();
app.use(express.json());
app.post("/api/formbold-webhook", (req, res) => {
const { event, form_id, submission_id, data, is_spam } = req.body;
// Only accept forms you expect
if (form_id !== process.env.FORMBOLD_FORM_ID) {
return res.status(404).end();
}
// Answer quickly, then do the slow work
res.status(200).json({ received: true });
if (is_spam) return;
console.log(`[Formbold] ${event} ${submission_id}:`, data.name, data.email);
// Save to your database, create a ticket, and so on
});
app.listen(3000, () => console.log("Webhook server running on port 3000"));
```
Respond with a `2xx` status as soon as you've read the body. If you need to call other APIs or send emails, do it after responding, or push the job to a queue.
## How do I secure my webhook endpoint?
Formbold doesn't sign webhook requests, so your endpoint should do its own checks. These are simple and cover most cases:
- **Use HTTPS only.** Formbold requires it, and it keeps the payload private in transit.
- **Make the URL hard to guess.** Put a long random value in the path or query string, like `/api/formbold-webhook?key=8f3c...`, and reject any request where it doesn't match a value in your environment variables.
- **Check `form_id`.** Accept only the form IDs you expect and ignore the rest.
- **Treat `data` as untrusted input.** It's whatever a visitor typed. Validate and escape it before you store it or show it in an admin page.
- **Respond fast.** Return `2xx` first and do heavy work in the background, so a slow downstream service doesn't hold up the request.
Your API token isn't used for webhooks. Don't put it in the webhook URL.
## How do I test webhooks locally with ngrok?
Your laptop isn't reachable from the internet, so use a tunnel:
1. Start your local server, for example on port 3000.
1. Run `ngrok http 3000`.
1. Copy the HTTPS forwarding URL and add your path, like `https://abc123.ngrok-free.app/api/formbold-webhook`.
1. Paste that URL into the Webhook dialog on the **Integrations** tab.
1. Submit your form and watch the payload arrive in your terminal.
Free ngrok URLs change each time you restart ngrok, so update the webhook URL when they do. If you just want to see the raw request first, a free URL from webhook.site works too.
---
# REST API Reference
Source: https://formbold.com/docs/api-reference
Section: Docs / API Reference
Fetch a form's submissions with the Formbold REST API. Available on every plan, including Free.
## What can I do with the Formbold REST API?
Right now it does one job: fetch the submissions for any of your forms. That's enough to copy new leads into a CRM or keep a backup in your own database.
| Item | Value |
| --- | --- |
| Base URL | https://api.formbold.com/api |
| Format | JSON responses |
| Protocol | HTTPS only |
| Plans | Every plan, including Free |
## How do I authenticate?
Every request needs an API token in the `Authorization` header. Create one in **API & MCP > API Tokens**. See [API Tokens](/docs/api-tokens).
```bash
Authorization: Bearer YOUR_API_TOKEN
```
## Which endpoints are available?
| Method | Endpoint | What it does |
| --- | --- | --- |
| GET | /api/forms/:formId/submissions | Lists a form's submissions |
## How do I fetch a form's submissions?
`GET https://api.formbold.com/api/forms/:formId/submissions` returns the submissions for one form. Replace `:formId` with your form's ID, the last part of its endpoint. If your endpoint is `https://formbold.com/s/3Vy25`, the ID is `3Vy25`.
First, turn on **HTTP API** for that form. Open the form, go to **Settings**, and switch on **HTTP API** in the **Email Configuration** card ("Allow programmatic access to this form's submissions"). Without it, the request fails with a `400`.
### Parameters
| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| formId (path) | string | Yes | Your form's ID, the last part of its endpoint (for example 3Vy25) |
### Request examples
cURL:
```bash
curl -X GET "https://api.formbold.com/api/forms/3Vy25/submissions" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
```
JavaScript or Node.js:
```javascript
const formId = "3Vy25";
const response = await fetch(
`https://api.formbold.com/api/forms/${formId}/submissions`,
{
headers: {
Authorization: `Bearer ${process.env.FORMBOLD_API_TOKEN}`,
Accept: "application/json",
},
}
);
if (!response.ok) {
throw new Error(`Formbold API error: ${response.status}`);
}
const data = await response.json();
console.log(data);
```
Python:
```python
import os
import requests
form_id = "3Vy25"
url = f"https://api.formbold.com/api/forms/{form_id}/submissions"
headers = {
"Authorization": f"Bearer {os.environ['FORMBOLD_API_TOKEN']}",
"Accept": "application/json",
}
response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
```
Run these on a server. A token in front-end code is a token anyone can copy.
### Success response (200 OK)
A successful call returns 200 OK with the form's submissions. Each submission is an object like the one below, shown here in a list with a single entry:
```json
[
{
"country": null,
"created_at": "2025-06-16T04:42:51",
"domain": null,
"fields": {
"name": "John Doe",
"email": "john.doe@example.com",
"message": "This is a test message."
},
"files": null,
"form_id": "12891",
"id": "525393",
"is_read": true,
"is_spam": false,
"is_starred": false,
"updated_at": "2025-06-16T04:42:51"
}
]
```
The list may sit inside a wrapper object with other top-level keys. Log the raw JSON from your first call and check its shape before you write the parsing code.
### What's in a submission object?
| Field | Type | Description |
| --- | --- | --- |
| id | string | The submission's unique ID. |
| form_id | string | Internal ID of the form that received the submission. It's not the ID in your endpoint URL. |
| fields | object | What the visitor entered, keyed by your form's input names, for example name, email and message. |
| files | null or file data | Files uploaded with the submission. null when there are none. |
| country | string or null | The visitor's country, when it's known. Otherwise null. |
| domain | string or null | The site the form was submitted from, when it's known. Otherwise null. |
| is_read | boolean | Whether the submission is marked as read. |
| is_spam | boolean | Whether the submission was flagged as spam. |
| is_starred | boolean | Whether the submission is starred. |
| created_at | string (ISO 8601) | When the submission arrived, for example 2025-06-16T04:42:51. There's no timezone suffix. |
| updated_at | string (ISO 8601) | When the submission was last updated. Same format as created_at. |
## What do the error codes mean?
| HTTP code | Status | What to check |
| --- | --- | --- |
| 400 | Bad Request | The form ID isn't valid, or HTTP API is turned off for this form. Check the ID, then switch HTTP API on in Settings > Email Configuration. |
| 401 | Unauthorized | The token is missing or revoked, or the header doesn't start with "Bearer ". |
Errors come back as JSON with a message. A request without a valid token gets this:
```json
{
"success": false,
"data": null,
"message": "Unauthorized"
}
```
## Can AI assistants use the API?
Yes, through the [Formbold MCP server](/docs/mcp-server). It has its own URL and takes the same API token:
| Item | Value |
| --- | --- |
| MCP URL | https://api.formbold.com/mcp |
| Authentication | Authorization: Bearer YOUR_API_TOKEN |
| Tools | list_workspaces, create_form, update_form, get_form, list_forms, test_submission, get_submissions |
With it, Cursor, VS Code, Claude Code, Claude Desktop or Codex can create forms, change form settings, send test submissions and check form stats from a chat. Setup for each client, the arguments for each tool and example prompts are in [MCP Server](/docs/mcp-server).
### What does the MCP server return without a valid token?
HTTP 401, with a message that tells you which problem it is, repeated in a details object. No token:
```json
{
"success": false,
"data": null,
"message": "Authentication token is required for Formbold MCP access.",
"details": {
"message": "Authentication token is required for Formbold MCP access.",
"error": "Unauthorized",
"statusCode": 401
}
}
```
An invalid or expired token:
```json
{
"success": false,
"data": null,
"message": "Invalid or expired Formbold MCP API token.",
"details": {
"message": "Invalid or expired Formbold MCP API token.",
"error": "Unauthorized",
"statusCode": 401
}
}
```
---
# Using Formbold with AI
Source: https://formbold.com/docs/ai
Section: Docs / AI
Let your AI assistant create forms, test them and read submissions, connect forms that AI app builders generate, and call the API from your own agents.
If you're new here, Formbold is the backend your form posts to. It stores each submission, filters spam and passes entries to email, Slack, Google Sheets, webhooks and 8 other apps. This page is about the AI side of that: assistants that talk to your forms, app builders that write them, and agents that read submissions.
## What can I do with Formbold and AI?
All of it works on every plan, Free included.
1. **Talk to Formbold from your AI assistant.** Connect Cursor, VS Code Copilot, Claude Code, Claude Desktop or Codex to the Formbold MCP server. Then ask it to create a form, change its settings, send a test submission or compare how your forms are doing.
1. **Connect forms that AI app builders write.** Lovable, Bolt.new, v0, Cursor and ChatGPT will all generate a contact form that has nowhere to send. Point it at Formbold, and let the dashboard write the prompt for you.
1. **Call the REST API from your own agents.** An agent or a plain script can fetch submissions over HTTPS with an API token.
## How do I let Claude or Cursor work with my forms?
Create an API token under **API & MCP > API Tokens**, then add the Formbold MCP server, `https://api.formbold.com/mcp`, to your client with the token as a Bearer header. For most clients that's one config block.
Once it's connected, try "Send a test submission with name and email to form to verify it works" or "Compare all my forms. Which form has the highest volume, and which one gets the most spam?" Setup for each client, the seven tools and more prompts are in [MCP Server](/docs/mcp-server).
## How do I connect a form an AI app builder made?
Open your form's **Form Setup** tab and scroll to **Built with an AI Tool?**. Pick your tool, copy the prompt, and paste it into the builder's chat. It already contains your endpoint.
Read what the builder wrote before you launch. The usual mistakes are a missing `name` attribute or a placeholder URL. The checklist is in [Connect AI-Built Forms](/docs/ai-form-builders).
## Can my own agent read submissions over the API?
Yes. Send the token as `Authorization: Bearer YOUR_API_TOKEN` to `https://api.formbold.com/api`. `GET /api/forms/:formId/submissions` returns a form's entries once HTTP API is on for that form.
Give each agent its own token. When you shut an agent down, revoke its token and nothing else is affected. Endpoints and responses are in the [REST API reference](/docs/api-reference).
## Is it safe to give an AI assistant access?
It's as safe as the token you give it. The token can read every submission in your account, so treat it like a password. Keep it out of Git, use one per tool, and revoke it on the **API Tokens** tab the moment you're unsure.
Submissions are personal data from real people. Before you paste them into a chat, think about whether that tool is somewhere your privacy policy says the data may go.
---
# Formbold MCP Server
Source: https://formbold.com/docs/mcp-server
Section: Docs / AI
Connect Cursor, VS Code, Claude Code, Claude Desktop or Codex to Formbold so your AI assistant can create forms, change their settings, send test submissions and check how each form is doing. Works on every plan, Free included.
## What is the Formbold MCP server?
It's a Model Context Protocol server that lets AI agents work with your Formbold account. From a chat in Cursor, VS Code, Claude Code, Claude Desktop or Codex, an agent can **create forms**, **manage form settings**, **test the submission pipeline** and **check form analytics**. You ask in plain language and the agent calls the right tool.
| Item | Value |
| --- | --- |
| Base URL | https://api.formbold.com/mcp |
| Authentication | Authorization: Bearer |
| Clients | Cursor, VS Code, Claude Code, Claude Desktop, Codex |
| Plans | Every plan, including Free |
## How do I authenticate?
Send your API token as a Bearer token in the `Authorization` header on every request:
```bash
Authorization: Bearer
```
To get a token, open **API & MCP** in the dashboard sidebar, go to the **API Tokens** tab and create one. Give it a name you'll recognise later, like "Cursor on work laptop", and copy it straight away. More in [API Tokens](/docs/api-tokens).
> Never commit tokens to Git. Make one token per tool or per machine, so if a laptop goes missing you revoke that one token and everything else keeps working.
## Which tools does the server give my assistant?
Seven. Your assistant picks the right one from what you ask, so you rarely need to name them.
| Tool | Purpose | Key arguments |
| --- | --- | --- |
| list_workspaces | List accessible workspaces and verified emails | None |
| create_form | Create a new form endpoint | name, workspace_id, notification_email |
| update_form | Update settings, redirect URL, spam filter, domains | form_id, name, redirect_url, allowed_domains, is_active |
| get_form | Get form details, endpoint URL, and stats | form_id |
| list_forms | List forms with submission counts | workspace_id, all_workspaces, limit |
| test_submission | Send a test payload to verify ingestion | form_id, data (key-value map) |
| get_submissions | View recent submissions (PII masked by default) | form_id, limit, include_content |
`get_submissions` masks personal data by default. The `include_content` argument controls whether the content of each entry comes back, so only turn it on when your assistant needs to read what people wrote.
## What happens if the token is missing or wrong?
The server answers with HTTP status **401 Unauthorized** and a JSON body. A request with no token gets this:
```json
{
"success": false,
"data": null,
"message": "Authentication token is required for Formbold MCP access.",
"details": {
"message": "Authentication token is required for Formbold MCP access.",
"error": "Unauthorized",
"statusCode": 401
}
}
```
An invalid, expired or revoked token gets this:
```json
{
"success": false,
"data": null,
"message": "Invalid or expired Formbold MCP API token.",
"details": {
"message": "Invalid or expired Formbold MCP API token.",
"error": "Unauthorized",
"statusCode": 401
}
}
```
Either way, check that the header reads `Authorization: Bearer`, then a space, then your token, and that the token is still listed on the API Tokens tab.
## How do I connect Cursor?
Add Formbold to `.cursor/mcp.json` in your project, or to `~/.cursor/mcp.json` to use it in every project:
```json
{
"mcpServers": {
"formbold": {
"url": "https://api.formbold.com/mcp",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
Save the file. Formbold should show up in Cursor's MCP list with a green dot. If it stays red, restart Cursor once.
## How do I connect VS Code?
Add Formbold to `.vscode/mcp.json` in your workspace. VS Code uses `servers` as the top-level key, not `mcpServers`, and a remote server needs `"type": "http"`:
```json
{
"servers": {
"formbold": {
"type": "http",
"url": "https://api.formbold.com/mcp",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
Open Copilot Chat in Agent mode and check the tools list. You should see the Formbold tools there.
## How do I connect Claude Code?
Run one command in your terminal:
```bash
claude mcp add --transport http formbold https://api.formbold.com/mcp --header "Authorization: Bearer "
```
Or add it to `.mcp.json` in your project root. Keep `"type": "http"`, because Claude Code skips a server that has a `url` but no `type`:
```json
{
"mcpServers": {
"formbold": {
"type": "http",
"url": "https://api.formbold.com/mcp",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
Then run `claude mcp list`. Formbold should be listed as connected.
## How do I connect Claude Desktop?
Claude Desktop reaches the Formbold server through `mcp-remote`, a small bridge that runs with Node.js. Open **Settings > Developer > Edit Config**. That opens `claude_desktop_config.json`. Add Formbold under `mcpServers`:
```json
{
"mcpServers": {
"formbold": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.formbold.com/mcp",
"--header",
"Authorization:${AUTH_HEADER}"
],
"env": {
"AUTH_HEADER": "Bearer "
}
}
}
}
```
Save the file, then quit Claude Desktop completely and open it again. Closing the window isn't enough.
## How do I connect Codex?
Add Formbold to `~/.codex/config.toml`. The Codex CLI, the IDE extension and the Codex app all read this file:
```toml
[mcp_servers.formbold]
url = "https://api.formbold.com/mcp"
http_headers = { "Authorization" = "Bearer " }
```
To keep the token out of the file, replace the `http_headers` line with `bearer_token_env_var = "FORMBOLD_API_TOKEN"` and set that variable in your shell. Start a new Codex session so it picks up the change.
## What can I ask in the AI chat?
Name the form and say what you want back. Each of these prompts maps to one or two tools:
| Prompt | Tools | What happens |
| --- | --- | --- |
| "Show my Formbold workspaces and verified notification emails." | list_workspaces | Lists your workspaces and the notification emails you can send to. |
| "Create a new Formbold contact form for my workspace." | create_form | Creates the form and returns its endpoint URL. |
| "Enable spam protection and restrict allowed domains to mysite.com on form ." | update_form | Changes the form's spam and domain settings. |
| "Send a test submission with name and email to form to verify it works." | test_submission | Sends a test entry so you can confirm the form receives data. |
| "Analyze the performance and recent feedback for form ." | get_form + get_submissions | The AI summarizes submission volume, calculates inbox vs. spam ratios, and reviews recent entries. |
| "Compare all my forms. Which form has the highest volume, and which one gets the most spam?" | list_forms | The AI compares forms, ranks traffic, and highlights high-performing vs. dormant endpoints. |
| "Compare recent submissions between form and form and highlight key differences." | get_submissions | The AI fetches entries from both forms and compares customer feedback themes. |
Replace `` with your form's ID, the last part of its endpoint. For `https://formbold.com/s/3Vy25`, the ID is `3Vy25`.
When your assistant creates a form, check it on **All Forms** before you ship. It takes ten seconds and catches a wrong name early.
## How do I test the connection with cURL?
Send an `initialize` request with your token:
```bash
curl -i -X POST https://api.formbold.com/mcp \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl-test","version":"1.0"}},"id":1}'
```
A missing or wrong token returns one of the 401 errors above. If the response includes an `Mcp-Session-Id` header, send that header with your later requests, such as `tools/list`.
## How do I keep my token safe?
Treat the token like a password. It can read every submission your account can read.
- Never commit tokens to Git. If `.cursor/mcp.json`, `.vscode/mcp.json`, `.mcp.json` or `config.toml` holds a real token and lives in a repo, add it to `.gitignore`.
- Use a separate token for each client, so you can revoke one without breaking the others.
- If you think a token leaked, revoke it on the API Tokens tab and create a new one. Revoking takes effect straight away.
## Why isn't the Formbold MCP server connecting?
Most problems come down to a few things.
A 401 means the header is missing or the token is wrong. Check there's a space after Bearer and that you copied the whole token.
In VS Code and Claude Code, check that the entry has `"type": "http"`. Claude Code skips a `url` entry without it.
If Claude Desktop says "npx: command not found", Node.js isn't installed or the app can't see it. Install Node.js 18 or newer and restart Claude Desktop.
On Windows, some clients split arguments on spaces, which breaks an `Authorization: Bearer ...` argument. The Claude Desktop example passes the header through `AUTH_HEADER` to avoid that.
For calling Formbold from your own code instead, see the [REST API reference](/docs/api-reference).
---
# Connect Forms Built with Lovable, Bolt.new, v0, Cursor or ChatGPT
Source: https://formbold.com/docs/ai-form-builders
Section: Docs / AI
AI app builders write good-looking forms that don't send anywhere. This guide shows you how to point them at Formbold and check the result before launch.
## Why doesn't the form my AI tool built send anything?
Because most AI builders write the front end only. The form looks right, the button clicks, and the data goes nowhere, or to a placeholder URL. Formbold gives that form a real endpoint that stores submissions and emails them to you.
You'll need a Formbold form first. Create one in **All Forms** with **Create New Form**.
## How do I use the "Built with an AI Tool?" prompt builder?
1. Open your form and go to the **Form Setup** tab.
1. Scroll to **Built with an AI Tool?**.
1. Pick your tool: **Lovable**, **Bolt.new**, **v0.dev**, **Cursor**, **ChatGPT** or **General**.
1. Copy the prompt. It already contains your endpoint, `https://formbold.com/s/YOUR_FORM_ID`.
The prompt asks the AI to submit your form with `fetch` and a JSON body, show a success message, and handle errors. You don't need to edit it.
## Where do I paste the prompt?
Into the same chat where you built the app. In Lovable, Bolt.new and v0 that's the project chat. In Cursor, open the chat with the form's file in context. In ChatGPT, paste the prompt together with your form's code.
If your app has more than one form, say which one, for example "Use this for the contact form on the Contact page only."
## What should I check after the AI updates my form?
Read the code it changed. It takes two minutes and saves an afternoon. Check these:
- **The URL** is your real endpoint, not `YOUR_FORM_ID` or an example domain.
- **The method** is `POST`.
- **Every field has a `name`**, or a matching key in the JSON body. That name is the label you'll see in Submissions and in the email.
- **The headers.** A `fetch` call with a JSON body should send `Content-Type: application/json` and `Accept: application/json`.
Then publish a preview and send a real submission. Check that it shows up in **Submissions** and that the email reaches your inbox, not spam.
## Should I set a redirect or spam protection?
Probably both. A `fetch` form shows its own thank-you message, so a redirect is optional. If the AI wrote a plain HTML form instead, set a **Redirect URL** in **Settings > Email Configuration** so visitors land on your own thank-you page. Redirects are on Starter and higher.
For spam, turn on **Basic Spam Filter** in **Settings > Spam & Security** straight away. Forms on AI-built sites often go live fast and get found by bots just as fast. Details in [Spam Protection](/docs/spam-protection).
## What mistakes do AI tools make most often?
These four cover nearly every "it doesn't work" message we see:
1. **A missing `name` attribute.** The input renders, but its value never reaches Formbold. Add `name="email"` and so on to each field.
1. **`GET` instead of `POST`.** The form puts your data in the URL and Formbold ignores it. Change the method to `POST`.
1. **The wrong endpoint.** A placeholder, an old form ID, or a made-up API URL. Copy the endpoint from **Form Setup** again.
1. **No `Content-Type` or `Accept` header on `fetch`.** Without them the request may be sent as plain text, or your code can't read the response. Add both as `application/json`.
If it still fails, open the browser's Network tab, submit the form, and look at the request to `formbold.com/s/...`. The status code and response usually point straight at the problem.
## Can the AI create the Formbold form for me too?
Yes, if your coding tool supports MCP. Connect the [Formbold MCP server](/docs/mcp-server) and ask "Create a Formbold contact form called Website Contact and wire it into the contact page." The `create_form` tool makes the form and hands the endpoint back to the AI. Then ask "Send a test submission with name and email to the new form to verify it works." The `test_submission` tool confirms that entries arrive before you launch.
## Is there a step-by-step guide for my tool?
Yes, for the three we're asked about most: [Lovable](/docs/lovable-contact-form), [Bolt.new](/docs/bolt-contact-form) and [v0](/docs/v0-contact-form). Each one has a prompt you can paste, the code you should end up with and the mistake that tool makes most often.
---
# Make your Lovable contact form send
Source: https://formbold.com/docs/lovable-contact-form
Section: Docs / AI
Lovable builds a good-looking contact form in seconds, but by default nothing receives it. Here's the prompt that connects it to Formbold, and what to check afterwards.
## Why doesn't my Lovable contact form send anything?
Because Lovable writes the front end and stops there. The submit button often just shows a toast, or Lovable offers to build a Supabase table and an Edge Function for it. For a contact form you don't need either. Point the form at a Formbold endpoint and each message is stored, filtered for spam and emailed to you.
## What do I need before I start?
A Formbold form. Open **All Forms**, click **Create New Form** and name it, for example "Lovable site contact". Then copy the endpoint from the **Form Setup** tab. It looks like `https://formbold.com/s/YOUR_FORM_ID`.
The Free plan is enough for this: 250 submissions a month across 10 forms.
## What prompt do I paste into Lovable?
The quickest route is **Form Setup > Built with an AI Tool?**. Pick **Lovable** and the dashboard writes the prompt with your endpoint already in it. If you'd rather write it yourself, this one works:
```text
Update the existing contact form so it really sends.
On submit, POST the form fields to https://formbold.com/s/YOUR_FORM_ID
using fetch with a JSON body and these headers:
Content-Type: application/json and Accept: application/json.
Give every input a name attribute (name, email, message).
Disable the button while sending. Show a success message only when
response.ok is true, and show an error message otherwise.
Do not add Supabase, Lovable Cloud, an Edge Function, an email API
or any other backend for this form. Keep the current design.
```
The last line matters. Without it, Lovable may decide the form needs a database and start building one.
## What should the code look like afterwards?
Open the component Lovable changed, usually something like `src/components/ContactForm.tsx`. The submit handler should look roughly like this:
```tsx
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
const form = e.currentTarget;
setSending(true);
const data = Object.fromEntries(new FormData(form));
const res = await fetch("https://formbold.com/s/YOUR_FORM_ID", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
});
setSending(false);
if (res.ok) {
form.reset();
setStatus("Thanks, we'll get back to you soon.");
} else {
setStatus("Something went wrong. Please try again.");
}
}
```
If you see a `setTimeout` that fakes a delay, a `console.log` instead of a request, or a call to `supabase.from(...)`, the prompt didn't take. Paste it again and name the file.
## How do I test it before I publish?
Send one message from the Lovable preview. Within a few seconds it should appear in your form's **Submissions** tab, and the email should follow. If it doesn't:
- Open the browser's Network tab, submit again and click the request to `formbold.com/s/...`. A 4xx status usually means a wrong form ID.
- Check the inputs. Generated components sometimes keep values in state and leave `name` off the input. With this handler, a field without a name never reaches Formbold.
- Publish, then test once more on the live URL. That's the one your visitors use.
> Do the live test from your phone. It's the fastest way to catch a form that works on desktop and breaks on mobile.
## Should I turn on spam protection straight away?
Yes. Lovable sites tend to go live quickly, and bots find contact forms just as quickly. In **Settings > Spam & Security**, turn on **Basic Spam Filter**. This form submits with fetch, so if you want a captcha as well, use **Custom reCAPTCHA** with your own v2 keys. The steps are in [Spam Protection](/docs/spam-protection).
## Can Lovable send the submissions to Slack or Google Sheets?
Formbold can, on Starter and higher. Connect the app on the form's **Integrations** tab and leave Lovable out of it. Your Lovable code stays the same.
---
# Connect a Bolt.new contact form to Formbold
Source: https://formbold.com/docs/bolt-contact-form
Section: Docs / AI
Bolt.new can scaffold a whole site in one prompt, contact form included. This guide wires that form to Formbold so the messages actually reach you.
## Why doesn't my Bolt.new contact form work?
Bolt builds the form and leaves the sending to you. In some projects the button does nothing at all. In others it logs to the console, or Bolt suggests adding Supabase. A Formbold endpoint is shorter: one URL, and every message is stored and emailed to you.
## What do I need first?
A Formbold form and its endpoint. Click **Create New Form** in **All Forms**, open the **Form Setup** tab and copy the URL, which looks like `https://formbold.com/s/YOUR_FORM_ID`. Free covers 250 submissions a month, which is plenty for a new site.
## What prompt should I give Bolt?
Use **Form Setup > Built with an AI Tool?** and pick **Bolt.new** to get a prompt with your endpoint filled in. Or paste this into the Bolt chat:
```text
Wire up the contact form so it sends real submissions.
POST the fields to https://formbold.com/s/YOUR_FORM_ID with fetch,
a JSON body, and the headers Content-Type: application/json
and Accept: application/json.
Every input needs a name attribute: name, email, message.
Show a success state only if response.ok is true, an error otherwise,
and disable the button while sending.
Don't add Supabase, a serverless function, Netlify Forms attributes
or any other backend. Only change the contact form component.
```
## Why mention Netlify Forms?
Bolt deploys to Netlify, and it sometimes adds `data-netlify="true"` or a hidden `form-name` input to forms it builds. Those tell Netlify to capture the form itself. You don't want two services fighting over one form, so ask Bolt to leave them out, and delete them if they're already there.
## How do I check what Bolt changed?
Open the form component in Bolt's code view, usually under `src/components/`. Look for three things:
1. A `fetch` call to your exact endpoint, not `YOUR_FORM_ID` or an example domain.
1. `method: "POST"` and both headers.
1. A `name` on every input, or matching keys in the JSON body.
If Bolt wrapped the request in a `try` block that shows success no matter what, change it so success depends on `response.ok`. Otherwise visitors see "Thanks!" even when nothing was sent.
## How do I test it?
Submit the form in Bolt's preview first. The preview runs in your browser, so the request goes straight to Formbold and the entry appears in **Submissions** within seconds. Then deploy and test once more on the live URL.
If nothing arrives, open the Network tab and look at the request to `formbold.com/s/...`. The status code and response body usually tell you what's wrong.
## What should I set up in Formbold after that?
Two things. Turn on **Basic Spam Filter** in **Settings > Spam & Security**, since new sites get bot traffic within days. And if you'd like messages in Slack, Telegram or Google Sheets, connect them on the **Integrations** tab. Integrations are on Starter and higher, and they don't need any change to your Bolt project.
---
# Wire a v0 contact form to Formbold
Source: https://formbold.com/docs/v0-contact-form
Section: Docs / AI
v0 generates Next.js components with shadcn/ui, and its contact forms usually end in a mock Server Action. Swap that for your Formbold endpoint and the form starts sending.
## Why doesn't my v0 contact form send?
v0 tends to finish a contact form with a placeholder. You'll often see a Server Action marked `"use server"` that waits a second and returns success, or a handler that only logs the data. Nothing is sent anywhere. Replace that with a request to your Formbold endpoint and every submission is stored and emailed to you.
## What do I need from Formbold?
A Formbold form. Click **Create New Form** in **All Forms**, then copy the endpoint from **Form Setup**: `https://formbold.com/s/YOUR_FORM_ID`. The Free plan gives you 250 submissions a month and 10 forms.
## What prompt do I give v0?
Pick **v0.dev** under **Form Setup > Built with an AI Tool?** for a prompt with your endpoint in it, or use this:
```text
Replace the mock submit logic in the contact form.
Make the form a client component ("use client") and on submit
POST the fields to https://formbold.com/s/YOUR_FORM_ID with fetch,
a JSON body, and the headers Content-Type: application/json and
Accept: application/json.
Keep name attributes on every input: name, email, message.
Show the success state only when response.ok is true and an error
state otherwise. Remove the fake delay and any unused Server Action.
Keep the existing shadcn/ui design.
```
## Can I keep a Server Action instead?
Yes, if you prefer. A Server Action can call the same endpoint with `fetch`, and the request is identical. The client version is simpler, though, and it keeps working if you later move the site to a static export. Pick one and delete the other, so there's no half-used action left behind.
## What should the component look like?
Roughly this, inside the file v0 generated:
```tsx
"use client";
import { useState } from "react";
export function ContactForm() {
const [status, setStatus] = useState<"idle" | "sending" | "sent" | "error">("idle");
async function onSubmit(e: React.FormEvent) {
e.preventDefault();
setStatus("sending");
const form = e.currentTarget;
const res = await fetch("https://formbold.com/s/YOUR_FORM_ID", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(Object.fromEntries(new FormData(form))),
});
if (res.ok) form.reset();
setStatus(res.ok ? "sent" : "error");
}
// keep v0's JSX, and make sure each and