Embedding and WebView integration
Technical reference for embedding OmniLab in a web page, mobile WebView, or custom domain — with HTML, JavaScript, and React Native examples.
This guide covers the technical implementation for all embedded OmniLab delivery modes: manual iframe, JavaScript player tag, native WebView (React Native and other platforms), and custom domain delegation via DNS.
See the business-facing overviews at:
Embed-ready URLs
All embedded delivery modes start from the same OmniLab URL patterns:
| Use case | URL pattern |
|---|---|
| Campaign landing page | https://experience.example.com/<campaign-public-link>?embedded=1 |
| Direct touchpoint | https://experience.example.com/<campaign-public-link>?c=<touchpoint-id>&embedded=1 |
| Space-specific launch | https://experience.example.com/<campaign-public-link>?s=<space-id>&embedded=1 |
| Variant or language | Append &v=<variant-id> or &l=<language> as needed |
Always add embedded=1 when loading in an iframe or WebView. This flag tells OmniLab to run in an embedded context and adjusts layout and navigation accordingly.
Manual iframe
Minimal example
<iframe
id="omnilab-embed"
src="https://experience.example.com/<campaign-public-link>?c=<touchpoint-id>&embedded=1"
title="OmniLab campaign"
loading="lazy"
allow="camera; microphone; geolocation"
style="width:100%;min-height:900px;border:0;overflow:hidden"
></iframe>Adjust the allow attribute to match the permissions the experience requires. Camera, microphone, and geolocation are only needed when the experience uses scanning, media capture, or location-aware flows.
Automatic height resize
OmniLab pages send postMessage resize events. Listen for them on the parent page so the iframe height follows content instead of showing an internal scrollbar.
<script>
window.addEventListener("message", (event) => {
const data = event.data;
if (data?.type !== "resize" || data?.target !== "body") return;
const iframe = document.querySelector("#omnilab-embed");
if (iframe && typeof data?.data?.height === "number") {
iframe.style.height = data.data.height + "px";
}
});
</script>Other postMessage events
OmniLab can also emit modal lifecycle events that your wrapper may want to participate in:
| Event type | When it fires |
|---|---|
resize | Content height changes |
open-modal | A modal is about to open inside the experience |
close-modal | A modal has closed |
ready-to-open-modal | The modal is ready to animate in |
ready-to-close-modal | The modal is ready to animate out |
To log all messages during development:
window.addEventListener("message", (event) => {
console.log("OmniLab message", event.origin, event.data);
});JavaScript player tag
Use the OmniLab JavaScript player tag when a single host page must load different campaigns based on the current page URL.
<div id="omnilab-container"></div>
<script>
(function (b, o, n, u, s) {
var a, t;
a = b.createElement(u);
a.async = 1;
a.src = s;
t = b.getElementsByTagName(u)[0];
t.parentNode.insertBefore(a, t);
o[n] = o[n] || [];
})(document, window, "_om_async", "script", "https://<omnilab-script-host>/omplayer.js");
_om_async.push([
"init",
{
domain: "experience.example.com",
targetId: "omnilab-container",
queryParam: "id",
},
]);
</script>With that setup, the host page URL drives which OmniLab experience loads:
- Simple campaign:
https://www.example.com/promo?id=summer-campaign - With touchpoint:
https://www.example.com/promo?id=summer-campaign%3Fc%3D<touchpoint-id>%26embedded%3D1
The value in id is the path after the OmniLab domain. URL-encode any nested query string before publishing the link. If your deployment uses a specific script host URL, use that instead of the placeholder above.
React Native WebView
Installation
npm install react-native-webviewMinimal example
import React from "react";
import { WebView } from "react-native-webview";
export default function OmniLabWebView() {
return (
<WebView
source={{
uri: "https://experience.example.com/<campaign-public-link>?c=<touchpoint-id>&embedded=1",
}}
style={{ flex: 1 }}
javaScriptEnabled
/>
);
}Use a campaign landing page URL when the app should show multiple experiences, or a direct touchpoint URL to launch one specific experience immediately.
React Native requirements
- Enable JavaScript (
javaScriptEnabled={true}). - Grant camera, microphone, geolocation, and file permissions when the experience needs them.
- Use a full-screen or edge-to-edge container (
flex: 1). - If the host app must react to OmniLab events, confirm that the WebView bridge supports
postMessage. - Test virtual keyboard behaviour when the experience includes forms or sign-in steps.
Native iOS and Android guidance
- Use the platform's standard WebView component or a maintained wrapper library.
- Enable JavaScript.
- Forward device permission prompts (camera, microphone, geolocation) to the WebView.
- Test portrait and landscape layouts on real target devices.
- Verify app backgrounding, resume, and network loss do not break the participant flow.
- If the wrapper needs to react to
postMessageevents, validate the bridge in staging before shipping.
Custom domain delegation (DNS setup)
Overview
A delegated custom domain lets OmniLab experiences run under your own branded subdomain (for example experience.example.com) instead of the default OmniLab-hosted domain.
DNS record to create
Your DNS team creates a CNAME record pointing the chosen subdomain to the OmniLab endpoint:
| Record type | Name | Value |
|---|---|---|
| CNAME | experience (your chosen subdomain) | OmniLab endpoint provided by your Customer Success Manager |
If your DNS provider does not support CNAME at the apex (root domain), use a subdomain such as experience.example.com rather than trying to delegate example.com itself.
TTL considerations
Set the TTL (time-to-live) on the DNS record to a low value (300–600 seconds) before the switch so propagation is faster if you need to roll back. After the domain is stable, you can raise the TTL.
SSL certificate
OmniLab provisions an SSL certificate automatically once the DNS record is verified. Allow up to 15–30 minutes after DNS propagation for the certificate to become active. During this window, browsers may show a temporary certificate warning.
Propagation time
DNS changes can take up to 48 hours to propagate globally, depending on your provider and the existing TTL on the record. Plan the domain delegation well before your go-live date.
Typical embedding model
| Surface | Example |
|---|---|
| Host website | https://www.example.com/promo |
| Embedded OmniLab source | https://experience.example.com/summer-campaign?embedded=1 |
Go-live checklist
- Custom subdomain approved and DNS record created.
- DNS propagation verified (use a DNS checker tool).
- SSL certificate active (no certificate warning in browser).
- Standalone OmniLab URL working on the new hostname.
- Embedded page tested: layout, permissions, cookies, redirects.
- Existing QR codes and media placements updated to the new hostname.
Delivery best practices
- Let the iframe fill available width; avoid a fixed narrow desktop width.
- Start with a generous minimum height (
min-height: 900px), then let the resize listener set the final height. - Test sign-in steps, camera permissions, redirects, and mobile layout inside the real host page.
- If the host page uses sticky headers or constrained containers, test touchpoints that open drawers, forms, keyboards, or camera prompts.
- Keep secrets and API tokens on your backend — never in the kiosk page or WebView bundle.
Related
Iframe embedding
Business overview of web embedding options.
WebView integration
Business overview of mobile WebView delivery.
Custom domain delegation
Business overview of branded domain setup.
Kiosk integration (technical deep-dive)
Add kiosk-specific messaging, sizing, and device requirements to an embedded delivery.