Double opt-in email verification

Require participants to confirm their email address before a sign-up counts, using a Function you control.

5 min read

Turn on double opt-in to hold a sign-up until the participant confirms their email address, so your contact list stays clean and you have a record of consent. OmniLab does not send the confirmation message itself — you write a small Function that decides how confirmation happens, then bind it to the organisation.

What the participant goes through

Worth reading before you configure anything: double opt-in adds a round trip through the participant's inbox, and where they end up depends on whether they open the email on the same device they signed up on.

1OmniLab experience

The participant fills in the sign-up form

2OmniLab experience

Your Function sends the confirmation email

Through your own email provider.

3OmniLab experience

A waiting screen holds the sign-up

Asks them to confirm, with Resend email and a recheck button.

4The participant's inbox

They open the email and click the link

5Confirmation page

A brief confirmation page appears

It confirms the address, then forwards them on by itself.

6OmniLab experience

They land back on the page they signed up from

Recognised, with anything they did before confirming still attached to them.

7OmniLab experience

They continue the experience

The sign-up is held at step 3 and only completes when the link is opened. Nothing is counted before that.

Three things about that journey are worth knowing before you turn it on.

The confirmation page is not a dead end. It confirms the address and forwards the participant back to the campaign on its own. They see it for a moment; there is nothing for them to click.

The link works once. A second click reports that it has already been used and points the participant back to the campaign, where they can sign in with a code sent to their email instead. This matters because mail security scanners and link previews open links before people do — the page is built so those scanners cannot burn the link before the real click.

Opening the email on another device is normal. They signed up on a laptop and opened the email on their phone, so the phone has no trace of the sign-up. On the laptop, the waiting screen's recheck button moves them on; on the phone, they are asked for a code instead. Neither is an error, and both end in the same place.

Before you begin

  • You need Admin access. Turning on the setting and binding the Function both require it.
  • A Function bound to the contact.verify hook point must exist before you turn double opt-in on. Without one, every affected sign-up fails.
  • Decide which email service provider (ESP) — the service that actually sends the confirmation message, such as Brevo — your Function will call, and have its API credentials ready.

Bind the Function first

Once double opt-in is enabled for an organisation, OmniLab refuses every passwordless sign-up until a Function is bound to contact.verify. Set up the Function before you flip the switch, not after.

Publishing is blocked while the binding is missing, so this surfaces as a validation error on any campaign in that organisation — including campaigns built by colleagues who never touched the setting.

Steps

Bind a Function to the verification hook

In the left sidebar, switch to the Global Organization, then open General Settings. On the Enterprise Settings page, select the Functions tab, and create or choose a Function bound to the contact.verify hook point. This is the code that actually delivers the confirmation message — OmniLab hands it the single-use link and waits for an answer.

Your Function has two valid responses: send the link through your ESP, or tell OmniLab the contact is already verified when your own records already prove it.

Two details on the binding decide whether OmniLab accepts it. It has to be Active — a binding left inactive counts as no binding at all. And it has to cover the organisation the campaign belongs to, either by being global or by naming that organisation among its targets. A binding that targets only one organisation leaves every other one blocked.

Function editor showing a binding to the contact.verify hook point

Writing the Function itself

Building and testing the Function is covered in Hook functions. Share that page with your developer.

Store your provider credentials as a secret

Still on the Functions tab, add your ESP's API key as a secret bundle and bind that bundle to your Function, so the credentials are available at runtime without being written into the code. See Configure runtime and secrets for the exact fields.

Turn on double opt-in for the organisation

Open General Settings > Authentication to set the tenant-wide default, or Organization Settings > Authentication to set it for one organisation only. Set Double opt-in for passwordless sign-up to Enabled.

Authentication settings panel with double opt-in for passwordless sign-up set to Enabled

A per-organisation choice always wins over the tenant default, so use the organisation setting for any group that needs different behaviour.

Confirm a sign-up is actually held

Sign up with a test contact and confirm the participant is not counted until they act on the confirmation message your Function sent, or until your own system reports them already verified. Check your Function's execution log to see which of the two paths ran.

Adjust the waiting screen copy if you need to

While a sign-up is held, the participant sees a screen asking them to confirm their address, with buttons to resend the email and to recheck once they have clicked the link. It ships translated in every language OmniLab supports, so this step is optional — do it only if you want different wording.

Edit it in Build > Settings > Campaign Translation > Acquisition Form; the exact labels are listed in the acquisition form reference.

The verification link is generated in the Campaign's default language, so a participant lands on a confirmation page in the language they signed up in.

If something's blocked

  • A campaign won't publish, with a double opt-in error under Auth. Double opt-in is on for this organisation but no active contact.verify binding covers it. Bind one as described above, or set double opt-in back to Disabled for that organisation. Both need Admin access, so a campaign builder who hits this has to escalate rather than work around it. See Validation & publishing.
  • The validation error says the binding couldn't be checked. OmniLab could not reach the function service to confirm the binding, which is not the same as finding it missing. Run the validation again; if it keeps happening, contact support.
  • Sign-ups fail immediately. Double opt-in is on for this organisation but no Function is bound to contact.verify. Bind one, or turn the setting off until you're ready.
  • A participant says the confirmation message never arrived. Open the Function's execution log for that sign-up — a successful run only means your Function's call to the ESP was accepted, not that the message was delivered. Check the ESP's own delivery logs next.
  • Sign-ups succeed instantly for everyone, with no message sent. Your Function is returning already verified on every run instead of only when your own records support it. Review its logic.

On this page