Quick Answer
You can add a working contact form to a website without writing a backend by using a form service: create a form in RSFlowHub Forms, paste one script tag where the form should appear, and every message lands in your dashboard and inbox with spam already filtered. If you want your own design, send the fields as JSON to the Forms API with a public form token instead.
A contact form looks like a ten-minute job until you list what sits behind the button: a server endpoint, validation, spam defence, email delivery, a place to store messages, and a privacy story. For a static site, a landing page or a small business site, that is a lot of machinery for "let people write to me". This guide explains the options, then shows how to do it with RSFlowHub Forms in two ways: the one-line embed and the JSON API.
What a contact form really involves
The visible part is a few inputs and a button. Behind it, a production-ready form needs:
- An endpoint that accepts the submission and answers quickly.
- Server-side validation, because browser checks are trivial to bypass.
- Spam defence, since any public form is found by bots within days.
- Storage, so a failed email never loses an enquiry.
- Notification to you, without flooding your inbox when a bot attacks.
- Privacy handling: consent, retention and the ability to delete one person's data.
Your options compared
| Approach | Good for | Trade-off |
|---|---|---|
| Build your own backend | Apps that already have a server and want full control. | You maintain validation, spam rules, storage and email forever. |
mailto: link | Almost nothing. | Depends on the visitor's mail app, exposes your address to scrapers, no record of messages. |
| Form service (embed) | Static sites, landing pages, WordPress, Shopify. | Messages live with the provider; check export and deletion options. |
| Form service (API) | Sites with their own design system or framework forms. | You write the markup and handle error display yourself. |
Option A: The one-line embed
- Open Dashboard → Forms and choose Contact form.
- In the Settings tab choose the fields, the button and thank-you texts, colours, an optional redirect and where email alerts go.
- In the Install tab copy the code. It never changes, even when you edit the form later.
- Paste it where the form should appear.
<section>
<h2>Contact us</h2>
<script src="https://rsflowhub.com/widget/v1/rsflowhub-forms.js"
data-form-token="fm_sec_YOUR_FORM_TOKEN"
async></script>
</section>
The form is drawn right where the tag is. To place it inside a specific element, add data-target="#contact-box" and an empty <div id="contact-box"></div>.
The embed runs in its own isolated box, so your site's CSS cannot break it and its CSS does not touch your site. It works under a strict Content-Security-Policy, has a label on every field, announces errors to screen readers and fires a browser event, rsflowhub:form-submitted, that you can use for analytics.
Option B: Your own design with the API
If your site has its own components, build the form yourself and send the fields as JSON. The token goes in the X-Form-Token header, and fields are keyed by the Field ID you defined in the form settings:
curl -X POST https://rsflowhub.com/api/v1/forms/submissions \
-H "X-Form-Token: fm_sec_YOUR_FORM_TOKEN" \
-H "Content-Type: application/json" \
-d '{"fields": {"name": "Ann", "email": "ann@example.com", "message": "Hello!"}, "consent": true}'
A successful answer returns a short reference such as FRM-AB12CD that you can show in your thank-you message. Invalid input returns status 422 with the problem fields, and an exhausted plan limit returns 429 with text that is safe to show to visitors.
The API accepts an optional
website field that acts as a trap for bots. If you render it in your own form, hide it with CSS and leave it empty for real visitors. If it arrives filled in, the request is accepted but nothing is stored, so bots learn nothing from the response.
How spam is handled
Every plan includes a hidden trap field, a speed limit per visitor, and rules that look for many links, throwaway email domains, repeated text and common spam phrases. Messages that look like spam are kept in a Spam filter for review, so nothing is silently lost, and they never count against your monthly limit. Paid plans can add an AI second opinion on messages the rules did not flag; if the AI is unavailable, real messages still arrive and the helper simply pauses.
Visitors and bots see the same "accepted" answer either way. That matters: if a form answers differently for spam, bots learn what to change.
Reading and answering messages
- Filter by Inbox, New, Read, Replied and Spam, and search across messages.
- Reply by email, mark a message as replied, or rescue a real message from the Spam filter with Not spam.
- Export everything as CSV. Cells starting with
=,+,-or@are neutralised so a visitor cannot plant a spreadsheet formula. - You also get an email for each new message, capped at 10 per hour per form so an attack cannot flood your inbox. Everything stays in the dashboard regardless.
On the Pro plan you can also turn on AI tags (a label such as sales or support, plus a mood), a suggested reply you review and send yourself, an automatic "we received your message" email, and a signed webhook that sends each new message to your own system.
Consent and data retention
A contact form collects personal data, so decide the rules up front. In the form settings you can require a privacy checkbox (the time of acceptance is stored with the message), choose how long messages are kept (30, 90, 180 or 365 days, or until you delete them) and let older ones be deleted every night. For access and erasure requests, enter the person's email under Privacy requests to download or delete everything stored about them. Visitor IP addresses are never stored, only a keyed hash used to spot abuse, and text sent to your inbox is cleaned of HTML. You remain responsible for your own privacy policy; these are the tools to support it.
Limits and plans
Forms has its own plans, separate from RSFlowHub API credits: you do not need an API plan to use it. The Free plan needs no payment and no phone verification, and each plan has a monthly message limit and a limit on stored newsletter subscribers. When a limit is reached, visitors see a short generic message and you get emails at 80% and 100%. Messages already received stay in your dashboard. Current prices and limits are on the pricing page.
Common mistakes to avoid
- Putting a private API key in page code. Only the public
fm_sec_form token belongs in the browser, and it can only send messages to that one form. - Leaving Allowed websites empty. Listing your domains stops other sites from using your token. Note that with a list set, server-side requests with no Origin are refused, so call the API from the browser.
- Forgetting the email alert address. Check the alert settings and your spam folder before you assume nobody is writing to you.
- Never opening the Spam filter. Look at it for the first few weeks and rescue anything real.
- Skipping the privacy checkbox when you serve visitors who expect one.
Building your own spam layer on top? See Detect Contact Form Spam with Python. Want a newsletter box next to it? Read Newsletter Double Opt-In Explained. Prefer live chat to a form? See How to Add an AI Chatbot to Any Website.
Add a Contact Form in Five Minutes
Start on the Free plan: one script tag or the JSON API, spam filtering included. Details are in the Forms docs.
See RSFlowHub Forms →Key Takeaways
- A contact form needs an endpoint, validation, spam defence, storage, notification and privacy handling, which a form service provides.
- Use the one-line embed for speed, or the JSON API with a public form token for your own design.
- Spam is kept for review and never counts against your limit, so nothing real is silently lost.
- Return the same answer for spam and real messages so bots learn nothing.
- Restrict the form token to your own websites and keep private API keys out of page code.
- Choose consent, retention and deletion settings before you collect real data.
No comments yet
Be the first to share your thoughts on this article!