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.
| Requirement | Detail |
|---|---|
| Optimove credentials | Required for all platforms |
| Mobile SDK credentials | Required for all platforms — Overlay Messaging cannot be initialized without them |
| Both Web and Mobile SDKs integrated | Full cross-platform delivery requires both; partial SDK implementation limits reach to a single surface |
| Overlay Messaging enabled on tenant | Beta — provisioned by your CSE. Contact them to enable. |
| Domain and brand mapping | Domains and brands must be mapped to your tenant before messages can be delivered |
| Attribute webhook mapping for Overlay Messaging | Done 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 length | 1 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 messagedefer— leave the message intact; it can be fetched again in the same or a future sessiondiscard— 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
reportEventcalls 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:
| Response | Effect |
|---|---|
show | Message is displayed to the customer. |
defer | Message is left intact and can be fetched again in the same or next session. Does not delete the message. |
discard | Message 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:
| Metric | Trigger | User-facing |
|---|---|---|
| Delivered | Message fetched by device. May fire more than once if fetched across multiple devices before deletion. | ✓ |
| Opened | Message displayed to the customer. | ✓ |
| Clicked | Customer clicked a CTA button. | ✓ |
| Closed | Customer dismissed the message via the close action. | ✓ |
| Processed | Message 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.
Updated about 2 hours ago