send.webforms.toRead the docs →

Frameworks and libraries

Add a contact form to Nuxt

Nuxt ships with Nitro, so you can write a server route for form handling - and then you own an SMTP integration, a spam problem and a deployment target that can no longer be static. WebForms lets you skip all three. Post from the component with $fetch, or proxy through a Nitro route if you prefer. Both work, and `nuxt generate` output stays fully static.

Get an endpointRead the docs

Setup

  1. Copy your endpoint

    Create a form in the dashboard and grab its URL.

  2. Submit with $fetch

    Nuxt's built-in $fetch is all you need. No module to install, no runtime config unless you want the endpoint in one place.

  3. Add destinations

    Email, Slack, Telegram, webhooks. Configure them once in the dashboard.

Nuxt examples

Swap in your own endpoint and these run as-is.

Client-side submit with $fetch.

pages/contact.vue
<script setup>
const form = reactive({ name: "", email: "", message: "" });
const pending = ref(false);
const sent = ref(false);
const error = ref(null);

async function onSubmit() {
  pending.value = true;
  error.value = null;

  try {
    await $fetch("https://send.webforms.to/wft_your_key", {
      method: "POST",
      headers: { accept: "application/json" },
      body: form,
    });
    sent.value = true;
  } catch (e) {
    error.value = e.data?.message ?? "Something went wrong.";
  } finally {
    pending.value = false;
  }
}
</script>

<template>
  <p v-if="sent" role="status">Thanks, we got it.</p>
  <form v-else @submit.prevent="onSubmit">
    <input v-model="form.name" required />
    <input v-model="form.email" type="email" required />
    <textarea v-model="form.message" required />
    <button :disabled="pending">{{ pending ? "Sending…" : "Send" }}</button>
    <p v-if="error" role="alert">{{ error }}</p>
  </form>
</template>

Nitro route, if you would rather keep the endpoint server-side.

server/api/contact.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event);

  return await $fetch("https://send.webforms.to/wft_your_key", {
    method: "POST",
    headers: {
      "content-type": "application/json",
      accept: "application/json",
    },
    body,
  });
});

For nuxt generate, a native POST keeps the build fully static.

pages/contact.vue (static)
<template>
  <form action="https://send.webforms.to/wft_your_key" method="POST">
    <input name="name" required />
    <input name="email" type="email" required />
    <textarea name="message" required />
    <input type="hidden" name="_next" value="https://example.com/thanks" />
    <button type="submit">Send</button>
  </form>
</template>

Nuxt form FAQ

No. $fetch straight from the component is enough. A server route is only worth it if you want to add your own logic before forwarding.

Ready to wire up your Nuxt form?

Free for 300 submissions a month. Endpoint in under a minute, no card required.

Start free