Embed a form
One script and one element put a OneForm form on any website: inline, full page, in a popup or slider, behind a button, or as a chat bubble. Voice forms have their own launcher, a glowing orb.
Snippet builder
Choose how the form appears and the code updates for each kind of website. In OneForm, the same code is under a form's Share tab, with your form's slug and colours already in. Only published forms load for visitors.
Sits inside your page, like a section. Grows to fit.
<div data-oneform="your-form" data-of-type="inline" style="width:100%"></div><script src="https://app.oneform.si/embed.js" async></script>- If the site sets a Content-Security-Policy, allow https://app.oneform.si in script-src and frame-src.
Embed types
| Type | What it does | Forms |
|---|---|---|
inlineStandard | Sits inside your page, like a section. Grows to fit. | Typed, Voice |
fullpageFull page | Takes over the whole page — for a dedicated form page. | Typed, Voice |
popupPopup | Opens in the middle of the screen — on load, on exit or after scrolling. | Typed |
sliderSlider | Slides in from the side of the screen. | Typed |
popoverChat bubble | A round button in the corner opens the form in a small window. | Typed |
sidetabSide tab | A tab on the edge of the screen that opens a slider. | Typed |
buttonButton | A button on your page that opens the form in a popup or slider. | Typed, Voice |
orbFloating orb | A small glowing orb in the corner. A tap opens the conversation. | Voice |
Voice forms offer floating orb, inline card, button → popup, full page. A conversation always opens in a popup, never a slider.
Data attributes
Everything is set with attributes on the element; the loader at https://app.oneform.si/embed.js reads them. Load the script once per page, however many forms the page has.
| Attribute | Values | What it does |
|---|---|---|
data-oneform | the form's slug | Required. Every element with it is turned into an embed when the loader runs (and again on window.OneForm.scan()). |
data-of-type | inline | fullpage | popup | slider | popover | sidetab | button | orb | How the form is shown. Default inline. |
data-of-voice | true | A voice form: dark panels, and the conversation always opens in a popup. |
data-of-hide-welcome | true | Skips the welcome screen (typed forms). |
data-of-transparentStandard, Full page | true | No background behind the form, so your page shows through. |
data-of-heightStandard | auto | <pixels> | auto (the default) grows and shrinks with the form, between 320 and 4,000 pixels. A number fixes the height. |
data-of-lang | en | fr | es | The language the form opens in. |
data-of-hidden | key1,key2 | Page URL parameters passed through to the form as hidden fields (UTM tags always are). |
data-of-hidden-values | key=value;key2=value2 | Fixed hidden-field values for this embed, for example the page or campaign it sits on. |
data-of-title | text | The frame's accessible title. Default Form. |
data-of-button-textButton, Side tab, Chat bubble, Floating orb | text | The button or side tab's text; the accessible label of the chat bubble and the orb. |
data-of-button-colorButton, Side tab, Chat bubble | #rrggbb | The button's colour. The text on it turns dark or light to stay readable. |
data-of-button-sizeButton | sm | md | lg | The button's size. Default md. |
data-of-open-asButton | popup | slider | What the button opens. Default popup. |
data-of-positionSlider, Side tab, Floating orb, Button | left | right | Which side the slider, side tab or orb sits on. Default right. |
data-of-openPopup, Slider, Chat bubble, Side tab | click | load | exit | scroll:<percent> | delay:<seconds> | Opens by itself: on load, on exit intent (after 15 seconds on touch screens), after scrolling a share of the page, or after a delay. |
data-of-open-oncePopup, Slider, Chat bubble, Side tab | true | An automatic open happens once per browser (remembered in localStorage). |
data-of-auto-closePopup, Slider, Chat bubble, Side tab, Button, Floating orb | <milliseconds> | Closes the panel this long after the form is submitted. |
data-of-colorsFloating orb | #a,#b,#c | The orb's three colours. A published form's current colours replace them once loaded. |
data-of-preview | true | Used by OneForm's own preview: loads drafts for signed-in admins and saves nothing. |
A popup or slider element with content of its own (a button or link inside it, say) opens the form when clicked, so your own markup can be the trigger.
JavaScript API
The loader adds window.OneForm. It runs once however often the script is included, and Escape closes an open form.
// After /embed.js has loaded:window.OneForm.open("your-form"); // open a popup, slider, chat bubble or side tab by its slugwindow.OneForm.close(); // close whatever is openwindow.OneForm.scan(); // look for new <div data-oneform> elements (single-page apps) window.OneForm.on("submitted", (e) => { // e.slug, e.endingId. Never the answers. console.log("Submitted", e.slug);});In single-page apps (React, Vue, Next.js and the like), call window.OneForm.scan() after the element mounts; the framework snippets above do this for you.
Events
The form tells the page what happens through postMessage. The loader passes each message on to window.OneForm.on listeners and fires it on the element as a oneform:<type> DOM event. Messages never contain answers.
| Event | Data | When |
|---|---|---|
ready | none | The form has loaded. |
started | none | The first question is on screen (once per visit), or a voice conversation has begun. |
question | fieldId: string, step: number | A question is on screen: its id, and its step number in this visit (typed forms). |
submitted | endingId: string | The form was submitted, with the id of the thank-you screen shown. No answers. |
resize | height: number | The form's content height in pixels; the loader sizes inline embeds with data-of-height auto. |
redirect | url: string | The thank-you screen sends the person to a URL. Only posted to the embedding page's own origin, since the URL can carry answers. |
close | none | The person closed a voice conversation from inside it. The loader also fires it whenever a popup, slider or chat panel closes. |
document.querySelector("[data-oneform]").addEventListener("oneform:submitted", (e) => { console.log(e.detail); // the same data as window.OneForm.on});Every message has the shape { source: "oneform", v: 1, id, type, ...data }, where id tells several embeds on one page apart. The loader only accepts messages from the OneForm origin and the frame it made. In the other direction, it sends pause (the panel was closed: a voice conversation stops talking and listening).
Hidden fields and UTM tags
- A form declares its hidden fields (a client id, a referrer). Only declared keys and the five UTM tags (
utm_source,utm_medium,utm_campaign,utm_term,utm_content) are kept; anything else is dropped, and each value is cut to 300 characters. - UTM tags in the page's address always pass through to the form.
data-of-hidden="client_id,ref"passes those page parameters through too, so?client_id=TD-1042on your page reaches the form.data-of-hidden-values="source=pricing;plan=pro"sets fixed values for that embed.- Links work the same way:
https://app.oneform.si/f/your-form?client_id=TD-1042. The API can make prefilled links for you.
Hidden values arrive with the submission and in webhook payloads under hidden.
Content-Security-Policy
If your site sets a Content-Security-Policy, add these sources to the matching directives you already have:
script-src https://app.oneform.si;frame-src https://app.oneform.si;style-src 'unsafe-inline';connect-src https://app.oneform.si;script-srcandframe-src: the script, and the form's frame.style-src 'unsafe-inline': the script adds one small<style>element for popups, sliders and launchers, and the inline snippet sizes its element with astyleattribute. A nonce or hash can't match the added styles, so it needs'unsafe-inline'.connect-src: only for voice forms. The orb fetches its colours from the OneForm origin; if that's blocked, it keeps the colours in its snippet.
With a nonce-based policy, give the script tag your nonce. Voice forms need the microphone: the frame asks for it with allow="microphone", so a Permissions-Policy on your page must not block it.
Without JavaScript
Where scripts aren't allowed, use a plain iframe. It has a fixed height and no popups, events or page parameters.
<iframe src="https://app.oneform.si/f/your-form?embed=iframe" width="100%" height="640" style="border:0;border-radius:12px" allow="microphone; autoplay; clipboard-write" title="Form"></iframe>