Contact form for static site with Web3Forms

No site is complete with a “contact us” form. What is the best way to do it?

Danielle H
4 min readFeb 10, 2023

I recently created my own site, as I wanted to do things that aren’t possible in Medium, like adding p5.js sketches. After some consideration, I decided on a static Jekyll site in GitHub pages. Static sites have no internal logic; they can’t save a user’s data in a form and send it to me. However, no personal site is complete without a “Contact” form (I certainly didn’t want to post my email for all the robots to spam!).

The first thing I tried was using Google Forms and embedding it in my site. This worked perfectly well, but… it was ugly. Google forms don’t let you customize that much, and the result clashed with my site. As the form is embedded using an iFrame, it is difficult to style it using CSS (because of CORS).

I figured there must be other form endpoint suppliers, and indeed there are plenty. Most have a free option with restrictions, you just need to choose what restrictions you can live with :)

After trying a few different providers, I chose Web3Forms, for the following main reasons:

  1. They have a custom redirect after submission. Most providers need a paid account for that, so people who fill out your contact form are redirected out of your site into a generic “Thank you” page. No thanks.
  2. Free hCaptcha integration, that lowers spam considerably.
  3. Awesome docs and support. They sent an email after I joined, they answered questions quickly, and they even offer extra free submissions per month (among other options, I can write a blog post about them 😉)

So how is it done? Easy :)

  1. In Web3Forms, click on “create access key”. Fill in your email. You’ll get the access key by email.
  2. Create an HTML (and optionally JavaScript) form on your site. They provide numerous examples, or create your own. Mine is below, based on their JavaScript example. As I wanted to show users a message after they submitted the form, I couldn’t stay with pure HTML only. You can see this code and the full code of my site in GitHub.
<!--Bootstrap so it looks nice-->
<link href="" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<!--This is for hCaptcha-->
<script src="" async defer></script>
<!--This is for showing the response-->
<script type="text/javascript" src="/js/contact-us.js"></script>

<!--This is the form-->
<div style="width:60%; margin:auto;">
<form id="contact-form" method="POST">
<!--Don't forget to put your access key!-->
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY_HERE" />
<input type="hidden" name="subject" value="new submission in contact" />
<div class="mb-3">
<label for="nameInput" class="form-label">Name</label>
<input type="text" name="name" class="form-control" id="nameInput" placeholder="my name" required>
<div class="mb-3">
<label for="emailInput" class="form-label">Email address</label>
<input type="email" name="email" class="form-control" id="emailInput" placeholder="" required>
<div class="mb-3">
<label for="messageInput" class="form-label">Message</label>
<textarea class="form-control" name="message" id="messageInput" rows="3" required></textarea>
<div class="h-captcha" data-captcha="true"></div>
<div class="mb-3" style="margin-top:10px">
<button type="submit" class="btn btn-danielle">Submit</button>
<div id="form-result"></div>
<!--Kudos to Web3Forms-->
<div>Powered by <a href="">Web3Forms</a></div>

First I import bootstrap, so it looks good. Then I import the hCaptcha script of Web3Forms. Then I create my HTML form. I also added a link to Web3Forms, because they are awesome (I don’t get extra submissions for that, but I like to give credit).

Here is my JavaScript file, to show users the response:

$( document ).ready(function() {

const form = document.getElementById('contact-form');
const result = document.getElementById('form-result');

//on submit, POST to web3Forms and get response
form.addEventListener('submit', function(e) {
const formData = new FormData(form);
const object = Object.fromEntries(formData);
const json = JSON.stringify(object);
result.innerHTML = "Please wait..."
//fetch result
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
body: json
.then(async (response) => {//show response
let json = await response.json();
if (response.status == 200) {
result.innerHTML = json.message;
} else {
result.innerHTML = json.message;

.catch(error => {//show error
result.innerHTML = "Something went wrong!";

.then(function() {//reset form
//make response dissapear after 3 seconds if you wish
setTimeout(() => { = "none";
}, 3000);

And that’s it! Your form is live. You can use other options for spam protection, but in order to enable hCaptcha you need to write them at (at least it was necessary when I joined, it might already be out of beta by now).

You can see the live form in my Contact page. Feel free to say hello and let me know what you think.



Danielle H

I started programming in LabVIEW and Matlab, and quickly expanded to include Android, Swift, Flutter, Web(PHP, HTML, Javascript), Arduino and Processing.