how-to
How to Add a Contact Form to a Static Website (The Complete Guide)
Everything you need: why static sites need a form backend, step-by-step setup with code you can copy, spam protection, and customization for any use case.
Last updated: March 2026
You built a fast, secure static website - but now you need visitors to reach you. The problem? Static sites don’t have server-side code to process form submissions. No PHP, no Node.js, no database.
So how do you add a working contact form to a static website?
This guide walks you through everything: why static sites need a form backend, how to set one up step-by-step (with code you can copy), how to protect against spam, and how to customize your form for any use case. Whether you’re running a portfolio on GitHub Pages, a blog on Hugo, or a business site on Netlify - you’ll have a fully functional contact form by the end.
Why Static Websites Can’t Process Forms on Their Own
A static website is made up of pre-built HTML, CSS, and JavaScript files. When someone visits your site, the server simply delivers those files as-is. There’s no code running on the server to receive data, process it, or send an email.
This is what makes static sites so great: they’re fast, cheap to host, and virtually immune to server-side security vulnerabilities. Platforms like GitHub Pages, Netlify, Vercel, Cloudflare Pages, and Amazon S3 can host them for free or near-free.
But it also means that when a visitor fills out a contact form and clicks “Submit,” there’s nothing on the server to catch that data.
Traditional dynamic websites (built with WordPress, Django, Rails, etc.) handle this with server-side scripts. The form data goes to the server, a script processes it, and you get an email. Static sites skip that entire layer - which is usually a benefit, until you need a form.
The mailto: Link Problem
The most common workaround is to slap a mailto: link on the page. This has real drawbacks:
It exposes your email to spam bots. Any email address in your HTML source code will be scraped by crawlers, leading to a flood of junk mail.
It depends on the visitor’s email client. If someone hasn’t configured a mail client in their browser, clicking a mailto: link does nothing - or worse, opens an app they don’t use.
It looks unprofessional. Visitors expect to fill out a form directly on your website, not get bounced to their email app. A proper contact form increases engagement and gives you control over what information you collect.
The Solution: A Form Backend Service
The cleanest way to add a contact form to a static website is to use a form backend service (also called a form endpoint service). Here’s the concept in plain terms:
- You build your HTML form like normal
- Instead of pointing the form’s
actionto your own server, you point it to the form service’s URL - When a visitor submits the form, the data goes to the service
- The service processes the submission and delivers it to your email inbox
You get a fully working contact form. Your site stays static. No backend code required.
Services like Un-static Forms are built specifically for this. You register a form endpoint, add it to your HTML, and submissions arrive in your email - often within seconds. You can see the full list of features Un-static offers.
Form Service vs. Serverless Function vs. mailto: - Which Approach Fits?
A form backend service isn’t the only way to handle submissions on a static site. Before we dive into the setup, it’s worth knowing all three approaches and their trade-offs:
Write your own serverless function. Platforms like Netlify Functions, Cloudflare Workers, Vercel Functions, and AWS Lambda let you run small pieces of server code without managing a server. You write a function that receives the form POST, validates it, and sends an email through a transactional provider like SES, Mailgun, or Resend.
This works, but you’ve now taken on real responsibilities: writing and maintaining the code, setting up and paying for an email-sending service, keeping API keys secret, and - the part most people underestimate - building your own spam protection. An unprotected form endpoint gets discovered by bots within days, and your email-provider reputation suffers for it. What looked like a free afternoon project becomes a small service you operate forever.
Use a mailto: link. Zero setup, but as covered above: it exposes your e-mail address to scrapers, depends on the visitor having a configured mail client, and gives you no formatting, validation, or spam control. Fine for a hobby page, not for anything you rely on.
Use a form backend service. You trade a small dependency on a third party for not having to build, secure, and babysit any of the above. Spam filtering, delivery, retries, and the endpoint itself are someone else’s job.
| mailto: link | Serverless function | Form service | |
|---|---|---|---|
| Setup time | seconds | hours | ~2 minutes |
| Code to maintain | none | yours, forever | none |
| Spam protection | none | build it yourself | built in |
| E-mail address hidden | no | yes | yes |
| Works without JavaScript | yes | usually | yes |
| Extra accounts needed | none | host + email provider | one |
If you enjoy operating infrastructure, a serverless function is a fine weekend project. If you just want messages from your visitors to reach your inbox, a form service gets you there in the time it takes to copy and paste - which is exactly what the rest of this guide covers.
Step-by-Step: Adding a Contact Form with Un-static Forms
Let’s build a real contact form from scratch. We’ll use Un-static Forms because it offers a generous free plan, supports all static site generators, and includes spam protection out of the box.
Step 1: Create Your Form Endpoint
Head to un-static.com and register a form endpoint. You can do this two ways:
- With an account (recommended): Sign up for free, then create a form endpoint from your dashboard. You’ll get access to all features including reCAPTCHA, webhooks, and submission history.
- Without an account: Un-static offers “unlinked” forms that don’t require registration. You provide your email, and they send you an endpoint reference. This gives you up to 25 submissions per month - great for quick testing.
Either way, you’ll receive a unique endpoint reference - a code that identifies your form.
Step 2: Build Your HTML Form
Here’s a clean, minimal contact form you can drop into any static website:
<form method="post" action="https://forms.un-static.com/forms/YOUR_ENDPOINT_REFERENCE">
<label for="name">Name</label>
<input type="text" id="name" name="name" placeholder="Your name" required>
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="Your email address" required>
<label for="message">Message</label>
<textarea id="message" name="message" rows="6" placeholder="How can we help?" required></textarea>
<button type="submit">Send Message</button>
</form>
Replace YOUR_ENDPOINT_REFERENCE with the endpoint code you received in the previous step. That’s it - you now have a working static site contact form.
A few important details about this code:
- The
method="post"attribute tells the browser to send the data as a POST request, which is the standard for form submissions. - The
actionattribute points to Un-static’s servers, where your submission will be processed and forwarded to your email. - Each input’s
nameattribute (likename,email,message) determines how the field appears in your email notification. Un-static passes through any field names you use. - The
requiredattribute provides basic client-side validation, preventing empty submissions.
Step 3: Test Your Form
Open your site (locally or deployed), fill in the form with real information, and click “Send.” Check your email inbox - you should receive the submission within a few seconds.
If you’re using Un-static for the first time, you may need to verify your email address. Check for a verification email and click the confirmation link. After that, all submissions will arrive normally.
Step 4: Add a Thank-You Page (Recommended)
After submission, visitors are typically redirected to a confirmation page. You can customize this by creating a simple thank-you.html page on your site:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thank You</title>
</head>
<body>
<h1>Thanks for reaching out!</h1>
<p>We received your message and will get back to you shortly.</p>
<a href="/">Back to homepage</a>
</body>
</html>
Many form backend services let you specify a redirect URL. With Un-static, the redirect behavior depends on your configuration - check your dashboard settings to point users to your custom page after submission.
Adding Your Contact Form to Popular Static Site Generators
The HTML above works everywhere, but here’s how to integrate it with the most common static site setups.
Hugo
Hugo is one of the most popular static site generators. To add your contact form, create a new content file at content/contact.md:
---
title: "Contact"
date: 2026-03-20
---
We'd love to hear from you. Fill out the form below and we'll get back to you as soon as possible.
<form method="post" action="https://forms.un-static.com/forms/YOUR_ENDPOINT_REFERENCE">
<input type="text" name="name" placeholder="Your name" required>
<input type="email" name="email" placeholder="Your email" required>
<textarea name="message" rows="6" placeholder="Your message" required></textarea>
<button type="submit">Send</button>
</form>
Hugo renders Markdown to HTML, and raw HTML within Markdown files is passed through as-is (make sure unsafe = true is set in your Hugo config for the Goldmark renderer if you’re using recent Hugo versions). For a more detailed walkthrough, see our Hugo contact form guide.
Jekyll (GitHub Pages)
Jekyll sites on GitHub Pages work the same way. Create a contact.html or embed the form in any page:
---
layout: default
title: Contact
---
<h1>Contact Us</h1>
<form method="post" action="https://forms.un-static.com/forms/YOUR_ENDPOINT_REFERENCE">
<input type="text" name="name" placeholder="Your name" required>
<input type="email" name="email" placeholder="Your email" required>
<textarea name="message" rows="6" placeholder="Your message" required></textarea>
<button type="submit">Send</button>
</form>
Since GitHub Pages serves static files only, a form endpoint service is the standard approach for handling contact forms on GitHub-hosted sites. See our dedicated GitHub Pages contact form guide for more details.
Gatsby, Next.js (Static Export), and Eleventy
For JavaScript-based static generators, the HTML form approach works identically. Just embed the form HTML in your JSX, template, or Nunjucks file. The action attribute handles everything - no JavaScript required on your end.
If you prefer a JavaScript-powered submission (for example, to show a success message without a page reload), see the AJAX section below.
Protecting Your Contact Form Against Spam
Spam is the #1 concern for any publicly accessible form. Without protection, bots will flood your inbox within days. Here are the most effective approaches, ranked from simplest to most robust.
Honeypot Fields
A honeypot is a hidden form field that real users can’t see but bots will fill in. If the field contains data on submission, you know it’s a bot.
<!-- Hidden from real users via CSS -->
<div style="display: none;">
<input type="text" name="website" tabindex="-1" autocomplete="off">
</div>
This is lightweight and doesn’t affect user experience. Many form backend services, including Un-static, support honeypot detection automatically.
reCAPTCHA
Google’s reCAPTCHA adds a verification step to confirm the submitter is human. Un-static Forms supports reCAPTCHA integration - you can configure it from your dashboard by adding your own reCAPTCHA site key and secret key.
With reCAPTCHA v2, users click a checkbox (“I’m not a robot”). With reCAPTCHA v3, verification happens invisibly in the background and assigns a score. Both work with static sites when paired with a form backend service. We have a step-by-step reCAPTCHA setup guide if you want detailed instructions.
Rate Limiting
Good form backend services enforce rate limits automatically, preventing any single IP from flooding your form with hundreds of submissions. This is a server-side protection that you get for free with services like Un-static - no configuration needed on your end.
Combining Multiple Layers
For the best protection, combine approaches. Use a honeypot field for frictionless bot filtering, add reCAPTCHA for more determined spam, and rely on your form backend’s built-in rate limiting as a safety net. This multi-layered approach stops the vast majority of spam without annoying legitimate visitors.
Sending Form Submissions via AJAX (No Page Reload)
A standard HTML form submission redirects the visitor to a new page. If you’d rather show a success message on the same page (a smoother experience), you can submit the form using JavaScript.
Here’s a vanilla JavaScript example - no jQuery or frameworks needed:
<form id="contact-form">
<input type="text" name="name" placeholder="Your name" required>
<input type="email" name="email" placeholder="Your email" required>
<textarea name="message" rows="6" placeholder="Your message" required></textarea>
<button type="submit">Send Message</button>
</form>
<div id="form-status" style="display: none;"></div>
<script>
document.getElementById('contact-form').addEventListener('submit', function(e) {
e.preventDefault();
const form = e.target;
const status = document.getElementById('form-status');
const data = new FormData(form);
fetch('https://forms.un-static.com/forms/YOUR_ENDPOINT_REFERENCE', {
method: 'POST',
body: data
})
.then(response => {
if (response.ok) {
status.textContent = 'Message sent! We\'ll get back to you soon.';
status.style.display = 'block';
form.reset();
} else {
status.textContent = 'Something went wrong. Please try again.';
status.style.display = 'block';
}
})
.catch(error => {
status.textContent = 'Network error. Please check your connection.';
status.style.display = 'block';
});
});
</script>
This approach works with Un-static’s AJAX endpoint. Append /ajax to your endpoint URL if required by your service configuration. The user stays on the same page and sees a confirmation message - a much better experience for single-page sites and portfolios. For a deeper dive, check out our AJAX contact form guide.
Customizing Your Contact Form
Adding More Fields
Un-static and similar services pass through any form fields you include. Want to add a phone number, company name, or subject dropdown? Just add the HTML:
<label for="phone">Phone (optional)</label>
<input type="tel" id="phone" name="phone" placeholder="Your phone number">
<label for="subject">Subject</label>
<select id="subject" name="subject">
<option value="General Inquiry">General Inquiry</option>
<option value="Support">Support</option>
<option value="Partnership">Partnership</option>
</select>
Every field with a name attribute will appear in your email notification.
Styling Your Form with CSS
The HTML examples above are intentionally unstyled so they work anywhere. Here’s a minimal CSS snippet to make your form look polished:
form {
max-width: 600px;
margin: 2rem auto;
}
form label {
display: block;
margin-top: 1rem;
font-weight: 600;
}
form input,
form textarea,
form select {
width: 100%;
padding: 0.75rem;
margin-top: 0.25rem;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
}
form input:focus,
form textarea:focus {
outline: none;
border-color: #0066cc;
box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.2);
}
form button {
margin-top: 1.5rem;
padding: 0.75rem 2rem;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
form button:hover {
background: #0052a3;
}
If you’re using a CSS framework like Tailwind CSS or Bootstrap, you can style the form with utility classes instead. Un-static provides ready-made Bootstrap form templates you can copy and paste directly.
File Uploads
Some form backend services support file attachments. This is useful for support forms where users need to share screenshots or documents. Check whether your chosen service supports file uploads and what the size limits are - this varies significantly between providers.
Webhooks and Integrations
Beyond email notifications, many form services can forward submissions to other tools. Un-static supports webhooks and Zapier integration, which means you can route form data to Slack, Google Sheets, a CRM, or virtually any other application. This is especially valuable for businesses that want form submissions to trigger automated workflows.
Comparing Your Options: Form Backend Services for Static Sites
There are several form endpoint services available. Here’s what to consider when choosing one:
Free tier limits vary widely. Some services offer 50 submissions per month on free plans, while others offer more. Un-static Forms includes a free tier with 50 submissions per month and access to all features - compare all plans to see what fits your needs. If you’re weighing specific providers, we’ve compared six services head-to-head in our Formspree alternatives breakdown.
Spam protection is critical. Look for services that include reCAPTCHA or similar verification, honeypot support, and server-side filtering. Un-static includes built-in spam filtering with every plan.
No JavaScript required is a key advantage. The best static form services work with plain HTML - you just set the action attribute and you’re done. Services that require embedding JavaScript widgets add complexity and may affect page load times.
Data privacy matters. Make sure your chosen service handles data responsibly, especially if you’re collecting information from visitors in the EU (GDPR) or other regulated regions.
Reliability and uptime are worth investigating. A contact form that doesn’t work is worse than no form at all. Choose a service with a solid track record.
Common Issues and Troubleshooting
Form submissions aren’t arriving. First, check your spam/junk folder. Then verify that your endpoint reference is correct in the action attribute. If you’re using Un-static for the first time, make sure you’ve confirmed the verification email.
Form shows a CORS error in the console. This typically happens when using AJAX submissions. Make sure you’re using the correct AJAX endpoint URL and that the form backend service supports cross-origin requests (Un-static does).
reCAPTCHA isn’t working. Double-check that your site key and secret key are correctly configured in both your HTML and your form backend dashboard. Also ensure the reCAPTCHA script is loading (check your browser’s network tab).
Visitors see a blank page after submitting. This means the redirect after submission isn’t configured. Set up a thank-you page and configure the redirect URL in your form backend’s settings.
Frequently Asked Questions
Can I add a contact form to a static site without JavaScript?
Yes. With a form backend service like Un-static, you only need HTML. The form uses a standard POST submission - no JavaScript required. JavaScript is optional if you want features like AJAX submission or client-side validation.
Does this work with GitHub Pages? Absolutely. GitHub Pages serves static files, so you can’t run server-side code. A form endpoint service handles the processing externally. Just add the form HTML to your repository and deploy.
Is my email address exposed to visitors? No. Your email address is stored securely on the form backend’s server. Visitors only see the endpoint URL in the HTML - never your actual email address.
How much does a form backend cost? Most services offer free tiers. Un-static’s free plan includes 50 submissions per month with full feature access. Paid plans start at $9/month for higher volumes. For a low-traffic portfolio or small business site, the free plan is usually more than enough. See the full plan comparison for details.
Can I use this for more than just contact forms?
Yes. Any HTML form that collects data - feedback surveys, event RSVPs, quote requests, newsletter signups - can use a form endpoint service. If your form has input fields with name attributes, it’ll work. Check our FAQ for more common questions, or browse all our integration guides.
Wrapping Up
Adding a contact form to a static website doesn’t require abandoning the simplicity and performance that made you choose a static site in the first place. With a form backend service, you keep your site static while gaining the ability to collect form submissions, protect against spam, and integrate with your existing tools.
The setup takes just a few minutes: register an endpoint, paste a few lines of HTML, and you’re live. Whether you’re building with Hugo, Jekyll, plain HTML, or any other static tool - a form endpoint makes the “contact us” problem disappear.
Ready to add a contact form to your static site? Get started with Un-static Forms - it’s free, takes under two minutes, and works with any static website.