Copy, paste, ship.
HTML form examples
Every snippet below works as-is once you swap in your endpoint key. Get one by creating a free account.
HTML contact form example
<form action="https://send.webforms.to/wft_your_key" method="POST">
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<!-- optional: redirect after success -->
<input type="hidden" name="_next"
value="https://example.com/thanks" />
<!-- optional: honeypot, catches bots -->
<input type="text" name="_gotcha"
style="display:none" tabindex="-1" />
<button type="submit">Send</button>
</form>Why this works: Works with JavaScript switched off: the browser does the POST, _next sends the visitor to your own page afterwards, and the honeypot sits in the markup where bots fill it and people never see it.
React contact form example
export function ContactForm() {
const [status, setStatus] = useState<"idle" | "sending" | "sent" | "error">("idle");
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setStatus("sending");
const res = await fetch("https://send.webforms.to/wft_your_key", {
method: "POST",
headers: { accept: "application/json" },
body: new FormData(e.currentTarget),
});
setStatus(res.ok ? "sent" : "error");
}
if (status === "sent") return <p>Thanks, we got it.</p>;
return (
<form onSubmit={onSubmit}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<button disabled={status === "sending"}>Send</button>
</form>
);
}Why this works: Submits in the background and asks for JSON with the Accept header, so the page stays put and the component shows its own confirmation. FormData reads every named field, so a new field is one line of JSX.
JavaScript contact form example
const res = await fetch("https://send.webforms.to/wft_your_key", {
method: "POST",
headers: {
"content-type": "application/json",
accept: "application/json",
},
body: JSON.stringify({
name: "Ada Lovelace",
email: "ada@example.com",
message: "JSON works too.",
}),
});
const data = await res.json();
console.log(data); // { ok: true, id: "sub_...", ... }Why this works: For when there is no form at all, a script or a scheduled job reporting in. Sending JSON is accepted as readily as a form post, and the Accept header returns a result you can check in code.
cURL contact form example
curl -X POST https://send.webforms.to/wft_your_key \
-H "content-type: application/json" \
-d '{
"name": "Ada Lovelace",
"email": "ada@example.com",
"message": "Hello from the command line"
}'Why this works: The fastest way to prove the endpoint before writing any frontend: if this reaches your inbox, the form will too.
Vue contact form example
<script setup>
import { ref } from "vue";
const status = ref("idle");
async function onSubmit(e) {
status.value = "sending";
const res = await fetch("https://send.webforms.to/wft_your_key", {
method: "POST",
headers: { accept: "application/json" },
body: new FormData(e.target),
});
status.value = res.ok ? "sent" : "error";
}
</script>
<template>
<p v-if="status === 'sent'">Thanks, we got it.</p>
<form v-else @submit.prevent="onSubmit">
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<button :disabled="status === 'sending'">Send</button>
</form>
</template>Why this works: @submit.prevent stops the reload and FormData reads the form's own fields, so the template stays plain HTML with no v-model wiring for values you only need to send.
WordPress contact form example
<!-- Add a Custom HTML block and paste: -->
<form action="https://send.webforms.to/wft_your_key" method="POST">
<input type="text" name="name"
placeholder="Your name" required />
<input type="email" name="email"
placeholder="Your email" required />
<textarea name="message"
placeholder="Message" required></textarea>
<input type="hidden" name="_next"
value="https://yoursite.com/thank-you/" />
<button type="submit">Send</button>
</form>
<!-- No plugin needed. Works with any theme. -->Why this works: No plugin means no PHP runs on submit and nothing is written to your database, so there is nothing to update and nothing to lose in a migration.
Want the full walkthrough for your stack: setup steps, gotchas and framework-specific patterns? Browse the integration guides.
Special fields
Optional hidden inputs that change behaviour. Everything else you send becomes submission data.
_nextURL to redirect to after a successful browser submit_gotchaHoneypot. If a bot fills it, the submission is silently dropped_subjectOverrides the subject line of email notifications
Ready to wire up your form?
Free for 300 submissions a month. Endpoint in under a minute.
Start free