
nForms
One script tag. Zero CAPTCHA. EU-only form backend.
## TL;DR
We run [nForms](https://nforms.eu) — a GDPR-compliant form backend with built-in bot protection via Proof-of-Work (instead of CAPTCHA). Last week I realized our compare pages had a huge conversion leak: visitors would read "nForms vs. reCAPTCHA", nod along, then bounce because they couldn't picture how hard the migration actually is.
So over 2 days I shipped:
- 4 drop-in migration guide pages (reCAPTCHA, Turnstile, hCaptcha, Friendly Captcha)
- EN + DE content for all 4 (~80k characters of markdown)
- HowTo + FAQPage JSON-LD schemas on each for Google Rich Results
- A 45-second inline screencast with live Proof-of-Work visualization — real API challenge, real SHA-256 solver, real numbers animating on screen
- og:video + Twitter player card metadata so shared URLs unfurl as inline video
- Conditional "Migrate in 60 seconds" CTA block on all 4 compare pages
- Cross-links from 6 existing blog posts that already rank for reCAPTCHA keywords
Results are pending (deployed today), but here's what I learned and why it should work.
---
## The leak I found
Our compare/recaptcha page already ranked on long-tail queries. Visitors landed, read the pain points, saw the feature table, agreed conceptually — and then the only CTAs were "Get Started Free → /login" and "View Pricing".
That's a huge commitment for someone who's 2 minutes into the page. What they actually want at that moment is proof that the migration isn't a weekend project. "Show me how hard this is" comes before "let me sign up".
I had nothing to show them.
---
## The drop-in snippet approach
The core insight that made the content click: reCAPTCHA has 3 common integration flavors in the wild — v2 Checkbox, v2 Invisible, v3 Score-based. Most migration guides cover one and leave the other two readers stranded.
But our "after" snippet is identical for all three:
```html
<script src="https://api.nforms.eu/shield.js"></script>
<form action="https://api.nforms.eu/f/YOUR_KEY" method="POST"
data-nforms-key="YOUR_KEY">
<input name="email" required />
<button type="submit">Send</button>
</form>
```
Three complex Before-states → one simple After-state. That asymmetry is the story. Once I framed it that way, the page wrote itself.
Plus the "what you can delete" section (server-side siteverify endpoint, RECAPTCHA_SECRET_KEY, cookie banner entry, react-google-recaptcha from package.json) is emotionally satisfying in a way that devs on Twitter eat up. People love deleting code.
---
## The live Proof-of-Work visualization
The thing I'm most proud of: the screencast doesn't just claim Shield runs a PoW solver, it shows it.
I wrote a Playwright script that renders a single-page HTML video with 6 narrative scenes:
1. Hook (3s) — "22 → 2" — big display
2. Problem (7s) — reCAPTCHA code + red stats
3. Solution (6s) — nForms code + emerald stats
4. Live PoW (9s) — fetches a REAL challenge from api.nforms.eu, solves it for real, animates the counter from 0 → n_found over 7 seconds, shows the real hash, displays the real solve time
5. Proof (9s) — fills and submits a real form with live Shield
6. CTA (4.5s) — nforms.eu with emerald glow
The PoW scene is the moneymaker. Every number and hash shown on screen is real — salt, target, counter, found n, completion time. Only the sweep speed is throttled (500k iterations compressed from ~200ms to 7 seconds of visual drama). It proves the "zero puzzles, just math" claim instead of stating it.
Playwright records at 1280×720, I export to MP4 (1.8 MB, for Twitter/LinkedIn), WebM (3.2 MB, for the embedded player), and GIF (8 MB, for Reddit/dev.to).
---
## On-site discoverability
The video is embedded directly on all 4 migration pages as autoplay-muted-loop. This does three things:
- Dwell time skyrockets (Google's strongest ranking signal after backlinks)
- Shared URLs unfurl as inline video on Twitter/LinkedIn/Slack (`og:video` + twitter:card=player)
- Visitors see the "60 seconds" proof before they even scroll
Plus the compare pages now have a conditional CTA block between "Why Switch" and "Feature Comparison" — exactly at the moment visitors go from problem-awareness to solution-evaluation.
---
## The internal link strategy
Instead of praying for external backlinks, I added 6 internal links from blog posts that already rank for reCAPTCHA keywords:
- /blog/why-proof-of-work-beats-captcha
- /blog/is-recaptcha-gdpr-compliant
- /blog/recaptcha-gdpr-problem
- /blog/recaptcha-alternative-eu
(Plus DE variants for each.)
Each post now closes with a CTA paragraph pointing to the migration guide. These are already-indexed, already-ranking pages passing link equity to the new target. No waiting for crawl budget or backlink outreach — the equity is there, I just needed to route it.
---
## Schema.org for Rich Results
Every migration page has both HowTo and FAQPage JSON-LD. Google's HowTo rich result is one of the few that still shows step counters and "total time" in SERPs. I set totalTime: "PT1M" (60 seconds) so the SERP snippet literally shows "⏱ 1 min" next to the headline. That's CTR gold.
The FAQ schema pulls the 3-7 most common questions per page. Combined with the HowTo schema, each page has ~11 KB of structured data that Google and LLM crawlers can cite directly.
---
## What I'd do differently
- Launch the distribution in parallel to the build: I finished the guides first, then started writing Twitter threads. Should've had drafts ready so I could ship + post in the same hour.
- Record per-competitor screencasts: Currently all 4 migration pages share one video (the reCAPTCHA one). Native per-competitor videos would rank better for "migrate from turnstile" etc., but the effort-to-impact felt marginal for v1.
- PostHog events: I didn't wire specific events for the migration guide funnel (page view → video play → CTA click → signup). Doing that this week so I can actually measure if any of this worked.
---
## Tech stack (for the curious)
- Next.js 15 on Cloudflare Pages via OpenNext
- Content in flat JSON files (`lib/docs/content-{en,de}.json`) rendered via a tiny custom tokenizer — no MDX, no CMS
- Playwright 1.59 for the screencast recording, ffmpeg for format conversion
- Sitemap auto-generated from a DOC_SECTIONS config
- Deployed via GitHub Actions → Cloudflare (3-4 min per deploy)
---
## Links
- Main migration page: https://nforms.eu/docs/migrate-from-recaptcha
- Compare page with new CTA: https://nforms.eu/compare/recaptcha
- nForms itself: https://nforms.eu (free tier: 100 submissions/month, no credit card)
Happy to answer questions about the PoW economics, the content strategy, or the Playwright screencast pipeline if anyone wants to steal it.
Hey IH 👋
I'm Noah, solo founder from Germany. I just launched nForms into public beta.
The problem I kept running into:
Every client form needed three things — spam protection, accessibility compliance, and GDPR compliance. reCAPTCHA handles one of those (badly). WCAG needs manual ARIA work. GDPR means cookie consent banners just for bot protection.
What I built:
A form backend that replaces CAPTCHA with SHA-256 Proof-of-Work. The browser solves a math challenge in ~200ms — bots can't scale it, users don't see it. The same script tag also adds WCAG 2.2 AA form validation automatically.
Zero cookies. EU-only infrastructure. One script tag.
Stack: Cloudflare Workers (Frankfurt), D1, Hono, Next.js
Where I'm at:
- Revenue: $0/mo
- Users: handful of beta testers
- Built solo as a side project
- Free tier: 100 submissions/month
- Paid: €9/mo
What I'm looking for:
Honest feedback. Especially from devs who've dealt with form spam or EU compliance headaches.
→ nforms.eu (the contact form is a live demo — Shield is active on it)
Happy to answer any questions about the tech or the journey so far.
Like
Comment
About
reCAPTCHA on client forms meant cookies, US data transfers, consent banners. No tool handled spam + accessibility + GDPR together. So I built one. PoW bot protection, WCAG validation, EU-only. One script tag.

Comment