Plainwork

Plainwork / Catalogue / Signup Shield Kit

TemplatesNo. 1012-08

Signup and contact forms for static sites that limit what bots can make you send

A Cloudflare Worker with double opt-in, proof of work, honeypot and per-address caps, plus three sample sites, docs and an attack simulator. One purchase, no subscription.

  • Worker (one file, 27.2 KB, no dependencies): double opt-in, proof of work tied to the address, honeypot, signed challenges, per-address, per-IP and daily caps, contact form, subscriber CSV export
  • Browser script (12.0 KB): solves the proof in a background thread, announces results to screen readers, no cookies, no third-party requests
  • 11 sample pages in 3 designs: a newsletter site, a product waitlist and a studio contact page, each with light and dark themes and starter privacy text
  • Attack simulator: 14 scripted scenarios run against the real Worker, with the numbers it prints
  • 34 automated tests, a local server that prints emails in your terminal, a form checker and a colour-contrast checker
  • Plain-text docs: deploy in 15 minutes, how it works, what it does not stop, free-plan limits, accessibility, licence and changelog
Try the free proof-of-work tester →
Instant deliverySecure checkout by Stripe14-day refund
Real output: what the kit does under attack

This is real output from the kit's own attack simulator (node tools/simulate.mjs), which runs the shipped Worker against scripted abuse. "Emails" are confirmation emails the Worker asked the email provider to send. Difficulty here is 16 bits and the run takes about a minute; the kit's default is 18.

1. Naive bot posts 1,000 random addresses, no proof of work
   attempts  1000   emails sent    0   storage writes     0   expected: 0 emails
2. Form-filling bot fills the hidden honeypot field, 1,000 times
   attempts  1000   emails sent    0   storage writes     0   expected: 0 emails
3. Bot solves the proof of work, one IP, 200 random addresses
   attempts   200   emails sent    5   storage writes    16   expected: at most 5 emails (IP cap)
4. Botnet: 300 IPs each solve the work, 300 random addresses
   attempts   300   emails sent  100   storage writes   301   expected: at most 100 emails (daily cap)
5. Subscription bomb: 300 IPs all target ONE victim address
   attempts   300   emails sent    1   storage writes     4   expected: 1 email
5b. Same bomb, but all 300 requests are fired in parallel
   attempts   300   emails sent    1   storage writes     4   expected: 1 email
6. Replay one solved proof against 200 different addresses
   attempts   200   emails sent    1   storage writes     4   expected: 1 email (the one address the proof was solved for)
7. Same as 6 but the bot posts instantly (before the minimum age)
   attempts   200   emails sent    0   storage writes     0   expected: 0 emails
8. Real visitors: 40 people from 40 IPs subscribe
   attempts    40   emails sent   40   storage writes   121   expected: 40 emails
9. Storage quota used up (storage writes fail), then 50 real visitors
   attempts    50   emails sent    0   storage writes     0   expected: 0 emails, fail closed
10. Mailbox variants: 300 IPs target ONE Gmail inbox as [email protected], v.ictim@, [email protected]
   attempts   300   emails sent    1   storage writes     4   expected: 1 email
11. Contact form: one solved proof reused for 200 different messages from 200 IPs
   attempts   200   emails sent    1   storage writes     5   expected: 1 email to the owner
12. Contact flood that pays the work for every message (200 IPs), then one real signup
   attempts   201   emails sent   31   storage writes   124   expected: at most 30 owner emails (contact cap), and the signup still gets its email
13. One IPv6 /64 (50 addresses in the same network) signs up 50 random addresses
   attempts    50   emails sent    5   storage writes    16   expected: at most 5 emails (IP cap counts the /64)

And the form markup you put on a page (the script adds the hidden field and does the rest):

<form class="shield" data-shield="subscribe" data-endpoint="https://signup-shield.your-name.workers.dev">
  <label for="s-email">Email address</label>
  <input id="s-email" name="email" type="email" autocomplete="email" required>
  <p data-shield-status id="form-status" role="status" aria-live="polite"></p>
  <button type="submit">Subscribe</button>
