Skip to content
FFormhook
All guides

Guide

Hugo contact form (no backend needed)

Hugo is a static site generator with no runtime, so a Hugo contact form is just a plain HTML form embedded in a Hugo template. Drop the snippet into a layout or partial, swap in your Formhook API key, and you're done.

The snippet

contact.Hugo
{{/* layouts/contact.html — plain HTML inside Hugo's template syntax */}}
<form action="https://formhook.app/f/YOUR_API_KEY" method="POST">
  <input type="email" name="email" placeholder="Email" required />
  <textarea name="message" placeholder="Message" required></textarea>
  <input type="text" name="_gotcha" tabindex="-1" autocomplete="off" hidden />
  <input type="hidden" name="_redirect" value="{{ "/thanks" | absURL }}" />
  <button type="submit">Send</button>
</form>

How it works

The snippet works inside any Hugo template — a layout, a partial, or a single-page template. Hugo passes through the raw HTML at build time, so the action attribute points at formhook.app/f/YOUR_API_KEY in the published HTML. The {{ "/thanks" | absURL }} bit is Hugo's templating: it expands at build time to an absolute URL within your site, which is what Formhook needs for the _redirect validation.

What happens next

  • Submission lands in your Formhook dashboard within a second.
  • Push notification fires on every device you've enabled it on.
  • Reply directly from the dashboard (Pro and above) — useful when client work means several Hugo sites pointing at one Formhook account.

Ship your Hugo contact form today.

Sign up free, create a form, paste the API key. Five minutes.

Start free

Free tier: 5 forms · 250 submissions/month · No credit card.

Hugo contact form — FAQ

Does this work with the `hugo` static build and `hugo deploy`?
Yes. The form is plain HTML in the built output. Hugo doesn't run server-side, so the form POSTs directly to Formhook from the browser.
Can I use Hugo's i18n features with the contact form?
Yes — the form itself is markup, so localised labels work the same as any other Hugo template. Use Hugo's i18n functions on the placeholder text and field labels.
How do I avoid hardcoding the API key in every template?
Put the key in your site's params (config.toml or hugo.yaml) and reference it as {{ .Site.Params.formhookKey }} in the template. Treat it as a public endpoint identifier — Formhook's per-form rate limits and Turnstile toggle do the actual protection.

Guides for other frameworks