Beta. In-App Messaging is in beta and open to every Gameball account. Send questions and feedback to support@gameball.co.
Display In-App Messages
Your dashboard campaigns, drawn natively in your React Native app: slide-ups, modals, and full screens, triggered by session start or by the events you already send. In-app messaging needs Gameball React Native SDK 4.0.0 or later. For campaign options, triggers, filters, priority, cooldown, quiet hours, and how the analytics are defined, see In-App Messaging Campaigns.Requirements
Install
startInAppMessaging, stopInAppMessaging, setOverlayOpen, onInAppMessage, and logPurchase), one read-only property (isInAppMessagingStarted), one component (<GameballInAppMessages />), and a debug option on init.
Mount the Surface
React Native has no window of its own to draw into, so the SDK needs a place in your tree. Mount<GameballInAppMessages /> once, near the root of your app and above your navigator.
App.tsx
Modal, which puts them above everything your app draws, including a navigator’s own screens, and gives Android’s Back button somewhere to land.
Start Messaging
Three calls, in order.Call
init at module load, not from a component effect. It is asynchronous, because it fetches your account’s settings, and every network-facing method refuses to run until it resolves. A child component’s effect runs before its parent’s, so an effect-based init leaves a window in which your app is mounted and interactive while the SDK is not ready.Awaiting
startInAppMessaging is optional. The SDK loads the customer’s message history before it judges any campaign, whether or not you await. The promise resolves once campaigns have synced and the session-start campaign has been evaluated. Events you send before then are not matched against campaigns, so await it before sending an event that should trigger one.startInAppMessaging takes an explicit customerId if you would rather not rely on the last customer passed to a successful initializeCustomer. You don’t need to stop to switch customers: a new initializeCustomer, or a start with a different customerId, fetches that customer’s campaigns.
Call stopInAppMessaging() on logout: it dismisses what is showing, sends pending analytics, and lets go of the customer, so the next start needs a customer again. The device keeps the customer’s message history, so the same customer signing back in is not shown a once-ever message twice. It keeps one customer’s history at a time: when a different customer starts messaging on the device, the previous history is discarded.
Control Display and Actions
Every option is optional. The hooks follow your most recentstartInAppMessaging call. sessionTimeoutSeconds is read only when messaging starts for the first time, or for the first time after stopInAppMessaging().
'later' waits until the screen frees up: setOverlayOpen(false), the profile widget or another message closing, or the device rotating. It is not passed to beforeDisplay again, so for a screen such as checkout, setOverlayOpen is the more reliable hold. beforeDisplay and onAction must return a value, not a promise. A message closes after any tap action, whatever onAction returns.
While your own modal, drawer, or checkout step is up, tell the SDK and it holds messages until you say the screen is yours again:
Actions
A campaign’s surface or button can dismiss, open a URL, navigate to a route, or ask for push permission.onAction sees all of them first.
If you bundle a browser, pass openUrl and decide for yourself:
openUrl, it opens every campaign link, both kinds. Return true when the link opened. Returning false does not hand the link back to the SDK: nothing opens, and the log says could not open "<url>".
Whatever you do, the SDK only ever opens http, https, mailto, and tel. A campaign carrying javascript:, file:, or your own deep-link scheme is refused and logged, so a campaign cannot launch arbitrary schemes in your app.
Observe Messages
beforeDisplay to hold or drop a message. It fires for every listener you register, and a listener that throws is logged rather than allowed to break the display. It fires once, at selection. A held message does not fire again when it finally displays.
Events and Purchases
Nothing extra to wire. Every event you already send is also a trigger, evaluated before the request goes out, so a campaign that fires onadd_to_cart needs no new code:
1200 equals "1200". contains ignores case. Event names must match exactly, including case. A property the event does not carry never matches, even for a “does not equal” filter.
Purchases have their own method. logPurchase sends an event named purchase through sendEvent, so a campaign triggered by purchase can filter on productId, price, currency, quantity, and anything in properties. It works whether or not messaging has started, and takes the same optional callback and sessionToken arguments as sendEvent. If you already send purchase events yourself, switch to logPurchase rather than sending both.
Language and Right-to-Left
A campaign is fetched in one language. The customer’s ownpreferredLanguage, a two-letter code, wins; without one, the SDK uses the language init was given, then English. setLanguage changes that language for every request from then on, and also saves it as the last initialized customer’s preferredLanguage. A code the SDK does not support falls back to en. Campaigns already synced keep the copy they were fetched with until the next sync. changeLanguage still works but is deprecated in favor of setLanguage.
Mirroring is your app’s business, not the SDK’s. Messages are drawn into whatever layout direction your app lays out in, so an app running under
I18nManager.isRTL gets right-aligned copy, mirrored buttons, and the close glyph in the top-left corner. An app that stays left-to-right does not. The SDK never forces a direction on you.Personalization
Campaign text can carry placeholders such as{player_name}. See In-App Messaging Campaigns for the list. Just before a message with placeholders displays, the SDK fetches the customer’s current values and fills them in. It waits at most 2 seconds and reuses the values for up to a minute, and every event you send clears them so the next message quotes fresh numbers.
If the request fails, the SDK uses the last values it stored for the customer. Any placeholder still without a value, including every placeholder when the request times out, is removed rather than shown as raw braces, and the message still displays. Messages with no placeholders skip the fetch. Your hooks receive the message as authored, with its placeholders.
Push Permission
React Native has no notification-permission API of its own, so a campaign that asks for one asks you. Without a requester the SDK logs and closes the message rather than pretending. For example, withreact-native-permissions:
Storage and Insets
The SDK keeps in-app messaging state in AsyncStorage, a required peer. The customer’s message history, the campaign cache, unsent analytics, and personalization values survive a restart. If storage cannot be read, messaging still runs, starts empty, and logs why.react-native-safe-area-context is optional and resolved at runtime. When it is installed, messages clear the notch and the home indicator, using the insets the device reports at startup. Without it, the SDK falls back to the status-bar height on Android and to zero elsewhere.
Session Tokens
In-app messaging requests carry the SDK’s current session token asX-GB-TOKEN when it has one, and each sync reports your app’s version. The current token is whatever your last initializeCustomer, sendEvent, logPurchase, or showProfile call passed, so pass it on every call if you use session tokens.
Behavior Reference
The campaign rules themselves are described in In-App Messaging Campaigns. This is what they mean in a React Native app.Logging and Troubleshooting
Passdebug: true to init for a running commentary prefixed [GameballIAM], showing which campaign was chosen, which was passed over, and why. It defaults to __DEV__, so it is on in development builds and off in release builds.
API Reference
init also takes debug?: boolean, which defaults to __DEV__.
Types InAppMessage, MessageButton, ClickAction, MessageType, MessageLayout, MessageOrientation, SlidePosition, MessageStyle, ButtonStyle, TextAlign, BeforeDisplay, DisplayDecision, OnAction, StartInAppMessagingOptions, GameballInAppMessagesProps, PresentedMessage, PresentCallbacks, and Purchase are exported from the package root.
Launch Checklist
1
Initialize at module load
init runs at module load and is awaited before anything else.2
Mount the surface
<GameballInAppMessages /> is mounted once, above the navigator.3
Start and stop messaging
startInAppMessaging is called after a customer is identified, and stopInAppMessaging() is called on logout.4
Wire the hooks
onNavigate if any campaign uses a route action, requestPushPermission if any campaign asks for notifications, and setOverlayOpen bracketing your own modals and checkout steps.5
Check storage and insets
AsyncStorage is installed, safe-area insets come from somewhere, and
debug is off in release builds.Related Articles
In-App Messaging Campaigns
Campaign options, triggers, delivery rules, and analytics definitions.
Track Events
Send the events your campaigns are triggered by.
Push Notifications
Reach customers when the app is closed.
Go-Live Checklist
Verify the full React Native integration before release.