Discuss your task

Search

Start typing to search articles, cases, and services.

navigate Esc close

How to Accept a Form Submission on a Static Site Without a Backend

A static site accepts a form submission without a backend through a separate handler - a serverless function, a third-party form-backend service, or your own API endpoint. Plain static HTML can’t process a POST request from a form on its own, because a static host has no running process to receive it. Which option you pick depends on whether you need control over the data right away or can add it later.

On Astro, Eleventy, and other static-site-generator projects, we regularly see the same bottleneck. The site is built and deployed, the contact form looks finished, but the data goes nowhere - the markup is there, the handler isn’t. Developers usually find out only after launch, when the first lead never arrives.

The cause is the static site’s nature itself. HTML, CSS, and JS are served from a static host or CDN with no process listening for incoming requests and acting on them. The form needs somewhere to send its data - and that has to be added separately, outside the site build.

Below: three working approaches, a step-by-step serverless-function implementation, and where to route the submitted data.

The problem becomes acute for teams building a marketing site or landing page on Astro without a CMS and without a dedicated backend developer. You need a lead or contact form, but there’s no server in the architecture to accept a POST request. Without a handler, the form either reloads the page for nothing or fails with an error in the browser console.

Serverless function: code that runs in response to an HTTP request on a cloud provider’s infrastructure, with no server that the developer maintains and updates themselves.

Why a static site can’t accept a form without a backend

A static site is a set of prebuilt HTML, CSS, and JS files that the host serves to the browser with no computation on its side. A regular Node.js, PHP, or Python server receives a POST request from a form, parses the request body, and does something with it - saves it to a database, sends an email, writes it to a CRM. A static site has no such process at all.

The <form> tag can send a request to any address, but that address has to respond to something. If action points to an endpoint that doesn’t exist or is misconfigured, the browser gets a 404 or a CORS rejection. The form technically works, but the result is zero.

There’s a separate wrinkle: static-site generators like Astro, Eleventy, and Hugo render pages at build time, not on every request. That makes the site faster and hosting simpler, but it removes the ability to run logic “on the fly” right inside the page template. The logic has to live outside the build - in a separate function or service.

That’s where three independent approaches to the problem come from, and they don’t compete with each other - they cover different scenarios by traffic volume and data requirements.

Options overview

There are three working architectures for a form without a backend, and all three are used in real projects today.

Serverless and edge functions. Code is deployed on the hosting infrastructure (Netlify Functions, Vercel Functions, Cloudflare Workers) and runs only on an incoming request. Gives full control over the logic: validation, spam protection, sending data straight to any system.

Edge function: a type of serverless function that runs on servers geographically close to the user, which makes it respond faster.

Third-party form-backend services. Formspree, Netlify Forms, and Getform accept a POST request from the form directly, with no server-side code at all. Sign up, paste the service’s address into the form’s action, and the service forwards submissions to email or a spreadsheet.

Your own minimal API endpoint. A small dedicated server (for example, Node.js in a container) or an API route in a framework with hybrid rendering. Fits when handling the form is more complex than validating and forwarding it - for example, when you need custom business logic around the lead.

Each approach follows the same data path - from the user’s browser to the final system (email, CRM, spreadsheet) - but manages it at a different layer.

Which option fits when

The choice depends not on technology but on what matters most right now - speed to launch, control over the data, or a ready-made CRM integration.

  • Fast MVP or a test hypothesis. A third-party service is the quickest path: about 15 minutes to set up, no code to deploy. Fits when you need a form for a day or two, not as part of a permanent architecture.
  • Control over data and logic. A serverless or edge function is the right format for a site meant to live long-term. Validation, spam protection, and response format are entirely in your hands.
  • CRM integration. If the lead needs to land directly in the sales pipeline with the right fields and tags, a serverless function with a direct webhook call to the CRM is more reliable than the chain “form -> third-party service -> email -> manual entry into the CRM.”
  • Complex business logic. Your own API endpoint - when handling the lead requires more than validation and forwarding: checking against an external database, running a calculation, generating a document.

