Add a Gatsby contact form without a Gatsby Function
A Gatsby contact form doesn't need a Gatsby Function. Write a normal React component, read the access key from a GATSBY_ prefixed variable, and post to FormThunder from the browser. FormThunder stores each submission and emails you. Your site stays pure static HTML, which means it can be deployed to any host.
Updated
The Gatsby code
GATSBY_FORMTHUNDER_KEY=YOUR_ACCESS_KEYimport * as React from "react";
export default function ContactForm() {
const [status, setStatus] = React.useState("idle");
const onSubmit = async (event) => {
event.preventDefault();
const form = event.currentTarget;
setStatus("sending");
const response = await fetch("https://formthunder.com/submit", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify({
...Object.fromEntries(new FormData(form)),
access_key: process.env.GATSBY_FORMTHUNDER_KEY,
}),
}).catch(() => null);
const data = response ? await response.json() : { success: false };
setStatus(data.success ? "sent" : "error");
};
return (
<form onSubmit={onSubmit}>
<label>Name <input name="name" required /></label>
<label>Email <input name="email" type="email" required /></label>
<label>Message <textarea name="message" required /></label>
<button disabled={status === "sending"}>Send</button>
{status === "sent" && <p role="status">Thanks, we got your message.</p>}
{status === "error" && <p role="alert">That didn't send. Please try again.</p>}
</form>
);
}import * as React from "react";
import ContactForm from "../components/contact-form";
export const Head = () => <title>Contact</title>;
export default function ContactPage() {
return (
<main>
<h1>Contact us</h1>
<ContactForm />
</main>
);
}Replace YOUR_ACCESS_KEY with your free key. It's public by design, so it's safe in client code.
Notes for Gatsby
- Gatsby only exposes variables starting with
GATSBY_to browser code, and it needs.env.developmentas well if you test undergatsby develop. - This code never touches
windowduring render, sogatsby buildserver-renders it without errors.fetchonly runs inside the handler. - If you want a no-JavaScript fallback, add
actionandmethodto the form with a hiddenaccess_key, since Gatsby keeps the static HTML.
Or have your AI add it
Connect the MCP server, then ask. The agent creates the form and writes the code for you, and it can send a real test when it's done.
Add a FormThunder contact form to this Gatsby site that emails hello@example.com. Send a test when you're done.Questions
Do I need a Gatsby Function?
No. The key is public by design, so the browser can post directly.
Does this work on Gatsby Cloud alternatives like Netlify?
Yes. It's static output, so it works on any host that serves files.
Get your Gatsby form sending
The free plan covers 250 submissions a month, with MCP, the CLI and the brand kit included.