Keep sales pitches out of your demo form
Agencies, SEO outreach and dev shops fill your demo form with pitches. Captchas and word lists can't stop a person who types. Doorman reads every submission, forwards only people who want what you sell, and shows the sentence that gave each pitch away. Bots, fake sign-ups and card testers stay out too. Paste one prompt into your coding agent and it's live.
Works with Claude Code, Codex, Cursor and any agent. Free for 1,000 checks a month, no card. What your agent does · Try it on a message
Transcript
- “Your contact form.” A message is typed into a contact form: “We do SEO and link building. Quick 15 min chat?” and sent.
- “It gets pitched all day.” The message arrives at Doorman’s door.
- “Doorman reads every one.” It is marked Dropped, sales pitch, with the giveaway sentence underlined. A real demo request is marked Delivered.
- “In 162 ms. Pitches, bots and fraud out.” Card fraud, abuse, fake sign-ups and bot spam are kept out; real customers go to the inbox.
- “Tell your coding agent.” A Copy prompt button for Claude Code, Codex, Cursor and OpenCode is clicked.
- “It sets everything up.” The agent is asked to protect the contact form with Doorman, reads withdoorman.com/llms.txt, changes the form’s action URL and confirms a test submission was delivered.
- “Enterprise-grade. Priced for everyone.” Free: 1,000 checks a month. Pro: $12 a month. No captcha, no sales call.
- Doorman. Spam protection for every website.
- 0.992precision on 1,956 human-labelled comments
- ~100 msto judge a submission
- 0real customers dropped in our labelled tests
- MITopen-source core, on GitHub
Works with the form you already have
- HTML
- React
- Next.js
- Webflow
- Framer
- Squarespace
- WordPress
Let your coding agent set it up
Claude Code, Codex and Cursor can set Doorman up without a browser: there's a setup guide written for agents, a signup API and a remote MCP server. Your agent asks you one question.
Add Doorman spam protection to this project's forms. Follow /llms.txt. Ask me which email should receive real submissions.
claude mcp add --transport http doorman /mcp
Step-by-step guides:
› Add Doorman spam protection to this project's forms. Follow /llms.txt ✓ Read the setup guide ✓ Found 1 form: index.html "Get a quote" ? Which email should get real submissions? owner@brightpath.co ✓ Created account and form f_qXGl50Gng1 ✓ Pointed the form at Doorman, added d.js ✓ Saved DOORMAN_KEY to .env (gitignored) ✓ Test: café asking about payroll → delivered 0.86 ✓ Test: SEO pitch → dropped 0.01
Why captchas and word filters stopped working
AI agents fill in forms in real browsers, and language models write spam that sounds human. Captchas and word filters were built for the old kind of bot. Doorman's models read each submission the way a person would, and judge what it's actually asking for.
Old defences check the wrong thing
A captcha tests whether a mouse moved. A word list looks for known phrases. An AI agent passes the first and rephrases around the second.
Reads meaning, not keywords
Doorman understands what a message is asking for and whether that fits what you sell. A polished AI-written pitch stays out; a blunt, misspelled real enquiry gets through.
Cutting-edge models, small bills
Small specialised models answer narrow questions in about 100 ms for a fraction of a cent each. That's why every plan, free included, gets the same protection.
Our mission: a safer internet for everyone, in the AI age.
One service for spam, fraud and abuse
Every form on your site gets a different kind of junk. Doorman knows what each form is for and what you sell, and judges every submission against that.
Contact and demo forms
Agency and SEO pitches, partnership spam, template outreach and bots, kept out of your sales inbox.
leadSign-ups and waitlists
Fake and throwaway accounts, disposable emails and scripted bulk sign-ups, stopped before they cost you.
signupCheckout
Card testing and stolen-card patterns, judged from signals you already have, before you capture payment.
checkoutComments and reviews
Promotion, link spam, harassment, hate and threats, removed before anyone else reads them.
commentOr do it yourself in two minutes
Keep your form, your fields and your thank-you page. Doorman sits between the submit button and your inbox.
Point your form at Doorman
Swap the action URL, or call one endpoint from your backend. Field names are detected automatically.
Our models score every submission
In about 100 ms, before the thank-you page loads: is this a real customer, a pitch, a bot, a fake account or fraud?
Real ones reach you
Forwarded to email, Slack or a signed webhook. The rest wait in your inbox, one click from rescue.
- <form action="/contact.php" method="POST">
+ <form action="/f/f_yourForm" method="POST">
<input name="email" type="email" required>
<textarea name="message"></textarea>
<button>Send</button>
</form>
<!-- optional: timing and honeypot signals -->
+ <script src="/d.js" defer></script>async function onSubmit(event) {
event.preventDefault();
await fetch("/f/f_yourForm", {
method: "POST",
body: new FormData(event.currentTarget),
headers: { Accept: "application/json" },
});
setSent(true); // everyone gets the same {"ok": true}
}curl /v1/check \
-H "Authorization: Bearer $DOORMAN_KEY" \
-H "Content-Type: application/json" \
-d '{"form": "f_yourForm", "email": "jess@brightline.co",
"message": "We send 200 invoices a month. Demo?"}'
# {"route": "deliver", "action": "deliver", "p_real": 0.97, ...}import { Doorman } from "@withdoorman/client";
const doorman = new Doorman(process.env.DOORMAN_KEY);
const r = await doorman.check({ form: "f_yourForm", email, message });
if (r.action === "drop") return thanks(); // the bot learns nothing
await saveLead({ email, message, held: r.action === "hold" });import os
import requests
try:
r = requests.post(
"/v1/check",
headers={"Authorization": f"Bearer {os.environ['DOORMAN_KEY']}"},
json={"form": "f_yourForm", "email": email, "message": message},
timeout=5,
).json()
except requests.RequestException:
r = {"action": "hold"} # never lose a lead
if r["action"] != "drop":
save_lead(email, message, held=r["action"] == "hold")require "net/http"
require "json"
res = Net::HTTP.post(
URI("/v1/check"),
{ form: "f_yourForm", email: email, message: message }.to_json,
"Authorization" => "Bearer #{ENV.fetch("DOORMAN_KEY")}",
"Content-Type" => "application/json"
)
r = JSON.parse(res.body)
save_lead(email, message, held: r["action"] == "hold") unless r["action"] == "drop"# {:req, "~> 0.5"}
{:ok, %{body: r}} =
Req.post("/v1/check",
auth: {:bearer, System.fetch_env!("DOORMAN_KEY")},
json: %{form: "f_yourForm", email: email, message: message},
receive_timeout: 5_000
)
unless r["action"] == "drop" do
save_lead(email, message, held: r["action"] == "hold")
endEvery drop comes with a reason
Rules and word lists match keywords. Doorman's models read the whole submission against what you sell, and show you the exact sentence that gave it away.
- Catches what captchas can't. A person paid to paste agency pitches passes any challenge. Doorman judges what they wrote.
- Rescue in one click. Nothing is deleted. If a real lead gets dropped, deliver it from the inbox and it's forwarded instantly.
- Unsure means held, not dropped. Borderline messages are forwarded with a flag so a person decides.