</form>
<script src="assets/shield.js" defer></script>

Open the live demo to try five of these attacks against a cut-down copy of the Worker running in the page.

Made for

Who it's for

Developers and agencies building static sites that need a signup or contact formIndie writers with a newsletter on their own domainSmall teams collecting a product waitlist without a form serviceAnyone who has seen confirmation emails going to addresses nobody typed

One mailbox, one confirmation email a day

Pending for 24 hours, never again once confirmed. Plus tags and Gmail dots count as one mailbox: 300 spellings of one inbox from 300 IPs produced 1 email in the simulator. Other providers' aliases are not folded; ATTACKS.txt says which.

Checks that cost you nothing run first

Wrong origin, bad input, a filled honeypot or a missing proof are refused before anything is stored or sent. A flood of lazy bots costs no storage writes and no email.

No third party in the loop

The check runs in your visitor's browser and on your own Worker. Nothing is sent to a captcha company, and there is no puzzle or cookie.

Fits the free plans, and says so

Designed around the Cloudflare free limits (10 ms CPU per request, a SQLite Durable Object for state). The limits file gives the numbers and what happens when you hit them: it fails closed and sends nothing.

Honest about what it cannot stop

Proof of work raises cost; it does not unmask a bot using a real browser. The docs and the simulator show where the daily ceiling takes over, and what that costs your real visitors.

What's inside

Everything you get

worker/index.jsThe Worker. Routes: challenge, subscribe, contact, confirm, unsubscribe, export.
client/shield.jsAdd data-shield to a form and load this script.
templates/newsletter-site, waitlist-site, contact-siteThree finished designs with confirmed and unsubscribed pages where they apply.
tools/simulate.mjsRuns scripted attacks against the Worker and prints what got through.
tools/serve-local.mjsEverything on your computer in one command; emails print in the terminal.
tools/check-form.mjs, contrast.mjsCheck form markup and theme colours before you publish.
tests/test.mjs34 tests of the Worker; run with node --test.
DEPLOY.txt and the other docsSteps from a free Cloudflare account to a working form.

How it works

From checkout to done

Buy

Download the zip and run node tools/serve-local.mjs to try it on your computer

Open

Follow DEPLOY.txt: set three secrets and deploy the Worker

Use

Point a template's forms at your Worker address and upload the site

Questions

Good to know

Does it send my newsletter?

No. It collects and confirms addresses and gives you a CSV; you send your issues with whatever mail tool you already use. It also makes signed one-click unsubscribe links for the addresses you hold.

Can bots still get through?

Some can. A bot that runs a real browser or copies the solver pays the proof of work. What the kit limits is the harm: one email per address a day, per-IP and daily ceilings, and nothing sent when storage is unavailable. ATTACKS.txt in the zip lists what it does not stop.

Why not just use Cloudflare Turnstile?

Turnstile is a strong check and you can add it. This kit avoids a third party by default, includes the opt-in, caps and email around the check, and gives you a way to test the result. Pick the trade-off that suits your audience.

What do I need to run it?

A free Cloudflare account, a free Resend account with a verified sending domain, Node 18 or newer on your computer to deploy, and any static host for the pages. Costs on the free plans are zero; the limits file explains the daily allowances.

Is the privacy text legal advice?

No. The templates include starter privacy wording for you to edit; you are responsible for your notice and for following the email and data-protection rules where you and your readers live.

Can I use it for clients?

Yes, on any number of sites you own or build for clients. You may not resell the kit or its templates. The licence file has the wording.

What if it doesn't work for me?

If it doesn't work as described or you can't access it, email us within 14 days and we'll fix it or refund you. See the refund policy for details.

Signup Shield Kit

Static-site newsletter, waitlist and contact forms with double opt-in and subscription-bombing protection. Worker, 3 sites, simulator.

Get it for $15

More from the catalogue

Other small tools

See everything →