Add a form to Nuxt with server routes
Use a Nitro server route to keep the Public Key server-side, then post to it from any Nuxt page. The built-in $fetch makes the call two lines.
- Free plan
- No plugin to install
- Set up in minutes
Nuxt in three steps.
- 1
Create a form and copy its Public Key
Sign up and copy the Public Key into runtimeConfig in nuxt.config. Server-side values never reach the client bundle.
- 2
Add a server route that forwards
server/api/submit.post.js reads the body, builds the form-specific URL with the runtime-configured Public Key, and relays to the endpoint.
- 3
Call it with $fetch
From any page or component, await $fetch("/api/submit", { method: "POST", body }). The composable handles JSON both ways.
Copy this into Nuxt.
Swap in your form’s key and submissions start landing in your inbox.
// server/api/submit.post.js
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const { formPublicKey } = useRuntimeConfig();
return $fetch("https://api.surveyowl.co/v1/submit/" + encodeURIComponent(formPublicKey), {
method: "POST",
body,
});
});
// any page or component
await $fetch("/api/submit", {
method: "POST",
body: { email, message },
});What people build with it.
Contact forms on Nuxt marketing sites rendered universal or static.
Teams that want the Public Key server-side without running a separate backend.
Nuxt apps already using server routes for their own API calls.
Nuxt forms, answered.
1. Create a form and copy its Public Key: Sign up and copy the Public Key into runtimeConfig in nuxt.config. Server-side values never reach the client bundle. 2. Add a server route that forwards: server/api/submit.post.js reads the body, builds the form-specific URL with the runtime-configured Public Key, and relays to the endpoint. 3. Call it with $fetch: From any page or component, await $fetch("/api/submit", { method: "POST", body }). The composable handles JSON both ways.
Nuxt ships a server layer, so the best pattern here is the proxied one: a server/api handler holds the Public Key in a runtime config var, and pages call it with $fetch. Static or universal rendering both work, since the browser only ever talks to your own route.
Set formPublicKey under runtimeConfig (not public runtimeConfig) so it stays on the server. During static generation the call from the browser still works because it targets your Nitro route, which runs when the site is deployed.