Every Shopify theme's contact form gets two layers of spam protection without you doing anything: hCaptcha, which watches how the visitor behaves, and a spam filter that reads the message. Then Shopify does something that is easy to miss: it emails you the messages its filter flags as spam as well. That is a stated design choice rather than a fault, and once you know it, the fix for most stores is a mail rule, not an app. Shopify details below are from its help centre and developer docs as of 24 October 2026.
What Shopify does with a contact form submission
- hCaptcha is on by default for every store. It lives in Online Store > Preferences, under Spam protection, as the checkbox Enable hCaptcha on contact and comment forms. It scores the visitor's behaviour invisibly, and only visitors it finds suspicious, or who send too many requests in a short time, are given an interactive challenge.
- The spam filter reads the message. Shopify's help says the content of the contact[body] field is analysed, and a submission flagged as spam is emailed to you with [SPAM] at the start of the subject line.
- Everything is delivered. In Shopify's words: "To make sure that you don't miss any legitimate messages that are flagged as spam by mistake, you receive all contact form submissions, including those flagged as spam."
- It all goes to one address, the store's sender email, which you set on the Notifications settings page. The subject line of contact form emails cannot be changed.
If spam is getting through, check these first
Most stores can deal with this without touching the form. In order:
- Confirm the hCaptcha checkbox is ticked in Online Store > Preferences.
- Make sure your contact form is one hCaptcha recognises. Shopify wires it up to forms whose action contains /contact and which carry a hidden form_type input set to contact. The Liquid tag {% form 'contact' %} outputs both; a theme or page builder that renders its own form without them is not protected.
- Check that the theme layout includes content_for_header. That object is how the hCaptcha code reaches the page, and Shopify's docs say that without it the protection is simply absent.
- Open your browser's developer tools on the Network tab, submit the form, and look for an h-captcha-response field in the request payload. If it is missing, hCaptcha is not wired up. Shopify notes that some apps, particularly ones for page speed or cookie consent, can block hCaptcha's resources.
- Add a mail rule that moves messages whose subject contains [SPAM] into their own folder. Flagged spam leaves your inbox, and a real enquiry tagged by mistake is still in that folder rather than deleted.
If spam still arrives after that and nearly all of it carries the [SPAM] tag, the built-in protection is working as designed and the mail rule is the whole fix. Keep Shopify's form.
Why untagged spam still gets through
What is left is spam that hCaptcha lets past and the filter does not tag. hCaptcha judges the visitor, so a person typing a pitch into your form passes, as does anything that behaves enough like a visitor. The filter judges the message, and a polite offer to redesign your store or fix its SEO reads a lot like a customer question. That is the hardest kind of form spam for any filter, ours included, and it is usually what store owners mean when they say spam is getting past Shopify.
There is also nowhere for it to go but your inbox. Shopify's own suggestion, if you do not want contact form mail going through the store's sender address, is to use a form from another service instead. The rest of this post is about what that involves.
Posting the contact form somewhere else
You cannot point {% form 'contact' %} at another address. The tag always renders action="/contact#contact_form" with its form_type input, because its whole purpose is posting to Shopify. Sending the form to an endpoint means replacing the tag with a plain HTML form in a section of its own: create the file under Edit code, then add the section to your contact page template in the theme editor.
<form action="https://send.webforms.to/wft_your_key" method="POST" class="contact-form">
<p hidden><input name="_gotcha" tabindex="-1" autocomplete="off"></p>
<input type="hidden" name="_redirect" value="{{ shop.url }}/pages/thank-you">
<input type="hidden" name="_start_time" id="wf-start">
<label for="wf-name">Name</label>
<input id="wf-name" name="name" autocomplete="name">
<label for="wf-email">Email</label>
<input id="wf-email" name="email" type="email" required autocomplete="email">
<label for="wf-message">Message</label>
<textarea id="wf-message" name="message" rows="5" required></textarea>
<button type="submit">Send</button>
</form>
<script>document.getElementById("wf-start").value = Date.now();</script>
{% schema %}
{
"name": "Contact form (WebForms)",
"settings": [],
"presets": [{ "name": "Contact form (WebForms)" }]
}
{% endschema %}Use plain field names rather than contact[email] and contact[body]; they become the labels in every notification. Create a thank-you page at /pages/thank-you for the redirect to land on. And if you lock the form to your own domains in the dashboard, list both your custom domain and the .myshopify.com address if customers can reach the store on either.
What you lose
- hCaptcha. It only attaches to forms whose action contains /contact, so a form posting to an outside endpoint is not covered.
- Shopify's spam filter and the [SPAM] tag, because the message never reaches Shopify.
- Delivery to the store's sender email. Notifications come from the form backend instead, and you choose the recipients there.
- The theme's own success and error messages. They come from the form object that only exists inside Shopify's form tag, so visitors see your thank-you page instead.
- A little upkeep. Shopify carries code edits across a theme update only when they do not conflict with it, so keep a copy of the section file before you update the theme.
What WebForms does instead
A submission from that section goes through the same filter as any other WebForms form. The honeypot and the time trap catch scripts that post directly, and a rejected submission still gets a normal success response, so the sender learns nothing about what caught it. If the form is locked to your store's domains, a submission from anywhere else adds to its score. Then an AI classifier reads the message, on every plan including free, which is the layer aimed at the polite pitch that hCaptcha lets through.
Anything over the spam threshold is quarantined: stored and readable in the dashboard, never delivered to email or anywhere else, and not counted toward your monthly submissions. That is the real difference from Shopify's approach. Shopify tags suspected spam and delivers it; we hold it back and keep it, so your inbox only gets what passed, and a real enquiry held by mistake is still there for you to read and answer.
Which one to choose
- The spam arrives tagged [SPAM]: add the mail rule and keep Shopify's form. It costs nothing and it is working.
- The spam arrives untagged and you have confirmed hCaptcha is wired up: what is left is the hand-typed kind. A filter that reads the message and holds suspected spam back is the change that helps, and the price is owning one section file.
- You also want enquiries somewhere other than one inbox, such as a wholesale channel in Slack: that is when replacing the form is worth the upkeep. Email delivery is on our free plan, at 300 submissions a month; Slack, webhooks and routing rules start at $5 a month.