Start free
Developers

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.

Form
Embed

Sits inside your page, like a section. Grows to fit.

Paste where the form should appear (the script tag can go once, before </body>).
<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

TypeWhat it doesForms
inline
Standard
Sits inside your page, like a section. Grows to fit.Typed, Voice
fullpage
Full page
Takes over the whole page — for a dedicated form page.Typed, Voice
popup
Popup
Opens in the middle of the screen — on load, on exit or after scrolling.Typed
slider
Slider
Slides in from the side of the screen.Typed
popover
Chat bubble
A round button in the corner opens the form in a small window.Typed
sidetab
Side tab
A tab on the edge of the screen that opens a slider.Typed
button
Button
A button on your page that opens the form in a popup or slider.Typed, Voice
orb
Floating 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.

AttributeValuesWhat it does
data-oneformthe form's slugRequired. Every element with it is turned into an embed when the loader runs (and again on window.OneForm.scan()).
data-of-typeinline | fullpage | popup | slider | popover | sidetab | button | orbHow the form is shown. Default inline.
data-of-voicetrueA voice form: dark panels, and the conversation always opens in a popup.
data-of-hide-welcometrueSkips the welcome screen (typed forms).
data-of-transparent
Standard, Full page
trueNo background behind the form, so your page shows through.
data-of-height
Standard
auto | <pixels>auto (the default) grows and shrinks with the form, between 320 and 4,000 pixels. A number fixes the height.
data-of-langen | fr | esThe language the form opens in.
data-of-hiddenkey1,key2Page URL parameters passed through to the form as hidden fields (UTM tags always are).
data-of-hidden-valueskey=value;key2=value2Fixed hidden-field values for this embed, for example the page or campaign it sits on.
data-of-titletextThe frame's accessible title. Default Form.
data-of-button-text
Button, Side tab, Chat bubble, Floating orb
textThe button or side tab's text; the accessible label of the chat bubble and the orb.
data-of-button-color
Button, Side tab, Chat bubble
#rrggbbThe button's colour. The text on it turns dark or light to stay readable.
data-of-button-size
Button
sm | md | lgThe button's size. Default md.
data-of-open-as
Button
popup | sliderWhat the button opens. Default popup.
data-of-position
Slider, Side tab, Floating orb, Button
left | rightWhich side the slider, side tab or orb sits on. Default right.
data-of-open
Popup, 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-once
Popup, Slider, Chat bubble, Side tab
trueAn automatic open happens once per browser (remembered in localStorage).
data-of-auto-close
Popup, Slider, Chat bubble, Side tab, Button, Floating orb
<milliseconds>Closes the panel this long after the form is submitted.
data-of-colors
Floating orb
#a,#b,#cThe orb's three colours. A published form's current colours replace them once loaded.
data-of-previewtrueUsed 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.

window.OneForm
// 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.

EventDataWhen
readynoneThe form has loaded.
startednoneThe first question is on screen (once per visit), or a voice conversation has begun.
questionfieldId: string, step: numberA question is on screen: its id, and its step number in this visit (typed forms).
submittedendingId: stringThe form was submitted, with the id of the thank-you screen shown. No answers.
resizeheight: numberThe form's content height in pixels; the loader sizes inline embeds with data-of-height auto.
redirecturl: stringThe thank-you screen sends the person to a URL. Only posted to the embedding page's own origin, since the URL can carry answers.
closenoneThe person closed a voice conversation from inside it. The loader also fires it whenever a popup, slider or chat panel closes.
DOM events
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-1042 on 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:

Content-Security-Policy (add to yours)
script-src https://app.oneform.si;frame-src https://app.oneform.si;style-src 'unsafe-inline';connect-src https://app.oneform.si;
  • script-src and frame-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 a style attribute. 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
<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>

Questions about the API, webhooks or embeds? Ask a developer.