Package2026
recaptcha-next, reCAPTCHA v3 for Server Actions
A React field and a server function that stop spam on Next.js forms without adding a field for the visitor.
RoleAuthor and maintainer
- TypeScript
- React 19
- Next.js
- Server Actions
- reCAPTCHA v3
- Playwright

Overview
My own sites kept receiving spam through their contact forms, and I wanted to stop it without making the form longer. reCAPTCHA v3 does that: it shows no challenge and gives each submission a score. I wrote a package so the same few lines work on every site I build.
A client field keeps a fresh token in a hidden input. A server function reads the token from the form data, asks Google, and returns a typed result: a success, or a reason such as low-score or missing-token.
The challenge
Using reCAPTCHA with Server Actions has details that are easy to get wrong. Google's script keeps its own state, so loading it again after a client-side navigation leaves duplicate badges. Tokens last two minutes, so a visitor who takes a while needs a fresh one. And if the secret key is missing in production, the check must fail and not let everything through.
Key features
- Server Actions friendly: read the token from
FormData, verify it, get a typed result. - One script per page, shared by every field and kept across client-side navigation.
- Lazy loading: Google's script can wait until the form is near the viewport.
- Fails closed in production when the secret key is missing.
- ESM and CommonJS, full types.
Technologies used
- Package: TypeScript, React 19, the Next.js Server Actions model, Google's reCAPTCHA v3.
- Tests: Jest for the domain and the hooks, and Playwright against a real Next.js app, including navigation, the back button and a form submitted after navigating.
- Tooling and infrastructure: GitHub Actions with npm trusted publishing, and a documentation site built with docs-sitekit.
Outcome
Version 0.1.0 was released on 2026-10-28. It runs on the contact form of this site and on the one of Image Optimizer, a site of mine that sells an image API. A check with real keys scored a human visitor at 0.9 on both, with one script and one badge on the page.
Screenshots

The lazy loading page of the docs. It explains why the badge may not show at the top of a page. 
The testing page: how to test a form without calling Google, and how to check it once with real keys.