Step-by-step implementation with a serverless function

Let’s walk through the option that gives the most control - a serverless function that accepts form data and sends it onward.

The handler

A serverless function lives in a separate file alongside the site code - for example, in a functions/ folder for Netlify or api/ for Vercel. The host automatically deploys it as a standalone HTTP endpoint at a given path, with no manual server setup.

Example handler structure (conceptual, pseudocode)
export async function handler(request) {
  const data = await request.json();
  // validate required fields
  // check the honeypot field and request rate
  // send the data to the CRM or by email
  return new Response(JSON.stringify({ ok: true }), { status: 200 });
}

The form on the page points to this endpoint in its action attribute, or sends the data via fetch from JavaScript - the second option gives you more control over the UI and doesn’t reload the page.

Validation

Browser-side checks (the required attribute, field types) are convenient for the user but guarantee nothing - they’re trivial to bypass with a direct request to the endpoint. Server-side validation is mandatory: checking required fields, email format, and reasonable text length.

Without server-side validation, the function will accept any data, including empty or clearly malicious requests.

Spam protection

The basic set: a honeypot field, checking request headers, and rate-limiting requests from a single IP address. More on this in the next section - it’s a separate and frequent point of failure when launching a form.

Responding to the user

The function needs to return a clear status - success, validation error, server error. The frontend uses that status to show the user a message, instead of relying on a page reload.

Spam and bot protection without an annoying CAPTCHA

CAPTCHA solves the spam problem, but it lowers form conversion - every extra step filters out some real users along with the bots.

Honeypot field: a form field hidden with CSS, invisible to a human but visible to simple bots that fill in every field they find. If the field is filled in, the request is dropped as spam, with no CAPTCHA shown to a real user.

The second layer is rate limiting: capping the number of requests from a single IP address within a short window. Serverless platforms usually provide built-in tools for this at the infrastructure level, with no extra code needed.

The third layer is server-side data-format validation: email must match an email pattern, text fields must have a reasonable length, numeric fields must accept only numbers.

On typical static-site projects, a honeypot field combined with basic rate limiting cuts the share of spam submissions by 85-95% - without a single extra click from the user. The exact number depends on traffic volume and how aggressive the bots are, but the effect itself holds steady across projects.

CAPTCHA remains a fallback for sites with high, targeted bot traffic - for example, public forms with heavy traffic and a history of abuse.

Where to send the data next

A form without a backend solves only the first half of the task - accepting the data. The second half is where to send it next.

Email notification is the simplest option: an email with the submission details sent to a work inbox. The problem is that emails get lost in spam, aren’t deduplicated, and don’t plug into the sales pipeline. The lead lives in an inbox, not in a system the whole sales team can see.

Google Sheets works as an intermediate store. Fine for a low volume of submissions and manual processing, but it doesn’t scale - no statuses, no communication history, no automatic reminders.

A webhook into the CRM - the serverless function sends the data straight to the CRM via its API, with the right fields, tags, and pipeline attached. The lead shows up in the CRM within seconds, with no manual entry and no risk of losing an email to a spam filter.

A direct CRM integration beats email notifications for three reasons: the data is structured from the start instead of being parsed out of an email body; the lead can’t get lost in a spam folder; and a repeat submission from the same contact updates the existing record instead of creating a duplicate. If the site is already connected to other services, adding a webhook from the form is just another integration of the site with your CRM, analytics, and other services, not a separate project from scratch.

This is a case where the checklist on lead form field count and conversion won’t help - the topic is adjacent but different. That article is about how many fields to ask the user for. This one is about where the data technically goes after submission.

Common mistakes

