Script examples
Working code for the common cases: tag manager, advertising pixels, cookie banner, conversion events, and scripts scoped to selected campaigns.
Working code for the cases that come up most. Copy one, change the identifiers, and hand it to whoever adds it in OmniLab. This page is for whoever writes the script.
Where the script runs
Organisation scripts run in the consumer-facing OmniLab Pages runtime, not inside OmniLab Studio. Before active scripts run, OmniLab initialises window.omnilab and can expose both group data and basic contact data to the page.
window.omnilab?.contact?.externalId
window.omnilab?.contact?.email
window.omnilab?.group
window.omnilab?.group?.configuration?.variables
window.omnilab?.group?.uniqueKey
window.location.pathnameContact values are available only when the participant is already known in that flow.
Your code must contain real script tags
OmniLab expects the script code field to contain one or more valid <script>...</script> blocks. Inline scripts and external script loaders are both supported.
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "omnilab_view",
organisation_key: window.omnilab?.group?.uniqueKey,
page: window.location.pathname,
});
</script><script async src="https://www.googletagmanager.com/gtm.js?id=GTM-AB12C3D"></script>Context and trigger behaviour
| Setting | What it means |
|---|---|
ALL | Run in both iframe and non-iframe OmniLab Pages |
IFRAME_ONLY | Run only when OmniLab is embedded |
NON_IFRAME_ONLY | Run only when OmniLab Pages is standalone |
VISIT | Load during the normal page visit |
REGISTRATION | Hold the script for the registration stage |
If the current trigger is REGISTRATION, OmniLab still keeps the other active scripts available and adds the registration-targeted scripts for that stage. In practice, use a separate REGISTRATION script for conversion events instead of overloading the base page-view script.
Safe use cases
- Analytics loaders such as GTM, a pixel base tag, or a
dataLayerbootstrap - Per-organisation behaviour based on
window.omnilab.group.configuration.variables - Lightweight event pushes on visit or registration
- Minor DOM enhancements that do not depend on fragile selectors or block interaction
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "omnilab_view",
organisation_key: window.omnilab?.group?.uniqueKey,
country: window.omnilab?.group?.configuration?.variables?.country,
locale: window.omnilab?.group?.configuration?.variables?.locale || "en_US",
page: window.location.pathname,
surface: "OmniLab Pages",
});
</script><script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "registration_complete",
external_id: window.omnilab?.contact?.externalId,
email: window.omnilab?.contact?.email,
organisation_key: window.omnilab?.group?.uniqueKey,
});
</script>What to avoid
- Replacing or overriding OmniLab business logic
- Blocking synchronous work that delays page load or prevents participation
- Fragile DOM rewrites that depend on unstable class names or layout details
- Collecting extra personal data without a clear legal basis and review
- Large client-side libraries that are not essential to the participant journey
A broken script can break every embedded experience
Because these scripts execute in OmniLab Pages, one bad script can affect live campaigns. Keep them small, test them in staging, and give admins a rollback plan before production.
Local testing workflow
- Build and review the script in a staging environment.
- Test both iframe and non-iframe delivery if the script depends on the container.
- If the trigger is
REGISTRATION, complete a full registration flow and inspect the browser console and network panel. - After admins save the script, publish the affected campaign again before you validate the live experience.
Handoff to admins
When you hand a script to an admin, provide:
- the script name
- the intended context (
ALL,IFRAME_ONLY, orNON_IFRAME_ONLY) - the intended trigger (
VISITorREGISTRATION) - whether the script should start active or inactive
- a rollback instruction and a staging test result
Complete example scripts
Google Tag Manager base loader
Use this when your team wants GTM available before firing additional events.
<script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({
'gtm.start': new Date().getTime(),
event: 'gtm.js',
});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-AB12C3D');
</script>Page-view event with organisation variables
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'view_page',
country: window.omnilab?.group?.configuration?.variables?.country,
region: window.omnilab?.group?.configuration?.variables?.region,
language:
window.omnilab?.group?.configuration?.variables?.centerLanguage || 'English',
locale:
window.omnilab?.group?.configuration?.variables?.locale || 'en_US',
page: window.location.pathname,
page_type: 'Experience',
organisation_key: window.omnilab?.group?.uniqueKey?.toUpperCase(),
surface: 'OmniLab Pages',
});
</script>Registration event with dataLayer.push
Use this when you want to emit a conversion-style event after registration.
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'registration_complete',
organisation_key: window.omnilab?.group?.uniqueKey?.toUpperCase(),
country: window.omnilab?.group?.configuration?.variables?.country,
locale:
window.omnilab?.group?.configuration?.variables?.locale || 'en_US',
page: window.location.pathname,
registration_status: 'complete',
});
</script>Meta Pixel registration trigger
Use this pattern when the base Meta Pixel is already present and you only need to fire an event from OmniLab Pages.
<script>
if (typeof window.fbq === 'function') {
window.fbq('track', 'CompleteRegistration', {
organisation_key: window.omnilab?.group?.uniqueKey,
country: window.omnilab?.group?.configuration?.variables?.country,
locale:
window.omnilab?.group?.configuration?.variables?.locale || 'en_US',
page: window.location.pathname,
});
}
</script>Kiosk idle signal, scoped to selected campaigns
Use this when kiosk campaigns need to reset themselves after a visitor walks away. It is also the reference pattern for any script that must run on some campaigns but not others: the allowlist is a substring match against the full URL, and a campaign public link works as an entry.
<script>
(function () {
const TRIGGER_STRINGS = ['summer-experience-kiosk', 'back-to-school-2026-kiosk'];
const shouldActivate = TRIGGER_STRINGS.some((trigger) =>
window.location.href.includes(trigger)
);
if (!shouldActivate) return;
const IDLE_TIMEOUT = 10000;
let timer;
function sendIdle() {
window.parent.postMessage({ type: 'omnilab:idle', timestamp: Date.now() }, '*');
reset();
}
function reset() {
clearTimeout(timer);
timer = setTimeout(sendIdle, IDLE_TIMEOUT);
}
['click', 'mousedown', 'mousemove', 'keydown', 'scroll', 'touchstart', 'touchmove'].forEach(
(e) => document.addEventListener(e, reset, { passive: true })
);
reset();
})();
</script>Install it as IFRAME_ONLY on the VISIT trigger, and hand the admin the list of campaigns it covers alongside the code — that list has to grow every time a new kiosk campaign launches. The signal repeats every 10 seconds while the screen stays idle. Acting on it is the kiosk application's job, not yours — this script's responsibility ends at the postMessage. Kiosk integration has the receiving contract to hand to whoever builds the kiosk.
Advertising pixels
Dropping your ad platform's pixel here is what lets it see campaign traffic — so you can build a lookalike audience from people who engaged, and exclude people who already converted.
<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '<YOUR-PIXEL-ID>');
fbq('track', 'PageView');
</script>Google Ads and TikTok follow the same shape: paste the base tag the platform gives you, on the page-load trigger. Fire the conversion event from a separate registration-triggered script rather than adding conditionals to the base tag.
If you already run a tag manager, load the container instead and manage the pixels inside it — one script in OmniLab, all your tags managed where your team already manages them.
Cookie banner
Load your own consent tool exactly as you do on your website, on the page-load trigger:
<script src="https://cdn.example-consent-tool.com/loader.js" data-site-id="<YOUR-SITE-ID>"></script>Then make your other scripts wait for its answer rather than firing regardless. Most consent tools expose a callback or a global you can check — follow that tool's documentation, and test the refuse path, not just the accept path.
Test what happens when someone refuses
The accept path almost always works. The refuse path is where tags fire anyway, and it is the one that carries regulatory risk. Refuse consent and confirm your pixels stay silent.
Reading organisation variables in your script
Only two paths are guaranteed to exist for every organisation:
| What you want to read | Variable path | Example result |
|---|---|---|
| Organisation key | window.omnilab?.group?.uniqueKey | paris-centre |
| Current page path | window.location.pathname | /summer-experience |
window.omnilab?.group?.configuration?.variables is a free-form key/value store: an admin can create any key with any name under Organisation settings, and none are seeded for you. country, locale, and region in the examples above are keys one organisation chose to configure — not built-in fields every organisation has. Confirm with whoever configures the organisation which keys actually exist before you reference them, and always add a fallback for a key that might be missing, for example variables?.locale || 'en_US'.
centerLanguage is not a real key
The centerLanguage path used in some examples on this page is illustrative only — it doesn't exist unless an admin creates a variable with that exact name. Reading an unconfigured key returns undefined, so always check with your admin first, or fall back to a literal default.
Keep analytics payloads generic
Prefer organisation, locale, page, and event context unless your measurement design truly requires more. If a destination expects transformed or filtered values, apply that logic inside your script before pushing it.