Static site generators like Eleventy have gained popularity for their speed, security, and low hosting costs, but they pose a classic problem: there is no server‑side runtime to handle form submissions. When a visitor fills out a contact form, the browser needs somewhere to POST the data so it can be turned into an email or stored for later review. On platforms such as Netlify, a built‑in forms service removes this friction, but on Cloudflare Pages you must bring your own backend. This is where Cloudflare Workers (exposed via Pages Functions) become a lightweight, cost‑effective alternative. By deploying a tiny JavaScript endpoint at /api/contact, you keep the site fully static while gaining the ability to process form data, validate it, and trigger an email send—all without provisioning a traditional server. The worker runs on Cloudflare’s edge network, meaning low latency and automatic scaling, and because it lives inside the same account as your Pages site you avoid extra billing complexities or third‑party dependencies.

Choosing a serverless endpoint also aligns with modern DevOps practices: the function lives alongside your site’s code in Git, receives the same CI/CD pipeline, and can be versioned, reviewed, and rolled out with the same confidence as any other asset. Compared to third‑party form handlers like Formspree or Formspark, a self‑hosted Worker gives you full control over data residency, privacy policies, and the exact shape of the payload you send to your email provider. Moreover, you avoid the recurring costs that many SaaS form services impose at higher submission volumes. For a personal blog or a small business site, the free tier of Cloudflare Workers is often sufficient, making this approach both economical and technically satisfying. The trade‑off is a modest amount of initial setup—registering keys, writing validation logic, and configuring environment variables—but the payoff is a bespoke, auditable pipeline that matches the exact needs of your audience.

reCAPTCHA v3 offers an invisible challenge that evaluates the likelihood that a visitor is human without interrupting their experience. Instead of presenting distorted text or image grids, the script gathers a rich set of signals from the browser and sends them to Google’s risk analysis engine, which returns a score between 0.0 (almost certainly a bot) and 1.0 (almost certainly a human). This score is then interpreted by your backend to decide whether to accept, flag, or discard the submission. The beauty of this model is that legitimate users never see a puzzle, reducing friction and improving conversion rates, while bots are still challenged by the underlying analysis. For a contact form, where the goal is to collect genuine inquiries while keeping spam at bay, reCAPTCHA v3 provides a seamless first line of defense that works silently in the background.

The signals fed into reCAPTCHA v3’s scoring algorithm are diverse and continually refined. On the behavioral side, the script examines mouse movements: human users tend to produce curved, slightly jittery paths with natural pauses, whereas automated scripts often generate straight lines and uniformly timed clicks. Typing dynamics are similarly scrutinized—real humans exhibit variable key‑press latency, occasional hesitations, and a rhythm that differs from the machine‑like uniformity of bots. Beyond interaction patterns, reCAPTCHA also performs browser and device fingerprinting, collecting attributes such as user agent, screen resolution, installed fonts, WebGL capabilities, and even subtle hardware characteristics. Each attribute adds entropy, making it easier to distinguish a genuine device from a headless browser or a spoofed environment. While fingerprinting raises privacy concerns, Google argues that the data is used solely for abuse prevention and is not tied to personal identities for advertising purposes.

In addition to local signals, reCAPTCHA v3 taps into Google’s global reputation network. By observing billions of interactions across its services, the search giant can identify IP addresses, ASNs, or even specific user agents that have historically been associated with abusive traffic. This global view allows the system to boost the risk score for connections originating from known bad actors, even if their local behavior appears benign. Furthermore, reCAPTCHA v3 can predict the intent behind an action: developers supply an action name (e.g., “login” or “submit_contact”), and the service compares the observed behavior against baseline patterns for that action learned from trillions of historical events. For instance, a genuine contact form submission typically takes a few seconds to fill out, whereas a bot might attempt to send hundreds of requests per minute. The resulting score reflects both the immediate behavior and the broader contextual risk, giving developers a nuanced tool for tuning their spam thresholds.

Integrating reCAPTCHA v3 with a Cloudflare Worker involves a few straightforward steps. First, register your site in the Google reCAPTCHA admin console to obtain a site key (for the client) and a secret key (for the server). The site key is embedded in your HTML so that the browser can request a token when the user interacts with the form. The secret key must never be exposed client‑side; instead, store it as an environment variable in your Cloudflare Pages dashboard, where it is encrypted at rest and injected into the Worker’s runtime environment. In the Worker, upon receiving a POST request, you extract the token from the form data, then make a sub‑request to https://www.google.com/recaptcha/api/siteverify, passing the secret key and the token. Google’s response includes the score and a success flag; you then apply a threshold—for example, rejecting any score below 0.3—as the baseline for bot likelihood. This logic lives entirely within the Worker, keeping the verification step close to the edge and minimizing latency.

