Getting Started with Overlay Messaging


Overlay Messaging enables your application to display personalized pop-up messages to customers across both web and mobile surfaces from a single Optimove campaign. This guide covers SDK integration for Android, iOS, and Web, along with a behavior reference for channel mechanics.

Beta: Overlay Messaging is currently in beta. Your CSE handles tenant enablement—contact them to obtain access.

Note: Overlay Messaging (Channel 429) is distinct from Embedded Messaging (Channel 427). They share infrastructure but are separately provisioned and have separate channel IDs. Do not conflate them in integrations or support queries.

Prerequisites

Overlay Messaging is a cross-platform channel — both the Web SDK and Mobile SDK must be implemented to deliver messages across all surfaces. If only one SDK is integrated, messages will only reach customers on that platform.

RequirementDetail
Optimove credentialsRequired for all platforms
Mobile SDK credentialsRequired for all platforms — Overlay Messaging cannot be initialized without them
Both Web and Mobile SDKs integratedFull cross-platform delivery requires both; partial SDK implementation limits reach to a single surface
Overlay Messaging enabled on tenantBeta — provisioned by your CSE. Contact them to enable.
Domain and brand mappingDomains and brands must be mapped to your tenant before messages can be delivered
Attribute webhook mapping for Overlay MessagingDone by your CSE - contact them to ensure everything’s set up correctly
Push permission (mobile, triggered only)Triggered overlays on mobile require the user to have granted push permission; your app must handle the permission prompt — not managed automatically by the SDK
Minimum session length1 hour (configurable upward)

Set up

Mobile SDKs

Android — Initialization

Enable Overlay Messaging when initializing the SDK by calling .enableOverlayMessaging(sessionLengthHours).

Integer sessionLengthHours = 1;

Optimove.initialize(this, OptimoveConfig.Builder(
        "<YOUR_OPTIMOVE_CREDENTIALS>",
        "<YOUR_OPTIMOBILE_CREDENTIALS>")
    // ...
    .enableOverlayMessaging(sessionLengthHours)
    .build());

Android — Session reset

Call this to reset the current session and allow the SDK to fetch the next available session message. Use when a new user session begins — for example, on logout/login.

OptimoveOverlayMessaging.getInstance().resetSession();

Android — Setting an interceptor

An interceptor lets you run custom logic before any overlay message is processed. The interceptor receives the message object and must return one of three outcomes:

  • show — display the message
  • defer — leave the message intact; it can be fetched again in the same or a future session
  • discard — permanently delete the message from the backend

If the interceptor does not resolve within the configured timeout (default: 5,000ms), it resolves automatically as defer.

OptimoveOverlayMessaging.getInstance()
    .setInterceptor(new OptimoveOverlayMessaging.OverlayMessagingInterceptor() {
        @Override
        public void onMessageLoaded(
            OverlayMessagingMessage message,
            OptimoveOverlayMessaging.OverlayMessagingInterceptorCallback callback
        ) {
            // Your logic here — call one of the following:
            callback.show();
            // callback.defer();
            // callback.discard();
        }

        @Override
        public long getTimeoutMs() {
            return 5000;
        }
    });

OverlayMessagingMessage object (Android):

public class OverlayMessagingMessage {
    public enum MessageType {
        SESSION, IMMEDIATE
    }
    public long getId() { return id; }
    public JSONObject getContent() { return content; }
    @Nullable
    public JSONObject getData() { return data; }
    public MessageType getType() { return type; }
}

iOS — Initialization

Optimove.initialize(with: OptimoveConfigBuilder(
        optimoveCredentials: "<YOUR_OPTIMOVE_CREDENTIALS>",
        optimobileCredentials: "<YOUR_OPTIMOBILE_CREDENTIALS>")
    // ...
    .enableOverlayMessaging(sessionLengthHours: 1)
    .build())

iOS — Session reset

OptimoveOverlayMessaging.resetSession()

iOS — Setting an interceptor

private class MyInterceptor: OverlayMessagingInterceptor {
    func onMessageLoaded(
        _ message: OverlayMessagingMessage,
        callback: OverlayMessagingInterceptorCallback
    ) {
        // Your logic here — call one of the following:
        callback.show()
        // callback.deferMessage()
        // callback.discard()
    }

    func getTimeoutMs() -> Int { return 5000 }
}

OptimoveOverlayMessaging.setInterceptor(MyInterceptor())

OverlayMessagingMessage object (iOS):

public struct OverlayMessagingMessage {
    public enum MessageType {
        case session
        case immediate
    }
    public let id: Int64
    public let content: NSDictionary
    public let data: NSDictionary?
    public let type: MessageType
}

Web SDK

Initialisation

No SDK code changes are required to enable Overlay Messaging on web. Contact your CSE to have it enabled for your tenant.

Session reset

Call this to reset the current session and allow the SDK to fetch the next available session message.

optimoveSDK.API.overlayMessaging.resetSession();

