Hugo, Jekyll, and Gatsby are all excellent static site generators. They compile to pure HTML, CSS, and JavaScript — which means they cannot handle form submissions on their own. You need an external form endpoint.
This guide shows how to add a working contact form to each of these generators using Flowqen as the backend. The setup takes under 5 minutes.
How It Works
When a user submits your form, the browser sends a POST request directly to Flowqen's servers. Flowqen stores the submission, sends you a notification, and (optionally) redirects the user back to your site. Your static site generator is never involved in the submission flow.
Hugo — Contact Form
In Hugo, create a partial template at layouts/partials/contact-form.html:
<form
action="https://flowqen.com/api/f/YOUR_FORM_ID"
method="POST"
>
<input type="text" name="name" placeholder="Your name" required />
<input type="email" name="email" placeholder="Email address" required />
<textarea name="message" placeholder="Your message" rows="5" required></textarea>
<input type="hidden" name="_redirect" value="{{ .Site.BaseURL }}thanks/" />
<!-- Honeypot spam trap -->
<input type="text" name="_gotcha" style="display:none" />
<button type="submit">Send message</button>
</form>
Include the partial in any page template:
{{ partial "contact-form.html" . }}
Create a content/thanks.md page so users land somewhere after submission:
---
title: "Message Sent"
---
Thanks! We'll reply within 24 hours.
Jekyll — Contact Form
Create an _includes/contact-form.html file:
<form
action="https://flowqen.com/api/f/YOUR_FORM_ID"
method="POST"
>
<input type="text" name="name" placeholder="Name" required />
<input type="email" name="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required></textarea>
<input type="hidden" name="_redirect" value="{{ site.url }}/thanks" />
<input type="text" name="_gotcha" style="display:none" />
<button type="submit">Send</button>
</form>
Include it in your layout:
{% include contact-form.html %}
Add a thanks.html page at the root:
---
layout: default
title: Thanks
---
<h1>Message received!</h1>
<p>We'll get back to you soon.</p>
Gatsby — Contact Form
Create a React component at src/components/ContactForm.tsx:
import React, { useState } from "react";
export default function ContactForm() {
const [submitted, setSubmitted] = useState(false);
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const data = new FormData(e.currentTarget);
await fetch("https://flowqen.com/api/f/YOUR_FORM_ID", {
method: "POST",
body: data,
headers: { Accept: "application/json" },
});
setSubmitted(true);
}
if (submitted) {
return <p>Thanks! We'll be in touch soon.</p>;
}
return (
<form onSubmit={handleSubmit}>
<input name="name" type="text" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required />
<input name="_gotcha" type="text" style={{ display: "none" }} />
<button type="submit">Send message</button>
</form>
);
}
Import and render in any Gatsby page:
import ContactForm from "../components/ContactForm";
export default function ContactPage() {
return <main><ContactForm /></main>;
}
Eleventy (11ty) — Contact Form
Same approach as Hugo/Jekyll — create an include file and point the form action at your Flowqen endpoint:
<form action="https://flowqen.com/api/f/YOUR_FORM_ID" method="POST">
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<button>Send</button>
</form>
Spam Protection
All examples include a honeypot field (name="_gotcha"). Bots fill it in; real users leave it blank. Flowqen filters any submission where this field has a value. For higher-traffic forms, enable Cloudflare Turnstile from the dashboard — no user friction.
After Submission: What Happens
- You receive an email notification with all field values.
- The submission appears in your Flowqen dashboard.
- Optional: route to Slack, Google Sheets, Notion, Discord, webhook, or your CRM.
FAQ
Can I use this with GitHub Pages?
Yes. GitHub Pages hosts static files — the form POSTs to Flowqen, not to GitHub. Works perfectly.
Does this work with Cloudflare Pages?
Yes. Same reasoning — the form backend is external.
What if I need custom validation before submission?
Add JavaScript validation client-side before calling fetch. Flowqen also validates required fields server-side.
Or skip all this and use FlowQen — 2 lines of code, done.