Bandage for Craft CMS

Installation

Requirements

  • Craft CMS 5.3 or later
  • PHP 8.2 or later
  • craftcms/contact-form 3.x

That last one catches people out. Contact Form 2.x is the Craft 3 line; the Craft 4 and 5 line is 3.x. If Composer resolves ^2.0 you are about to install a plugin for a version of Craft you are not running.

Bandage has no other runtime dependencies. CAPTCHA providers are called over HTTPS only when you switch one on.

Install

composer require justinholtweb/craft-bandage
php craft plugin/install bandage

Contact Form is a Composer dependency, so it will be fetched for you. Installing it in Craft is a separate step, and one Bandage cannot do on your behalf:

php craft plugin/install contact-form

Installing Bandage creates a default form profile. Every form on the site uses it until you create another one, so a single-form site never has to visit the Forms screen at all.

Add the tag

Bandage attaches to the form you already have. Add one line to it:

<form method="post" accept-charset="UTF-8">
  {{ csrfInput() }}
  {{ actionInput('contact-form/send') }}
  {{ redirectInput('contact/thanks') }}

  {# This is the only line Bandage needs. #}
  {{ craft.bandage.form() }}

  <input type="email" name="fromEmail" value="{{ submission is defined ? submission.fromEmail }}">
  <input type="text" name="fromName" value="{{ submission is defined ? submission.fromName }}">
  <textarea name="message[body]">{{ submission is defined ? submission.message.body ?? '' }}</textarea>

  <button type="submit">Send</button>
</form>

That tag renders three hidden inputs — which form profile applies, a honeypot, and a signed render timestamp — plus the CAPTCHA markup once you configure one.

Nothing else about the form changes. contact-form/send is still the action you post to, submission is still Contact Form's model, and submission.getErrors() still behaves exactly as Contact Form documents it.

What happens straight away

From the first submission after that tag goes in:

  • Every message is stored as a Craft element, listed under Bandage → Submissions
  • Each one gets a short reference like K4TP-9WQR, quotable down a phone
  • The honeypot and the time trap are running, scoring anything that trips them
  • Spam scoring above the threshold is quarantined — stored, marked, not sent, and the visitor still sees the ordinary success message

Nothing is deleted, nothing is blocked outright, and no email that was going out stops going out unless the score says so. Retention is off by default: a plugin that quietly deletes your correspondence is worse than one that keeps it.

Editions

Lite (free)Pro
Stored submissions, field layout, search, trash
Spam scoring, honeypot, time trap, blocklists, CAPTCHA
Attachment capture and limits
CSV export, retention, the digest
Multiple form profiles
Field validation rules
Recipient routing (To / Cc / Bcc by answer)
Conditional redirects
Autoresponder
Webhooks, Slack, Microsoft Teams

Pro is $79, with a $29 annual renewal for updates. Lite is free and stays free.

Downgrading never deletes configuration — it stops it applying. A site that drops to Lite keeps its routing rules on disk, in project config, and picks them back up if it upgrades again.

Verify it

Submit the form once, then:

php craft bandage/submissions/export --path=/tmp/check.csv

One row means the pipeline is wired up. If the export is empty but the email arrived, the tag is missing from the template — Contact Form sent the message without Bandage ever seeing it.

Next

  • Configuration — spam, recipients, retention, the digest
  • Usage — Twig, conditions, routing, the console