Note: Minimum session length is 1 hour.

Setting an interceptor

The web interceptor works identically to mobile — return 'show', 'defer', or 'discard'. If the callback does not resolve within the configured timeout (default: 5,000ms), it resolves as defer.

// Basic usage — show the message
optimoveSDK.API.overlayMessaging.setInterceptor(
    (message) => { return 'show'; },
    { timeoutMs: 10000 }
);

// Advanced usage — take full control of message presentation
optimoveSDK.API.overlayMessaging.setInterceptor(
    (message) => {
        customMessageQueue.push(message);
        return 'discard';
    },
    { timeoutMs: 10000 }
);

Relevant types:

type InterceptorResponse = 'show' | 'defer' | 'discard';

type InterceptorCallback = (message: OverlayMessage) =>
    InterceptorResponse | Promise<InterceptorResponse>;

interface InterceptorOptions {
    timeoutMs?: number;
}

interface OverlayMessage {
    id: number;
    content: { ver: number; html: string };
    data?: Record<string, unknown>;
    type: OverlayMessageType;
}

enum OverlayMessageType {
    Session = 'session',
    Immediate = 'immediate'
}

Setting overlay options

Change the session length at runtime. This takes effect immediately — if the new session length indicates the current session has already elapsed (counting from the previous session start), a new session begins.

optimoveSDK.API.overlayMessaging.setOverlayOptions({
    sessionLengthHours: 2
});

Relevant types:

interface OverlayOptions {
    sessionLengthHours?: number;
}

Trigger setup for web and mobile

Because Overlay Messaging is cross-platform, triggers must be wired up on both surfaces for a triggered campaign to reach a customer on whichever device they're active on.

  • Web events are reported via the Web SDK using reportEvent calls on your site.
  • Mobile events are reported via the Mobile SDK on iOS and Android.

If a trigger event is implemented only on one platform, customers on the other platform will not receive triggered overlays — even if the channel is active on both platforms. Confirm with your CSE that all trigger events intended for Overlay Messaging campaigns are implemented and verified on both your web and mobile integrations before going live.


Behavior reference

Sessions

A session defines the window during which a customer is eligible to receive one scheduled overlay message. The session persists for the configured sessionLengthHours (default: 1 hour; minimum: 1 hour). A session starts when the SDK is first initialized and has never loaded before, when the configured session duration expires, or when resetSession() is called programmatically.

To programmatically start a new session — for example, on user logout — call resetSession() on the relevant SDK.

Message limits

  • Session (scheduled) messages: One per session restart. Only the most recent eligible scheduled message is shown.
  • Triggered (immediate) messages: Not limited to one per session. Multiple triggered messages may be delivered within a session — each shown after the previous is interacted with or dismissed — provided each message is still within its 2-minute TTL at the point of fetch.

Scheduled message delivery

At session start, the SDK syncs scheduled messages and identifies the most recent by execution time (send_at).

  • If the most recent message is within its TTL → it is shown.
  • If the most recent message has expired → nothing is shown. Older messages are not surfaced as a fallback.
  • Default TTL: 2 days from execution time. If the message is not fetched within 2 days of the campaign execution date and time, it expires and is not shown.
  • Maximum retention: 14 days.

Triggered message delivery

  • Triggered messages have a TTL of 2 minutes from the time they are sent.
  • Multiple triggered messages can be delivered within a session if the customer performs multiple trigger actions. Each message's TTL is independent.
  • On mobile, delivery requires push permission. Customers without push permission will not receive triggered overlays on mobile.
  • Delivery is near real-time: silent push on mobile, web sync on event emit.

Cross-device deduplication

When a message is interacted with or dismissed, it is hard-deleted from the backend. This mechanism prevents the message from reappearing on other devices. State syncs at session start and at a minimum once per hour on mobile.

Edge case: If a customer has the application open on two devices simultaneously at the point of delivery, both may briefly display the message before the deletion sync propagates.

Interceptor behavior

The interceptor is called before any message is presented. Outcomes:

ResponseEffect
showMessage is displayed to the customer.
deferMessage is left intact and can be fetched again in the same or next session. Does not delete the message.
discardMessage is permanently deleted from the backend. Will not appear on any device.

If the interceptor timeout elapses without a response, the outcome defaults to defer.

Default timeout: 5,000ms. Configurable via getTimeoutMs() (mobile) or the timeoutMs option (web).

Metrics

The following metrics are tracked and reported in Mission Control:

MetricTriggerUser-facing
DeliveredMessage fetched by device. May fire more than once if fetched across multiple devices before deletion.
OpenedMessage displayed to the customer.
ClickedCustomer clicked a CTA button.
ClosedCustomer dismissed the message via the close action.
ProcessedMessage written to storage.Internal only

Rendering

  • Web and mobile use a shared renderer.
  • On the web, the overlay renders inside a Shadow DOM — CSS is fully isolated from the host page in both directions.