Try it on a real message
Paste something from your inbox, or pick an example. We'll judge it as if you sell invoicing software (or, for the comment, run a developer blog). Nothing is stored.
Enterprise-grade accuracy, at a price anyone can pay
Measured on labelled test sets and a public benchmark, judged live. Methodology below.
Test set: 104 invented but labelled submissions to a fictional invoicing company's demo form and checkout (13/13 agency pitches, 11/11 bots and 16/16 fraudulent orders dropped; 45 of 52 genuine delivered straight through, 7 held for a person), judged live. Benchmark: the UCI YouTube Spam Collection, recall 0.980, 8.8% held for a person. Sign-ups and comments: a small hand-labelled set of 25 (fake accounts, abuse, spam and genuine ones), none on the wrong side. Questions were not tuned to any of these sets.
The protection big platforms have, without the enterprise contract
Until now you could buy machine-learning fraud screening after a sales call and an integration project, or settle for captchas and word lists that miss anything a person typed.
| Question | Doorman | Enterprise fraud platform | Captcha | Honeypot + word list |
|---|---|---|---|---|
| Price | Free, then from $12 a month | Usually an annual contract | Free or low | Free |
| Getting started | One URL, or one sentence to your agent | Sales call and integration | A script and a server check | A few lines of code |
| What real visitors see | Nothing | Nothing | A challenge, sometimes | Nothing |
| AI agents and AI-written spam | Reads what they say | Depends on the product | Often passes | Rephrased around |
| Human-written pitches and abuse | Reads intent | Depends on the product | Passes | Only known phrases |
| Card testing and fake accounts | Yes | Yes | Slows it | No |
| Why it blocked something | The exact sentence | A risk score | No | No |
Built so nothing real gets lost
Fails open
Over quota, an outage or a flood from one address: submissions are held for a person, never silently dropped.
Watch mode
Judges everything but delivers what it would have dropped, tagged. Check its calls on your real traffic first.
Email, Slack, webhooks
Signed JSON webhooks, retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours.
Allow and block lists
Emails or domains that are always delivered, or always dropped, without a check.
Checkout screening
Card testing and stolen-card patterns, judged from signals you already have: attempts, countries, account age.
Bots learn nothing
Delivered or dropped, the sender gets the same redirect and the same response. There's nothing to probe.
Simple pricing
Every plan gets the same models. You pay for volume, not for a sales process. Test submissions are free.
Free
For side projects and trying it on a real form.
- 1,000 checks a month
- 300 email forwards; Slack and webhooks unlimited
- API, MCP and agent setup
- 30 days of history
Pro
For a business site with a busy contact or demo form.
- 25,000 checks a month
- 5,000 email forwards
- Everything in Free
- 180 days of history
Business
For agencies and sites with many forms.
- 250,000 checks a month
- 20,000 email forwards
- Everything in Pro
- 365 days of history
Go over your plan and nothing is dropped: submissions are held and forwarded with a flag until the month resets. Confirm your email to unlock the free plan; forwarding addresses other than your own confirm once.
Frequently asked questions
What about AI agents and AI-written spam?
They're why Doorman exists. An AI agent can fill in a form in a real browser and pass a captcha, and a language model can rephrase a pitch until no word list matches it. Doorman doesn't look for bot behaviour or banned words: its models read what the submission says and whether it's a genuine enquiry for what you sell, the way a person reading it would. A well-written AI pitch is still a pitch.
How is this different from a captcha?
A captcha asks every visitor to prove they are human. Doorman lets everyone submit and then reads what they sent. A person paid to paste agency pitches passes any captcha; Doorman judges the message itself against what your business sells.
What does my agent need?
Nothing special. Any coding agent that can make an HTTP request can follow /llms.txt: it creates your account with POST /v1/signup (no browser), puts the form URL or an API call into your project, stores the key in .env and runs two free test submissions. Agents that support MCP can add the remote server at /mcp instead. The only thing it asks you is which email should receive real submissions.
What happens if Doorman is down?
If judging fails or times out, the submission is held: stored, forwarded to you flagged as held, and queued for review. The same happens over your monthly quota. Doorman never drops something it did not judge. If you call the API from your backend, the @withdoorman/client package treats a network error or timeout as hold. If the hosted form endpoint itself cannot be reached, the visitor's form post fails the way it would with any form backend.
Is my data used for training?
No. Submissions are sent to our machine-learning provider only to be judged. We don't use them for training. We keep submissions for 30 days on Free, 180 days on Pro and 365 days on Business, then delete them automatically.
What data do you store?
For each submission: the fields your form sent, the sender's IP address, the decision (route, probability it is real, reason and evidence sentence) and where it was forwarded. File uploads are ignored. Passwords are hashed; API keys and session tokens are stored only as hashes.
Does a bot find out it was dropped?
No. Every submission gets the same response whatever the verdict: the same redirect to your thank-you page, or the same {"ok": true} for JSON requests.
Can I start without trusting it?
Yes. Watch mode judges everything but delivers what it would have dropped, tagged, so you can check its calls on real traffic. Thresholds are per form, and allow and block lists let you always deliver or always drop specific emails or domains.
Does it work in other languages?
Doorman's models judge meaning, not keywords, and Doorman's questions say that a short, badly written or non-English message is still genuine. Our published benchmark is English, so if most of your traffic is in another language, start in watch mode.
What kinds of forms does it handle?
Contact, demo and quote forms; sign-ups and waitlists; public comments; and checkouts, where card testing and stolen cards are judged from signals you pass such as payment attempts and card versus IP country.
How can protection this good cost so little?
Doorman uses small, specialised models that answer narrow questions (is this a real customer, is this a pitch, is this card testing) in milliseconds. Each check costs a tiny fraction of a cent to run, so we can give every plan the same models, including the free one, and charge for volume instead of for a sales process.
Can I run Doorman myself?
You can build your own: the core idea is open source at github.com/0x4rch/doorman (MIT), and we’re happy to help. You’d bring your own model key, hosting, email and monitoring, and keep the questions tuned. Hosted Doorman is live in minutes, managed for you, and the model costs are in one clear price. What hosted adds.
What happens if I go over my plan?
Nothing is dropped. Submissions over the monthly quota are held and forwarded unjudged, flagged as held, until the month resets or you upgrade. You get an email at 80% and at 100%.
Protection that used to need a fraud team
One prompt to your coding agent and every form is covered. Free for your first 1,000 checks every month.
