Framer
Where the code goes
Insert an Embed component, choose HTML, and paste the generated form. Framer keeps the script, so the form submits in place.
The origin to allow
Allow your Framer site's domain (custom domain and framer.app / framer.website address) as allowed origins.
Thank-you handling
The thank-you message appears in place; point a success redirect at a Framer page if you want a full page.
File uploads
Add a file field to the definition and regenerate the embed to accept uploads.
The code
Generated from the form’s fields (plain HTML with a small script). Replace YOUR_FORM_ID with your form’s public id, then restyle it; keep the field names and the hidden _gotcha honeypot.
<form id="formto-form" action="https://api.formto.io/f/YOUR_FORM_ID" method="post" enctype="application/x-www-form-urlencoded">
<h2>Contact</h2>
<p>
<label for="formto-name">Name</label>
<input type="text" id="formto-name" name="name" required>
</p>
<p>
<label for="formto-email">Email</label>
<input type="email" id="formto-email" name="email" autocomplete="email" required>
</p>
<p>
<label for="formto-message">Message</label>
<textarea id="formto-message" name="message" rows="5" required></textarea>
</p>
<!-- Spam trap: people never see or fill this field. -->
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" aria-hidden="true" style="position:absolute;left:-10000px">
<button type="submit">Send</button>
<p data-formto-status role="status" aria-live="polite"></p>
</form>
<script>
// Progressive enhancement: without JavaScript the form above posts natively.
;(function () {
var form = document.getElementById('formto-form')
if (!form || !window.fetch || !window.FormData) return
form.addEventListener('submit', function (event) {
event.preventDefault()
var status = form.querySelector('[data-formto-status]')
var button = form.querySelector('button[type=submit]')
button.disabled = true
fetch(form.action, { method: 'POST', body: new FormData(form), headers: { Accept: 'application/json' } })
.then(function (res) {
return res.json().then(function (body) {
if (!res.ok || !body.success) throw new Error(body.error || 'Something went wrong. Please try again.')
form.reset()
status.textContent = 'Thanks, we got it.'
})
})
.catch(function (err) {
status.textContent = err.message || 'Could not send. Please try again.'
})
.finally(function () {
button.disabled = false
})
})
})()
</script>
Other platforms: Plain HTML, React, Next.js, Astro, WordPress, Squarespace, Webflow, Wix, Shopify.