Embed Script
The SingleForm embed script adds a QR code widget and autofill capabilities to your existing HTML forms. No framework required — it works with plain HTML, React, Vue, or anything that renders a <form> element.
Installation
Add the script tag before the closing </body> tag on any page with a SingleForm-enabled form:
<script src="https://api.singleform.ai/api/embed.min.js"></script>The script automatically discovers forms on the page by looking for elements with the data-sf-form-id attribute.
Domain Verification
Before the embed script can load on your website, you need to verify your domain in Settings → Domain Verification in the SingleForm dashboard.
- Enter your root domain (e.g.
acme.com) - Add the provided DNS TXT record to your domain
- Click Check Verification — once verified, the embed script will work on that domain and all its subdomains (e.g.
shop.acme.com,staging.acme.com)
Development: localhost is always allowed without verification, so you can develop and test locally without adding a domain.
No domains verified yet? The embed script works on any origin until you verify your first domain. Once you verify a domain, only verified domains (and their subdomains) are allowed.
You can verify multiple domains if your forms are embedded across different sites. Each domain goes through the same DNS TXT verification process.
Basic Example
Here’s a minimal webhook form with SingleForm enabled:
<form
data-sf-form-id="your-form-id"
data-sf-form-type="webhook"
data-sf-button="after:submit"
>
<label for="firstName">First Name</label>
<input type="text" name="firstName" data-sf-field="firstName" />
<label for="email">Email</label>
<input type="email" name="email" data-sf-field="email" />
<button type="submit">Submit</button>
</form>
<script src="https://api.singleform.ai/api/embed.min.js"></script>That’s it. The script will:
- Append a “Fill with SingleForm” button next to your submit button
- Show a QR code widget when the button is clicked (desktop) or open the mobile app (phone)
- Handle the data flow between the mobile app and your form
Form Attributes
These attributes go on the <form> element.
data-sf-form-id (required)
Your form’s unique ID from the SingleForm dashboard.
<form data-sf-form-id="d4e5f6a7-b8c9-4d2e-a1f3-1234567890ab">data-sf-form-type
Controls how submissions are delivered. Defaults to autofill.
| Value | Behavior |
|---|---|
autofill | Fields on your page fill in real-time as the user types on their phone. You control the submit. |
webhook | Data is sent directly from the phone to your webhook endpoint. No page interaction needed. |
<!-- Fields fill live on the page -->
<form data-sf-form-id="..." data-sf-form-type="autofill">
<!-- Data goes straight to your webhook -->
<form data-sf-form-id="..." data-sf-form-type="webhook">data-sf-button
Controls where the “Fill with SingleForm” button appears. When omitted, no button is created (you’d need to call the JavaScript API manually).
| Value | Behavior |
|---|---|
after:submit | Insert the button after your submit button |
before:submit | Insert the button before your submit button |
replace:submit | Replace your submit button entirely |
CSS selector (e.g. #my-slot) | Insert the button into a specific container element |
<!-- Button appears after the submit button -->
<form data-sf-form-id="..." data-sf-button="after:submit">
...
<button type="submit">Submit</button>
<!-- SingleForm button will appear here -->
</form>
<!-- Button placed in a custom container -->
<form data-sf-form-id="..." data-sf-button="#sf-button-slot">
<div id="sf-button-slot"></div>
...
<button type="submit">Submit</button>
</form>data-sf-style
Sets the widget and button theme. Defaults to light.
| Value | Behavior |
|---|---|
light | Light button and widget (for light backgrounds) |
dark | Dark button and widget (for dark backgrounds) |
<form data-sf-form-id="..." data-sf-style="dark">data-sf-short-code
Optional. The form’s 8-character short code, used to generate compact QR codes. If omitted, the script fetches it from the API automatically.
<form data-sf-form-id="..." data-sf-short-code="aB3kM9xQ">Field Attributes
These attributes go on <input>, <select>, and <textarea> elements inside the form.
data-sf-field
Maps a form field to a SingleForm field key. When the user submits from the mobile app, data is matched to your fields by this key.
<input type="text" name="firstName" data-sf-field="firstName" />
<input type="email" name="email" data-sf-field="email" />
<input type="tel" name="phone" data-sf-field="phone" />
<select name="role" data-sf-field="role">
<option value="developer">Developer</option>
<option value="designer">Designer</option>
</select>
<textarea name="message" data-sf-field="message"></textarea>Works with all standard input types including checkboxes, radio buttons, selects, and textareas.
data-sf-meta
Attaches custom metadata to the submission. Use this for hidden values like tracking IDs, campaign sources, or session tokens.
<input type="hidden" data-sf-meta="campaignId" value="spring-2026" />
<input type="hidden" data-sf-meta="referrer" value="homepage" />Metadata values are included in the deep link to the mobile app and passed along with the submission.
Autofill Behavior
When data-sf-form-type="autofill" is set:
- The embed script opens a real-time session between the phone and the browser
- As the user types on their phone, form fields on the page update live
- Filled fields get a brief green pulse animation for visual feedback
- The script triggers
inputandchangeevents on filled fields, so framework-managed forms (React, Vue, etc.) pick up the changes - Your submit button stays in control — the user or staff clicks it when ready
Webhook Behavior
When data-sf-form-type="webhook" is set:
- The user scans the QR code and submits directly from the mobile app
- Data is delivered to your webhook endpoint as a signed POST request
- No fields on the page are filled — the form acts as a QR code trigger
- See Webhook Security for how to verify the signature
Multiple Forms
You can have multiple SingleForm-enabled forms on the same page. Each form gets its own widget and session:
<form data-sf-form-id="form-1" data-sf-form-type="webhook" data-sf-button="after:submit">
...
</form>
<form data-sf-form-id="form-2" data-sf-form-type="autofill" data-sf-button="after:submit">
...
</form>
<script src="https://api.singleform.ai/api/embed.min.js"></script>Only include the script tag once — it discovers all forms on the page automatically.
Dynamic Forms
The embed script watches the DOM for changes using a MutationObserver. If your framework renders forms dynamically (e.g. React, Vue, or a SPA), the script will detect new data-sf-form-id elements and initialize them automatically.
If you need to manually trigger initialization after adding a form to the DOM:
window.SingleForm?.init();Local Development
The embed script automatically allows localhost — no domain verification needed for local testing. Just include the script from the production API:
<script src="https://api.singleform.ai/api/embed.min.js"></script>The widget, QR codes, and real-time autofill all work on localhost out of the box. The only requirement is that your webhook URL must be reachable from the internet for the mobile app to deliver submissions. If your server is running locally, use a tunneling service like ngrok or Cloudflare Tunnel to expose it:
ngrok http 3000
# Use the generated URL as your webhook URL in the SingleForm dashboard
# e.g. https://abc123.ngrok.io/webhooks/singleformWhen you’re ready to deploy, verify your production domain in Settings → Domain Verification and update your webhook URL to your production server.
Full Example
A complete page with a webhook contact form and an autofill registration form:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Site</title>
</head>
<body>
<h2>Contact Us</h2>
<form
data-sf-form-id="your-webhook-form-id"
data-sf-form-type="webhook"
data-sf-button="after:submit"
>
<input type="text" name="firstName" data-sf-field="firstName" placeholder="First Name" />
<input type="text" name="lastName" data-sf-field="lastName" placeholder="Last Name" />
<input type="email" name="email" data-sf-field="email" placeholder="Email" />
<input type="hidden" data-sf-meta="source" value="contact-page" />
<button type="submit">Send</button>
</form>
<h2>Register</h2>
<form
data-sf-form-id="your-autofill-form-id"
data-sf-form-type="autofill"
data-sf-button="after:submit"
>
<input type="text" name="firstName" data-sf-field="firstName" placeholder="First Name" />
<input type="email" name="email" data-sf-field="email" placeholder="Email" />
<input type="text" name="company" data-sf-field="company" placeholder="Company" />
<button type="submit">Register</button>
</form>
<script src="https://api.singleform.ai/api/embed.min.js"></script>
</body>
</html>