Most problems with a backend-free form surface not during development but after the first few weeks in production.

  • Client-side validation only. Bypassed with a single direct request to the endpoint - server-side validation is mandatory.
  • Secret keys in frontend code. A CRM or email-service API key pasted straight into browser JavaScript is visible to anyone who views the page source - such keys belong only on the function’s side.
  • No honeypot or rate limiting. A form with no basic protection starts getting more spam than real leads within a few weeks.
  • A rate limit set too tight. A limit calibrated for one user at a time ends up blocking an entire office sharing one IP address.
  • Forgotten CORS configuration. The function rejects requests from the site’s own domain because of misconfigured headers - the form works in tests but not in production.
  • Notification by email only. The lead exists, but nobody sees it in time - without a direct CRM integration, checking email on time is one person’s responsibility alone.

Who this matters for

This topic matters for teams building a marketing site, a landing page for paid traffic, or a brochure site on a static stack (Astro, Eleventy, plain HTML) with no dedicated backend developer on the project. That’s startups at the MVP stage, agencies building landing pages for ad campaigns, and companies that deliberately chose a static site for speed and simple hosting. As soon as the first form appears on the site - contact, demo request, newsletter signup - the question of a handler becomes unavoidable.

Frequently asked questions

What’s the difference between a serverless function and an edge function?

A serverless function runs in one or a few regions of a cloud provider and can reach external databases with minimal latency. An edge function runs on servers geographically closer to the user, so it responds faster, but it usually has stricter limits on execution time and available memory. For a contact form, the difference is barely noticeable in practice - both handle validation and sending data in milliseconds. Edge functions are the right pick when minimal response latency matters and your audience is spread across a wide geography.

Can you skip code entirely and just use a third-party service?

Yes, for a backend-free form on a static site with a low volume of submissions, that’s enough. Formspree, Netlify Forms, and similar services accept form data directly at the address given in action, with no server-side code at all. The tradeoff is less control over data format, spam protection, and direct CRM integration. Once submission volume grows or you need a pipeline connection, it makes sense to move to a serverless function with your own logic.

Do you need a CAPTCHA if you already have a honeypot field?

In most projects - no. A honeypot field combined with rate limiting and server-side validation covers the bulk of automated spam with no extra click for a real user. CAPTCHA adds friction and lowers form conversion, so it’s worth adding only as a fallback layer - for example, if the honeypot stops being enough because of a targeted attack. Decide based on evidence: start with simple protection, add CAPTCHA only if that protection fails.

How do you send form data straight to a CRM instead of email?

The serverless function that accepts the form data can make an additional HTTP request to the CRM’s API right after validation - that’s what’s called a webhook. Instead of an email, the function creates or updates a contact and deal record directly in the CRM, with the right fields and tags. This approach removes manual data entry and the risk of losing a lead to an email spam filter. The setup depends on the specific CRM - you’ll typically need an API token and knowledge of the target pipeline’s field structure.

How much does maintaining a serverless-function form cost?

The infrastructure side, on most hosts (Netlify, Vercel, Cloudflare), fits within the free tier at low request volumes - the limits are built for thousands of calls a month. The main cost is the time spent building the handler, validation, and spam protection up front, not ongoing operation afterward. A typical project budgets anywhere from a few hours to one or two days of work for this, depending on how complex the CRM integration is.

In short: for a quick hypothesis test, a third-party form-backend service is enough. For a site meant to last, a serverless or edge function with your own validation pays off. Honeypot and rate limiting cover most spam without a CAPTCHA and without hurting conversion. A direct webhook into the CRM is more reliable than email notifications and saves the sales team time.

If you’re building a site on Astro or another static stack and your lead form needs to land directly in a CRM - tell the Exceltic.dev team about it. We’ll map out the architecture and estimate the scope of work.

More articles

All
Get in touch your way
WhatsApp Telegram

Before you go: a free estimate

Describe your task in a few words and we propose a solution, a stack and a quote with timelines.

Three areas with one team: software, web development and CRM implementation. Over 100 projects, and the project is run directly by an engineer, in Russian and English.