Skip to Content
GuidesChannelsIn-app messaging

Set up In-app messaging

Public

In-app messages appear inside your website or mobile app — modals, banners, floating widgets, and surveys. Unlike other channels, in-app messaging doesn’t require provider credentials. It’s powered entirely by the Active Reach SDK.

In-app is a property-scoped channel, not workspace-scoped. Each property (web app / mobile app / kiosk = one SDK install) maintains its own enabled types, kill-switches, and per-surface metrics. Campaigns are authored at the workspace and target one or more properties.

Before you start

You’ll need:

  • Admin access to your Active Reach workspace
  • Access to your website or app codebase to install the SDK

Setup walkthrough

Select your platforms

Go to Settings → Channels → In-App → Setup. Select every platform where you want to show in-app messages:

PlatformSDK type
WebBrowser SDK (JavaScript)
AndroidKotlin SDK
iOSSwift SDK
React NativeRN Bridge
FlutterDart SDK

You can add more platforms later. Select at least one to proceed.

Install the SDK

The wizard shows code snippets for each selected platform, pre-filled with your write key and workspace ID. Copy and paste into your codebase.

Web:

<script src="https://cdn.activereach.ai/sdk/aegis.min.js"></script> <script> Aegis.init('YOUR_WRITE_KEY', { workspace_id: 'YOUR_WORKSPACE_ID', inapp: { enabled: true } }); </script>

For SPAs (React, Next.js, Vue), initialize once in your entry file. The SDK detects route changes automatically.

Android (Kotlin):

Add the Gradle dependency and initialize in your Application class. Call Aegis.onResume() in your Activity’s onResume to trigger display-rule evaluation.

iOS (Swift):

Add via Swift Package Manager or CocoaPods (min iOS 13). Initialize in AppDelegate.didFinishLaunchingWithOptions and call Aegis.shared.onAppResume() when the app foregrounds.

React Native / Flutter:

Install the npm/pub package and await initialization in your app’s entry point. The native bridges handle platform-specific lifecycle events.

Full SDK reference with all methods and config options → Web SDK docs · Mobile SDK docs

Verify the connection

Open your website or app and trigger a page load. The SDK posts events to the gateway over two ingress paths — /v1/batch for the main SDK event stream (track / identify / page / screen / group / alias) and /v1/in_app/events narrowly for in-app campaign click and dismiss telemetry. Both are authed via X-Aegis-Write-Key. Check the SDK Health Dashboard (Settings → Channels → SDK Health) to confirm the connection.

Direct SDK calls to /api/v1/events will fail with 401 — that path is the internal scheme and requires a JWT, not a write key. Use trackEvent on the SDK and let it route through /v1/in_app/events over the gateway.

You’re done

Your in-app messaging channel is active. The wizard shows a badge with the number of platforms configured.

What you can build

Once the SDK is installed, you can create in-app campaigns from Engage → In-app Messages → Create:

FormatBest forExample
ModalFeature announcements, promotions”New feature: AI segment builder — try it now”
BannerPersistent nudges, warnings”Complete your profile for 10% off”
Floating widgetOngoing engagement, social proof”12 people bought this in the last hour”
SurveyFeedback, NPS”How would you rate your experience? 1-5”
Full-screenOnboarding, critical updates”Welcome! Here’s how to get started”

Each campaign uses a visual editor with drag-and-drop positioning, rich text, buttons, and images. You set display rules — which segments see it, on which pages, at what frequency — and Active Reach handles rendering.

SMB vs Marketer mode

The workspace mode toggle at the top of /dashboard/{ws}/in-app-messages is not a feature-density switch — it swaps the entire information architecture of the in-app surface. Both modes ship the full functionality their persona needs; nothing is hidden behind the toggle that the persona depends on.

The mode is read from useWorkspaceMode() ('smb' | 'advanced', default 'smb'). It persists per-operator across sessions.

SMB mode — outcome-grouped

The SMB view answers the question “what is this in-app campaign trying to achieve for the business?” It’s the default for chain operators and single-brand owners.

  • Outcome cards, not rows. Each card groups campaigns by the goal derived from the (widget_category, sub_type, intent_pattern_id) tuple — e.g. Drive reviews, Recover carts, Welcome new visitors, Win back lapsed customers.
  • Plain-language state per card. “Active · 8 reviews this week · Web only” — not impression counts or CTR percentages.
  • One primary action. Pause or Resume sits on the card directly; everything else lives behind the overflow menu.
  • Three-number KPI strip in plain English at the top — “245 customers saw an offer this week” — instead of a dense rollup grid.
  • Dropdown property picker instead of a chip grid, because most SMB brands run one or two properties.
  • Thin preset deck at the bottom with a “Browse all” link into /create.

Marketer / Advanced mode — campaign-oriented

The Advanced view answers the question “how do I operate this campaign portfolio?” It’s the default for in-house marketers and agency operators.

  • Dense table with one row per campaign.
  • Bulk actions — checkbox column, then Pause / Duplicate / Archive on the selected set.
  • Prioritize column — drag-to-reorder modal that writes the priority column on in_app_campaigns, scoped per (workspace_id, property_id, fire_on_set) bucket.
  • A/B-test badge per row when ab_variants is non-empty.
  • CVR column alongside the standard delivery / engagement columns.
  • Audience filter, date-range filter, audience-size column for portfolio triage.
  • Chip grid property picker so multi-property operators can switch quickly.

What the toggle does not hide

Every today-surfaced capability survives the split. The smart trigger patterns (the micro-intent engine — 4 anonymous shipped + 4 identified locked) and the Quick Start templates that used to crowd the SMB list page have moved to /create, where they get more prominence as featured rows. Nothing was removed.

The /create three-row discovery surface

Clicking Create from either persona view lands on the same three-row discovery shell. The rows are always present; only their order flips by persona.

RowWhat it contains
Smart trigger patternsThe micro-intent engine catalog — anonymous and identified-contact subgroups, each tile a pre-wired IntentRule that the wizard stamps into display_rules.trigger_config
Quick Start templatesThe eight format tiles — modal, banner, floating widget, survey, full-screen, and the three interactive families
Blank canvasStart from scratch, pick a format, build the rule by hand

SMB persona sees outcomes first; Marketer persona sees templates first.

Deep-linking from outcome cards. SMB outcome cards link into the wizard via /create?outcome=<id>. The query param resolves through lib/in-app/outcomes.ts and prefills defaultSubType plus the wizard body via preset_payload on each Outcome entry, so the operator lands on a wired-up draft. The existing ?pattern=<id> deep-link from the Smart Trigger Pattern tiles is unchanged.

Telemetry. Each campaign-create call sends an X-Aegis-Workspace-Mode header; the cell-plane creator attaches it as a workspace_mode dimension on the emitted in_app_campaign_created event, so portfolio-level read-outs can split authorship by persona.

How journey-queued in-app touches respect suppression

In-app campaigns enqueued by a journey (e.g. cart recovery) opt into the same suppression machinery as catalog campaigns via the frequency_cap JSONB on contact_in_app_queue. When the SDK fires a conversion event (e.g. notifyConversion), queued journey touches that compete with the conversion are silenced in lockstep with their catalog peers. Targeting bypass on queue rows is preserved by design.

What’s next