Beyond the invisible CAPTCHA, a solid contact form incorporates multiple layers of defense and accessibility. A honeypot field—an input hidden via CSS but still present in the markup—catches bots that indiscriminately fill every field they encounter; if that field contains a value, the request can be rejected immediately without bothering the user. On the accessibility front, semantic HTML is essential: use

and

, and provide ARIA attributes such as aria-labelledby, aria-describedby, and aria-invalid to convey state to screen readers. Visually hidden error messages, live regions with role=”alert”, and focus management (moving focus to the error summary when validation fails) ensure that users relying on assistive technologies receive timely feedback. Additionally, adding autocomplete attributes for name and email fields enables browsers to suggest previously entered values, streamlining the experience for returning visitors while maintaining security.

Validation should happen both in the browser and on the server to defend against bypassed client‑side checks. Client‑side JavaScript can enforce basic rules—required fields, minimum lengths, and pattern matches for email—while providing instant, inline feedback. However, the server (your Cloudflare Worker) must re‑validate every piece of data: confirm that required fields are present, enforce maximum lengths to prevent buffer‑style attacks, and sanitize any user‑generated content before it enters the email body. Escaping HTML entities protects against injection attempts that could compromise your email service or expose recipients to malicious content. Once all checks pass, the Worker assembles a multipart email (both plain text and HTML versions) and hands it off to an email delivery provider. After a successful send, the Worker returns a 303 redirect to a thank‑you page, completing the POST‑Redirect‑GET pattern and preventing duplicate submissions on refresh.

For email transmission, Resend offers a developer‑friendly API that abstracts away the complexities of SMTP, deliverability, and bounce handling. By invoking Resend’s REST endpoint from within the Worker, you gain access to features like open‑and‑click tracking, suppression lists, and detailed analytics—all without managing your own mail servers. Because the request originates from the Worker, there is no need to modify your site’s Content‑Security‑Policy (CSP) to allow connections to an external email service; the CSP only needs to permit the Worker’s own origin, which is already trusted. This reduction in third‑party dependencies simplifies compliance audits and lowers the attack surface: if Resend experiences an outage, you can quickly switch to another provider or queue the messages for later delivery, whereas a direct SMTP integration might leave you stranded without fallback options.

When readers pointed out that Cloudflare offers its own CAPTCHA alternative—Turnstile—I revisited the implementation to compare the two. Turnstile functions similarly to reCAPTCHA v3 in that it runs invisibly, returns a token, and relies on a server‑side verification step. However, Turnstile’s verification endpoint lives within Cloudflare’s own infrastructure, meaning the secret key never leaves the Cloudflare network and the verification request does not traverse the public internet. From a privacy standpoint, this eliminates the need to share behavioral data with Google, addressing concerns about tracking and profiling. Performance‑wise, both solutions exhibit low latency, but Turnstile can shave a few milliseconds off the verification round‑trip because the request stays on Cloudflare’s edge. Integration-wise, the changes are minimal: replace the reCAPTCHA script tag with Turnstile’s, swap the site key, and adjust the verification URL in the Worker to https://challenges.cloudflare.com/turnstile/v0/siteverify. The rest of the validation logic remains unchanged.

Choosing between reCAPTCHA v3 and Turnstile ultimately hinges on your priorities regarding data privacy, vendor lock‑in, and compliance requirements. If your audience is particularly sensitive to third‑party tracking or you operate under strict data‑localization rules (e.g., GDPR with restrictions on transferring personal data outside the EU), Turnstile offers a compelling advantage by keeping verification wholly within Cloudflare’s ecosystem. On the other hand, reCAPTCHA v3 benefits from years of refinement across a massive global dataset, potentially offering slightly higher detection accuracy for sophisticated bots. For many personal blogs, the difference in detection rates is negligible, making the privacy‑first Turnstile an attractive default. Regardless of which you choose, remember to monitor the scores in your logs, adjust thresholds based on observed false positives/negatives, and keep the secret keys secured through environment variables.

To put this into practice, start by scaffolding your Eleventy site with a simple contact form that includes the honeypot, proper labeling, and ARIA attributes. Add the chosen CAPTCHA script (either reCAPTCHA v3 or Turnstile) and ensure the token is submitted alongside the form data. Create a Cloudflare Pages Function at /api/contact that reads environment variables for the secret key, validates the token, enforces server‑side validation, sanitizes input, and forwards the message via Resend (or your preferred email API). Test the flow with both legitimate inputs and simulated bot behavior to verify that the scoring threshold works as intended. Finally, audit your CSP to confirm that no unnecessary third‑party sources are allowed, and set up logging to capture submission volumes and spam rates. With these steps in place, you’ll have a robust, private‑respecting contact form that scales with your traffic, protects your inbox, and delivers a smooth experience for every visitor.