Wagtail Honeypot
Add optional form spam protection to your Wagtail forms
It should help to reduce form spam by tricking bots into submitting data in fields that should remain empty.
How it works
When the Wagtail Form is submitted and the honeypot protection is enabled, the honeypot fields & values are available in the POST data.
It provides validation for a hidden text field that should remain empty and checks a time interval between the form being displayed and submitted.
If the form is submitted with content in the hidden field or before the interval expires the submission is ignored.
- No email is sent
- No submission is stored
Installation and setup
Add the package to your python environment.
pip install wagtail-honeypot
Add the package to your settings
INSTALLED_APPS = [
...
"wagtail_honeypot",
...
]
The HoneypotFormMixin & HoneypotFormSubmissionMixin
They will add a honeypot enable/disable field to your form page model and custom form submission method.
If you follow the official Wagtail docs for the Form Builder your form should look something like this...
from wagtail_honeypot.models import (
HoneypotFormMixin, HoneypotFormSubmissionMixin
)
class FormField(AbstractFormField):
page = ParentalKey("FormPage", related_name="form_fields")
class FormPage(HoneypotFormMixin, HoneypotFormSubmissionMixin):
intro = RichTextField(blank=True)
thank_you_text = RichTextField(blank=True)
content_panels = AbstractEmailForm.content_panels + [
FieldPanel("intro", classname="full"),
InlinePanel("form_fields", label="Form fields"),
FieldPanel("thank_you_text", classname="full"),
MultiFieldPanel(
[
FieldRowPanel(
[
FieldPanel("from_address", classname="col6"),
FieldPanel("to_address", classname="col6"),
]
),
FieldPanel("subject"),
],
"Email",
),
]
honeypot_panels = [
MultiFieldPanel(
[FieldPanel("honeypot")],
heading="Reduce Form Spam",
)
]
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading="Content"),
ObjectList(honeypot_panels, heading="Honeypot"),
ObjectList(Page.promote_panels, heading="Promote"),
ObjectList(Page.settings_panels, heading="Settings", classname="settings"),
]
)
If you prefer you could add the honeypot field to the content_panels rather than a new Tab
# replace
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading="Content"),
ObjectList(honeypot_panels, heading="Honeypot"),
ObjectList(Page.promote_panels, heading="Promote"),
ObjectList(Page.settings_panels, heading="Settings", classname="settings"),
]
)
# with
content_panels = content_panels + honeypot_panels
Run python manage.py makemigrations and python manage.py migrate here
Honeypot Template Tag
Add the following template tag loader to your form page.
{% load honeypot_tags %}
Add the Honeypot fields template tag anywhere inside the form
<form>
...
{% honeypot_fields page.honeypot %}
...
</form>
In your Wagtail site you should now be able to add a new form page, enable the honeypot field.
Test that the honey pot field works
- View the newly created form page.
- The honeypot field is visible and could be submitted with any value.
- Test it out by submitting the form with the honeypot field set to any value. It won't save the form submission or send an email if you have enabled that in your form page.
Hide the Honeypot field
The honeypot field should be invisible to when viewed in a browser.
Use CSS & JS to hide the honeypot field
The package has some basic css and javascript you can use to hide the field.
Example: add the following to your form template.
<!-- recommended:
to add both but you can use one or the other -->
{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/honeypot.css' %}">
{% endblock extra_css %}
<!-- alternative:
but without the css above loaded first
the field could be seen for a flash while the page loads -->
{% block extra_js %}
<script src="{% static 'js/honeypot.js' %}"></script>
{% endblock extra_js %}
The field should be visibly hidden and not be available to receive any value from a site visitor.
When rendered, the fields will have the HTML attributes
tabindex="-1" autocomplete="off" aria-hidden="true"to keep them out of normal keyboard navigation, disable browser autocomplete, and hide them from assistive technology.
Developer Documentation
Developer Docs for detailed help.
Versions
Wagtail honey pot can be used in environments:
- Python 3.10+
- Django 4.2+
- Wagtail 6.3+
Contributions
Contributions or ideas to improve this package are welcome.
Release files for wagtail-honeypot 1.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wagtail_honeypot-1.3.1.tar.gz | 14.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wagtail_honeypot-1.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:22.7 kB
Release files / wagtail_honeypot-1.3.1.tar.gz
| Download URL | wagtail_honeypot-1.3.1.tar.gz |
|---|---|
| Size | 14.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e09cbb99ef6e18b98a3c36b06d9c2b7bd357477af4470404146af55d567528ff
|
|
BLAKE2b-256 checksum How to use checksums |
23c7d2a6130617ca2f1b0279ef80b93e034cc1b426b0d7b52ac1a3d76996bf5a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 16, 2026.
Transparency logRelease files / wagtail_honeypot-1.3.1-py3-none-any.whl
| Download URL | wagtail_honeypot-1.3.1-py3-none-any.whl |
|---|---|
| Size | 8.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
793f7bf91cdc8cf9b2516c4e6a274f939bfa94ef977fe031cabeef6c5e47cd91
|
|
BLAKE2b-256 checksum How to use checksums |
3b1770dc2a8f118046a9d12f67ea8061de2fe78e4a9d9bfdb9f42345d9cc42a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 16, 2026.
Transparency log