Skip to content
FFormhook
Back to blog

Blog

Contact form not working? Here's how to actually find out why

· 5 min read

"My contact form isn't working" usually means one of about six things, and guessing at which one wastes more time than checking. The fix is to work through causes in order of likelihood, starting with the one thing that tells you the most in the least time: what actually happened to the request when it left the browser.

1. Check what the request actually did

Open the page, open devtools, switch to the Network tab, and submit the form yourself. Two things break here constantly:

  • The action URL is wrong - a typo'd API key, a URL copied from an old form and never updated, or (embarrassingly common) still pointing at localhost from local development and never switched to production.
  • The request goes out but comes back with an error status. You don't need to know the exact meaning of every code - a 4xx or 5xx response is enough to tell you the problem is on the receiving end, not in your HTML.

If the request never fires at all, or fires against a domain that clearly isn't your form backend, that's the bug, found in under a minute - before you go looking anywhere else.

2. Confirm it's actually sending as POST

A <form> without an explicit method="POST" defaults to GET, which appends your fields to the URL as a query string instead of sending a body - a form backend endpoint generally won't accept that as a real submission. Check the tag itself first.

If the form submits through JavaScript instead of a native browser POST, the more common failure is a handler that calls e.preventDefault() to stop the default navigation and then never actually sends anything - a broken fetch call, a typo in the endpoint inside the handler, or a silent early return. preventDefault() without a working request behind it is indistinguishable from a dead form to the visitor: the page just... does nothing.

3. Rule out the console, not just the network

For any fetch-based submission, open the Console tab alongside Network. A CORS error, a blocked mixed-content request (submitting to http:// from an https:// page), or an uncaught exception inside the submit handler will all stop the request cold - and none of them produce a visible error for the visitor. They just look like silence, which is exactly what a broken form looks like from the outside.

4. Check where the notification actually landed

If the request in step 1 came back with a success status, the submission reached the backend - the remaining question is just where the alert went. Check spam and promotions folders first; it's the single most common reason a "missing" notification isn't actually missing. If you're sending from a custom verified domain rather than the default sender, a misconfigured SPF or DKIM record will get emails silently filtered or bounced by the receiving mail server, which looks identical to "nothing was sent" from your side.

5. Consider a silent rejection - rate limits and a broken honeypot

Legitimate submissions occasionally get treated as suspicious. Testing repeatedly and quickly from the same IP while debugging is exactly the pattern rate limiting exists to catch, and can trip it on you without any hostile intent involved. Wait a few minutes and try again before assuming something's broken.

A subtler and genuinely common bug: the honeypot field. Most spam protection includes a hidden field real visitors never see or fill in - if a bot fills it, the submission is silently discarded. A CSS regression (a class renamed, a stylesheet failing to load, a layout change that un-hides the wrong element) can make that field visible to real users, who then either get confused by an extra field or - worse - have it auto-filled by a password manager, which trips the same filter that was meant for bots. If submissions started failing right after a redesign or a CSS change, this is worth checking first.

Check the dashboard, not just your inbox

The meta-lesson across all of the above: "did I get an email" is not the same question as "did the submission arrive," and conflating them is what makes this kind of bug take days to find instead of minutes. With Formhook, every submission that actually reaches the backend shows up in the dashboard regardless of whether the notification email was delivered - so the first useful check, before any of the steps above, is simply logging in and looking. If it's there, the problem is on the notification side (steps 4-5). If it isn't, the problem is upstream, before the request even reached the backend (steps 1-3).

Worth doing regularly, not just when something breaks: the pre-launch testing checklist covers the fifteen-minute pass that catches most of this before a real visitor ever hits it. And if you're evaluating a form backend and want to know what a working one looks like end to end, the docs and pricing page cover setup and the free tier.

Ship a working form in one line

EU-hosted, submissions kept forever, push notifications on every tier.

Start free

No credit card · read the docs

Keep reading