Embed a Form
This page is for developers who show an Omniform form inside their own website, live chat, or mobile app, instead of sending the customer to a separate page. The customer fills in the form in a panel, and your page can close the panel by itself after the form is sent.
Embedding uses the same links as Share Forms with Customers: one form, one room, one submission, and an expiry time. The answers go to the same webhook, described in the Developer Reference.
Which URL to embed
When your system creates a link with the Form Links API, the response has two addresses for the same link:
Key | Path | Use |
|---|---|---|
|
| Send it to the customer to open as a page of its own. Browsers refuse to show it inside a frame. |
|
| Show it in an iframe or a WebView. It is the same form and the same link, and it tells the page around it what happens. |
Create the link on your server, with an Omniform API token, and give only the embed_url to the page or app that shows it. The API token must never be in browser or app code. The Form Links API is described in the Public API Documentation, linked at the top of the API Tokens menu in Omniform settings.
Basic iframe
The form has no close button of its own. Your panel, modal, or screen must provide one, and must also close when
omniform:closearrives. See Close the panel.Give the frame at least 320 px of width and about 560 px of height. A wider frame simply gives the form more room.
For the height, use a fixed value (the form scrolls inside the frame and keeps its submit button in view), or follow
omniform:resize. See Resize the frame.sandbox:allow-scriptsruns the form.allow-same-originlets the form keep a draft of the answers. Without it, the form still loads and submits, but a reload starts empty.allow-formsis part of the recommended set.allow-popupslets links in the form, such as your terms in a Consent field, open in a new tab.Do not add
allow-top-navigation: the form never needs to move your page.
referrerpolicy="no-referrer"keeps your page URL from reaching Omniform.Your page must use HTTPS. A page on
http://gets a refused frame. If your page sets a Content-Security-Policy, add the form host toframe-src.
Events
The embedded form tells the page around it what happens, with postMessage. Every message is a plain object with a type, and at most a status or a number. It never carries the token, an answer, the room, or any server text.
| Extra fields | When |
|---|---|---|
| none | The first screen is showing: the form, a closed-link screen, or an error screen. Sent once. |
|
| The height the content needs. Sent after |
| none | The customer sent the form and the Thank you screen is showing. |
|
| The link can't be filled in: |
| none | The Thank you screen counted down and asks you to close the panel. Sent once, only when Close automatically is on. |
A temporary load error, such as a network problem, shows the form's own message and sends no state. ready still arrives, so ready alone does not mean the form is showing.
The messages are sent to window.parent with target origin *, because your page can be on any website. That makes the check on your side important: accept a message only when event.origin is the form's origin and event.source is your iframe's contentWindow. Any other window can post messages with the same shape.
Put the listener right after the iframe, or register it before the iframe is added to the page, so ready can't arrive before anyone is listening.
Listener
showClosedLink is your own function: for example, replace the frame with your own message for expired, submitted, or unavailable.
Don't close the panel on omniform:submitted. The Thank you screen is still showing, and closing at once hides it before the customer can read it. Wait for omniform:close, or for the customer to use your close button.
Resize the frame
The reported height is the height of the content, not of the frame, so it can go down as well as up, and setting the frame to it never loops. Cap it if your layout needs a maximum, for example Math.min(message.height, window.innerHeight); the form then scrolls inside the frame.
Close the panel
Closing is always up to you. The form shows no close button, so your panel needs one that the customer can use at any time, before or after sending the form.
After a successful submission, the Thank you screen shows Closing in 5s and counts down. At zero, the form sends omniform:close once. It is a request: the form can't close your panel by itself, so you decide what closing means, such as removing the iframe, hiding the modal, or going back a screen.
The admin sets the countdown for the whole app, in Omniform settings → Customer Page → Thank you → Close automatically: on or off, 1 to 30 seconds, on after 5 seconds by default. When it is off, no omniform:close is sent, and the Thank you screen stays until the customer closes your panel. See Close automatically.
The countdown never runs on /f/, on a closed-link screen (omniform:state), or when sending fails.
Mobile apps (WebView)
A WebView shows the form as a top-level page, so there is no window.parent to post to. When window.ReactNativeWebView.postMessage exists, the form sends each event there as a JSON string, with the same types and fields as in the browser.
React Native (react-native-webview)
onShouldStartLoadWithRequest keeps the WebView on the form's origin, so a page it navigates to can't post events that look like Omniform's. Your screen still needs its own close or back button, for a customer who wants to leave early or when Close automatically is off. Handle omniform:resize the same way if you size the WebView from its content, and omniform:state to show your own screen.
Native WebViews (Android WebView, iOS WKWebView)
Without react-native-webview, there is no window.ReactNativeWebView. Define it yourself before the page's scripts run, with a document-start script (WebViewCompat.addDocumentStartJavaScript on Android, a WKUserScript at document start on iOS), and forward the string to your own bridge:
nativeBridge stands for whatever your platform exposes to the page (addJavascriptInterface on Android, a WKScriptMessageHandler on iOS). The string is the same JSON as above. On the native side, check that the message came from the form's origin before you act on it.
About the link
One submission. After a successful submission, the link is used for good: opening it again shows the Already filled screen and sends
omniform:statewithsubmitted.Expiry. 72 hours by default; your system can choose 5 minutes to 30 days when it creates the link.
/e/and/f/are two doors to the same link, so they share the status and the expiry: a submission through one closes the other.Whoever has the URL can submit. There is no login in front of the form, and any HTTPS website can show an embed URL in a frame, so keeping the URL secret is what protects it. Treat
embed_urllike a password:create it on your server for one customer and one room, and give it only to that customer;
keep it out of logs, analytics, and shared screenshots;
use the shortest expiry that fits, and revoke the link when it is no longer needed.
omniform:submitted is not proof. Any script on your page can post the same message, so don't unlock anything because of it. The answers reach your webhook, and the Form Links API returns the link status
submittedon your server.Blocked storage. When the browser blocks third-party storage (for example Firefox in strict mode, or Chrome with third-party cookies blocked), the form still loads and submits. It only can't keep a draft, so a reload starts with empty answers.
/f/ can't be framed. A frame with a
/f/URL stays blank or shows the browser's "refused to connect" screen, and it sends no events. Useembed_url. Opening/e/as a normal page works too; it simply posts nothing.
Troubleshooting
Symptom | Check |
|---|---|
The frame is blank or says it refused to connect | The URL is |
The form shows but no event reaches the listener | Compare the full origin (scheme, host, and port) of the embed URL, check against |
The customer's answers are gone after a reload | Normal when the browser blocks third-party storage or the |
| It starts after |
| Close automatically is off in Customer Page settings, or the submission did not succeed. It only follows the Thank you countdown. |
The Thank you screen disappears at once | Your listener closes the panel on |
Qiscus Technology