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 freeFree 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.