Skip to main content
New:Build with AI agents

Gatsby contact forms
without functions.

Let Gatsby serve the page and Form Plume run the form backend: email notifications, dashboard storage, spam filtering, uploads, integrations, and signed webhooks.

Free foreverNo credit cardGatsby endpoint ready in under a minute
src/pages/contact.tsx
const endpoint =
  process.env.GATSBY_FORM_PLUME_ENDPOINT ??
  "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";

async function onSubmit(event) {
  event.preventDefault();

  await fetch(endpoint, {
    method: "POST",
    body: new FormData(event.currentTarget),
  });
}

The full guide

A static-friendly backend for Gatsby contact forms.

Use a Gatsby page or reusable component, keep public endpoint configuration clear, and avoid custom email infrastructure.

  1. 1
    Create your Form Plume accountStart free and give your Gatsby form a hosted endpoint for email, submissions, spam filtering, uploads, integrations, and webhooks.Start free
  2. 2
    Create the form and copy the endpointCopy the endpoint URL from Form Plume. It looks like https://api.formplume.com/f/your-slug
  3. 3
    Connect it inside GatsbyUse a Gatsby page or component, keep the endpoint in a GATSBY_ variable if desired, and submit FormData from the browser. Send one test submission from the real Gatsby app or preview environment and confirm it reaches Form Plume.

You can use this AI prompt to hand the platform-specific wiring to an assistant without accidentally creating a backend.

Gatsby page component

Gatsby builds static pages, but the browser can still submit a form to Form Plume after the page loads.

import * as React from "react";
 
const FORM_PLUME_ENDPOINT =
  process.env.GATSBY_FORM_PLUME_ENDPOINT ??
  "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";
 
export default function ContactPage() {
  const [status, setStatus] = React.useState("idle");
 
  async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setStatus("sending");
 
    const response = await fetch(FORM_PLUME_ENDPOINT, {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(event.currentTarget),
    });
 
    setStatus(response.ok ? "sent" : "error");
  }
 
  return (
    <main>
      <h1>Contact us</h1>
      <form onSubmit={onSubmit}>
        <label htmlFor="email">Email</label>
        <input id="email" type="email" name="email" required />
 
        <label htmlFor="message">Message</label>
        <textarea id="message" name="message" rows={5} required />
 
        <button type="submit" disabled={status === "sending"}>
          {status === "sending" ? "Sending..." : "Send message"}
        </button>
 
        {status === "sent" && <p role="status">Thanks, we got your message.</p>}
        {status === "error" && <p role="alert">Please try again.</p>}
      </form>
    </main>
  );
}

Public environment caveat

Gatsby exposes GATSBY_ variables to browser code. That is acceptable for a Form Plume endpoint, because it is the address your public form posts to.

Do not put SMTP passwords, webhook signing secrets, or private API keys in GATSBY_ variables. Form Plume owns those backend responsibilities for the form.

Static fallback option

For a simpler Gatsby site, use a normal form action and let Form Plume redirect.

<form action="PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE" method="POST">
  <input name="email" type="email" required />
  <textarea name="message" required />
  <input type="hidden" name="_redirect" value="/thanks" />
  <button type="submit">Send message</button>
</form>

This works even before React hydrates. It is a good fit for lightweight marketing pages.

Attachments in Gatsby

Use FormData for uploads and add encType.

<form onSubmit={onSubmit} encType="multipart/form-data">
  <input type="file" name="attachment" accept=".pdf,.png,.jpg" />
  <button type="submit">Send message</button>
</form>

Form Plume stores files separately from email delivery and keeps the submission available in the dashboard.

Gatsby forms often live in reusable components. Keep the endpoint close to the component or pass it as a prop so preview and production builds can use different Form Plume forms.

What Gatsby does not need to own

You do not need a serverless function to send email, a database table for submissions, or browser-side calls to several automation tools.

Form Plume receives the Gatsby submission once, filters spam, sends notifications, stores the record, and triggers integrations or signed webhooks from the backend.

Primary sources

FAQ

Gatsby form questions
before build.

Yes. Gatsby can render the page statically while the browser submits the form to Form Plume. Form Plume sends email and stores the submission.

One line. Zero backend.

The form backend you don’t have to build.

Free foreverNo credit cardSet up in under a minute