CMS
WordPress form handling without a backend
Most WordPress form plugins store submissions in your own database and email through your host - which means you own the personal data, the spam, and the GDPR exposure. If you would rather not, you can embed a plain HTML form that posts to Formward, an EU-hosted form backend, and skip the plugin's data store entirely. The submissions live in the EU, not in wp_postmeta.
The cleanest route is a Custom HTML block (Gutenberg) or a Classic Editor HTML view: paste the markup below and you are done. If you prefer a shortcode, register a tiny one in your theme's functions.php that returns the same HTML, so editors can drop [formward_contact] into any page.
EU-hosted · Run WordPress wherever you like while contact data is collected and stored in Sweden - an easy GDPR win without a heavyweight forms plugin.
The WordPress example
Copy this into your project and replace <FORM_ID> with the id of a form you create in the Formward dashboard.
html
<!-- Paste into a Custom HTML block, or return from a shortcode. -->
<form action="https://forms.formward.eu/f/<FORM_ID>" method="POST">
<p>
<label>Email<br />
<input type="email" name="email" required />
</label>
</p>
<p>
<label>Message<br />
<textarea name="message" required></textarea>
</label>
</p>
<!-- Honeypot: leave empty. -->
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off"
style="display:none" aria-hidden="true" />
<p><button type="submit">Send</button></p>
</form>
<!-- Optional shortcode - add to your theme's functions.php: -->
<?php
function formward_contact_shortcode() {
ob_start(); ?>
<form action="https://forms.formward.eu/f/<FORM_ID>" method="POST">
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off"
style="display:none" aria-hidden="true" />
<button type="submit">Send</button>
</form>
<?php return ob_get_clean();
}
add_shortcode("formward_contact", "formward_contact_shortcode");
?>Success and error handling
- A plain HTML POST needs no JavaScript: WordPress serves the page, the browser submits to Formward, and Formward returns a 302 redirect (or your thank-you page).
- Keep the form in a Custom HTML block - the visual editor will not strip the markup the way it can with pasted-in code elsewhere.
- Because nothing is stored in WordPress, a database breach or a vulnerable plugin cannot leak the form submissions; they only exist in Formward.
Spam protection
Every example above includes the _gotcha honeypot field. It is hidden from real users and must stay empty. When a bot fills it, Formward files the submission as spam and still answers with a normal success response, so the bot learns nothing and nothing reaches your inbox. Rate limits and the origin allowlist are checked on Formward's side as well. For a stricter gate, switch on Cloudflare Turnstile in the form's settings and add the widget; it adds a cf-turnstile-response field that Formward verifies on receipt. Turnstile is optional, and Cloudflare is a US provider, listed as such in the sub-processor register. The spam docs have the widget markup.
The JSON response
A standard POST gets a 302 redirect (or your thank-you page). Send the Accept: application/json header - as every fetch() example above does - and Formward returns JSON instead:
HTTP/1.1 200 OK
Content-Type: application/json
{ "ok": true, "id": "3f2a9c1e-...", "files": 0, "success": { "title": "Thank you!", ... } }files is the number of uploaded files stored and success carries the confirmation text from the form's settings. When you set a redirect URL for the form, the reply also has a redirect field your code can send the visitor to. On failure the body is { ok: false, error } with a 4xx status: 422 when required consent is missing or a field is too long, 403 when a Turnstile check fails, 429 for too many submissions from one address, 402 when the account is over its plan limit. See responses and redirects for the full table and the AJAX docs for CORS.
Other frameworks
Collect your first WordPress submission
Create a form, paste the snippet, and keep every submission in the EU. GDPR-clean from the first POST.