About functions

What OmniLab functions are, how they run, when to use one instead of a webhook, and the limits your code works within.

4 min read

A function is a small piece of TypeScript that runs on OmniLab's own infrastructure. You write it in OmniLab Studio, OmniLab compiles it, and from then on the platform runs it for you — either when something happens in a campaign, or at a specific decision point such as a contact signing up.

You need no server, no endpoint, and no deployment of your own.

Functions are configured under Enterprise Settings, which needs an Admin role with the Global Organization selected — worth confirming you have that access before planning work, because the tab is hidden without it.

How it works

You store one TypeScript file with one exported handler. When you build it, OmniLab compiles that file to a WebAssembly module and keeps the compiled version. Every invocation from then on loads it into a fresh sandbox and calls your export.

The shape of every function
import type { PlatformEventHandler } from "./omnilab";

export const onPlatformEvent: PlatformEventHandler = (event) => {
  console.log("Something happened: " + event.type);
};

Your handler reaches the outside world through the calls OmniLab provides: read a config value, read a secret, make an HTTP request to a host you have allow-listed, read a contact, and write contact custom fields. That set is deliberately small — it is what lets OmniLab run your code on its own infrastructure safely, and it is enough for most integration work.

Each invocation is independent. Nothing you set on one call carries over to the next, so anything you need to keep goes into contact custom fields or into your own system over HTTP.

Functions or webhooks?

Both let you react to what happens in OmniLab. The difference is where your code runs and whether it can change the outcome.

FunctionWebhook
Runs onOmniLab's infrastructureYours
You need to hostNothingAn HTTPS endpoint
Can change what OmniLab doesYes, for one kindNo
Best forLogic that must run inside an OmniLab operation, or small integrations you would rather not hostFeeding a system you already run

A webhook tells your systems that something happened, after OmniLab has already decided it. A function runs inside OmniLab and — for one of the two kinds — inside the decision itself, so it can reject a signup, normalize an email before it is stored, or send a verification message through your own provider.

Choose a kind

Every function is one of two kinds, and the kind decides when it runs and what it can affect. It is fixed when you create the function, so make this choice before you start writing.

Platform event functionHook function
RunsAfter something happenedDuring an operation, which waits for it
Can it change the outcome?NoYes — it continues or refuses
Your exportonPlatformEventon + the hook point, for example onContactCreatePre
Wired up byA subscription to event typesA binding to a hook point
Your return valueDiscardedThe decision OmniLab acts on
If it failsThe activity is unaffectedThe operation is blocked

Start with a platform event function when either would work. It cannot break anything a customer is doing, so the cost of getting it wrong is a missing side effect rather than a failed signup.

Changing the kind means starting again

The kind determines the export your code must provide, which tabs appear in the editor, and the payload the test runner sends. There is no way to convert one kind into another: you create a new function and delete the old one.

From draft to running

Saving and building are separate on purpose. Saving stores your code and type-checks it; it never changes what is running. Only a build produces a new compiled version.

Create Build build succeeds build fails, nothing was live build fails, previous version kept Build again Save new source, Build again Delete Delete Delete Draft Building Ready BuildFailed Deleted

The status in the function list is one of Draft, Building, Ready, Build failed, or Deleted. Only a Ready function runs.

The two paths out of Building are worth knowing. A function that has never built successfully goes to Build failed. A function that is already live and fails a rebuild returns to Ready and keeps serving the version it was serving before, so a broken rebuild never takes a working function offline.

What your code works within

LanguageTypeScript, one file, entry point user.ts
Time per invocationUp to 2 seconds
Outbound calls per invocation20, counting every SDK call
NetworkOnly hosts you allow-list; a function with an empty list makes no outbound calls
Memory2 MiB by default, up to 4 MiB

Two rules catch people out. Secrets never go in your source — you store them in a bundle, bind the bundle to the function, and read them by name at runtime. And contact custom field keys beginning system. or feature. are reserved, so writes to them are rejected.

Full values, error codes and contracts are in the SDK reference.

On this page