Restrict to your domain

Accept submissions only from your own site so nobody can reuse your access key elsewhere, and what this can and cannot stop.

An access key sits in your page's HTML, where anyone can copy it. That is safe, because the key can only send submissions to you, but someone could paste it into their own form and fill your inbox. An allowed-domains list makes the endpoint refuse submissions that a browser sends from any other site.

Turn it on#

  1. Sign in to the dashboard with the email address your key belongs to. Keys you created earlier appear there automatically.
  2. Open the form and find "Allowed domains" under Delivery and access.
  3. Enter your domains, one per line (for example example.com and example-shop.net), and save.

Paste a full URL if that is easier: https://www.example.com/contact is stored as www.example.com. The scheme, path and port are dropped.

Leave the list empty to accept submissions from anywhere, which is the default.

How matching works#

A bare domain covers the domain itself and every subdomain:

Allowed entryAcceptedRefused
example.comexample.com, www.example.com, blog.example.comexample.org, notexample.com
www.example.comwww.example.comexample.com, shop.example.com

The safest entry is usually your bare domain. Listing only www.example.com breaks the form for anyone who reaches your site without the www.

Remember the other hostnames your site is served from: a staging subdomain, a preview URL from your host (for example a *.pages.dev or *.netlify.app address) or a second domain. Add each one you want to accept. Add the preview host's specific subdomain rather than the whole platform domain, otherwise every site on that platform could use your key.

How the site is detected#

Browsers attach an Origin header to cross-site form posts and fetch requests, naming the site the request came from. SilentForms compares its hostname with your list. When there is no usable Origin (for example Origin: null), it falls back to the Referer header.

A web page cannot set either header to another site's address, which is why the check works against copied keys in other people's websites. A page can ask the browser to hide them, with a no-referrer policy or from a sandboxed frame. The browser then sends Origin: null and no Referer. While your list is set, SilentForms refuses such a request with the same 403: only a browser hiding where it came from sends it, and that is exactly how a copy of your form on another site would try to get past the list.

Requests without an Origin#

Scripts and servers (curl, a backend job, a bot written in Python) do not have to send Origin or Referer at all. By default such requests are still accepted, so your own server-side integrations keep working. (A request carrying Origin: null is not one of these: it comes from a browser and is refused, as described above.)

Tick "Also block requests that send no Origin" to refuse requests with no origin too. This stops casual scripted use of your key, at the cost of any server-to-server posting you do yourself. It only has an effect when the allowed-domains list is not empty.

Why it is a deterrent, not a lock#

The check relies on headers that the browser sets honestly. A script outside a browser can send any header it likes, including Origin: https://example.com with your domain. So the allowlist stops the realistic abuse (your key pasted into someone else's site, where real visitors' browsers report the real origin), but not a determined attacker who scripts requests directly.

For that, combine it with the other protections:

  • the honeypot catches simple bots for free,
  • a CAPTCHA requires a token that only a real visitor on your page can obtain,
  • rate limits cap how fast any one source can submit,
  • key rotation gives you a fresh key if the old one is being abused.

The error visitors see#

A refused submission gets 403 with the message "This form does not accept submissions from this domain." A plain HTML form lands on the SilentForms error page with that text; a fetch request gets it in the JSON message.

Test it#

Submit the form on your live site and check it arrives. Then simulate a post from another site with curl, which lets you set the Origin header by hand:

curl -i -X POST https://silentforms.com/api/submit \
  -H "Origin: https://not-my-site.example" \
  -H "Accept: application/json" \
  -d accessKey=YOUR_ACCESS_KEY_HERE \
  -d message=Test

You should get HTTP/2 403 (or HTTP/1.1 403) and the domain message. Change the Origin to one of your domains and the same request is accepted, which also demonstrates why this is a deterrent rather than a lock.

Local development is the usual surprise: localhost and IP addresses cannot be added to the list, so a form running on http://localhost:3000 is refused once the list is set. Test locally before turning the restriction on, use a second form with no restriction for development, or test on a staging subdomain you have listed.

Next steps#