In-App Messages
The Tappd Mobile SDK supports displaying in-app messages (banners, popups, and modals) created in your Tappd dashboard. Messages are automatically fetched and displayed when enabled, and you can integrate them into your React Native app using the provided components.
Overview
In-app messages allow you to:
- Display personalized messages to users based on their behavior
- Show banners at the top or bottom of the screen
- Display popups and modals with rich content
- Track message views, clicks, and dismissals
- Automatically evaluate trigger conditions and expiration dates
Configuration
Enable in-app messages when initializing the SDK:
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk',
enableInAppMessages: true, // Enable in-app message rendering (default: true)
autoDisplayMessages: true, // Automatically display pending messages (default: true)
messagePollingInterval: 30, // Poll for new messages every 30 seconds (default: 30)
});Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
enableInAppMessages | boolean | true | Enable/disable in-app message rendering |
autoDisplayMessages | boolean | true | Automatically fetch and display pending messages |
messagePollingInterval | number | 30 | Interval in seconds for polling new messages |
React Native Integration
To render messages in your React Native app, you need to set up a render callback that displays the message components.
Basic Setup
import React, { useState, useEffect } from 'react';
import { View } from 'react-native';
import TappdSDK from '@tappd/mobile-sdk';
import { MessageRenderer } from '@tappd/mobile-sdk/src/renderers/MessageRenderer';
import type { InAppMessage } from '@tappd/mobile-sdk/src/types/inAppMessage';
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
enableInAppMessages: true,
autoDisplayMessages: true
});
function App() {
const [currentMessage, setCurrentMessage] = useState<InAppMessage | null>(null);
useEffect(() => {
// Set callback for rendering messages
tappd.setMessageRenderCallback((message: InAppMessage) => {
setCurrentMessage(message);
});
}, []);
const handleDismiss = async (messageId: string) => {
await tappd.dismissMessage(messageId);
setCurrentMessage(null);
};
const handleButtonClick = async (messageId: string, link: string, text: string) => {
// Handle button click (e.g., navigation)
console.log('Button clicked:', link);
await handleDismiss(messageId);
};
return (
<View style={{ flex: 1 }}>
{/* Your app content */}
{/* Render in-app message */}
{currentMessage && (
<MessageRenderer
message={currentMessage}
onDismiss={handleDismiss}
onButtonClick={handleButtonClick}
/>
)}
</View>
);
}Automatic Display
When autoDisplayMessages is enabled, the SDK will:
- Automatically fetch pending messages for the identified user
- Evaluate trigger conditions (immediate, delay, event-based)
- Call the render callback for messages that are ready to be shown
- Track events (viewed, clicked, dismissed)
- Poll periodically for new messages (based on
messagePollingInterval)
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
enableInAppMessages: true,
autoDisplayMessages: true,
messagePollingInterval: 30 // Check for new messages every 30 seconds
});
// Identify user - messages will be fetched automatically
await tappd.identify({
external_id: 'user_123',
email: 'john@example.com',
name: 'John Doe'
});
// Set render callback to display messages
tappd.setMessageRenderCallback((message) => {
// Display the message in your UI
setCurrentMessage(message);
});Manual Control
You can also manually control message fetching and display:
Fetch Messages
// Fetch all pending messages for the current user
const messages = await tappd.getInAppMessages();
console.log(`Found ${messages.length} pending messages`);Display a Specific Message
const messages = await tappd.getInAppMessages();
// Display the first message
if (messages.length > 0) {
await tappd.displayInAppMessage(messages[0]);
}Display All Pending Messages
// Fetch and display all pending messages
await tappd.displayPendingMessages();Dismiss a Message
// Dismiss a message by its ID
await tappd.dismissMessage('message_id_123');Message Types
The SDK supports three message types, each rendered as React Native components:
1. Banner
Banners are fixed-position messages that appear at the top or bottom of the screen using absolute positioning.
- Position: Top or bottom
- Dismissible: Can include a dismiss button
- Animation: Slide animation
- Use cases: Important announcements, notifications, promotions
2. Popup
Popups are centered modal dialogs with an optional overlay using React Native's Modal component.
- Size: Smaller modal (typically 90% of screen width, max 500px)
- Overlay: Optional semi-transparent background overlay
- Close button: Optional close button
- Animation: Fade or scale animation
- Use cases: Important alerts, confirmations, CTAs
3. Modal
Modals are larger centered modal dialogs, similar to popups but with more space.
- Size: Larger modal (typically 85% of screen width, max 600px)
- Overlay: Optional semi-transparent background overlay
- Close button: Optional close button
- Animation: Fade or scale animation
- Use cases: Detailed information, forms, multi-step flows
Message Blocks
Messages can contain multiple content blocks rendered as React Native components:
Image Block
Display images using React Native's Image component.
Properties:
url- Image URLalt- Alt text for accessibilitywidth- Image widthheight- Image heightalignment- left, center, right, or full
Text Block
Display text content using React Native's Text component.
Properties:
content- Text contentfontSize- sm, base, lg, xl, 2xl, or custom sizefontWeight- normal or boldcolor- Text color (hex, rgb, or named color)alignment- left, center, right, or justify
Button Block
Clickable buttons using React Native's TouchableOpacity or Pressable.
Properties:
text- Button textlink- URL to navigate to (usesLinking.openURL())textColor- Button text colorbackgroundColor- Button background colorlinkBehavior- browser (open URL), in_app, or deeplinkalignment- left, center, or right
HTML Block
Basic HTML content rendering (for full HTML support, consider using react-native-render-html).
Properties:
content- HTML content (simplified rendering - strips tags and displays text)
Note: For full HTML rendering, you can enhance the HtmlBlock component to use react-native-render-html.
Event Tracking
The SDK automatically tracks message interactions:
Message Viewed
Tracked when a message is displayed:
// Automatically tracked by SDK
// Event: message.viewed
// Properties: { messageId: '...' }Message Clicked
Tracked when a button in a message is clicked:
// Automatically tracked by SDK
// Event: message.clicked
// Properties: { messageId: '...', buttonText: '...', buttonLink: '...' }Message Dismissed
Tracked when a message is dismissed:
// Automatically tracked by SDK
// Event: message.dismissed
// Properties: { messageId: '...' }Manual Event Tracking
You can also manually track message events:
await tappd.trackMessageEvent('message_id_123', 'clicked', {
buttonText: 'Sign Up',
buttonLink: 'https://example.com/signup'
});API Reference
setMessageRenderCallback(callback)
Set a callback function that will be called when a message should be displayed.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
callback | (message: InAppMessage) => void | Yes | Function called with the message to display |
Returns: void
Example:
tappd.setMessageRenderCallback((message) => {
setCurrentMessage(message);
});getInAppMessages()
Fetch pending in-app messages for the current user.
Returns: Promise<InAppMessage[]>
Example:
const messages = await tappd.getInAppMessages();
messages.forEach(message => {
console.log(`Message: ${message.config.messageType}`);
console.log(`Status: ${message.status}`);
});displayInAppMessage(message)
Display a specific in-app message. This will call the render callback if set.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
message | InAppMessage | Yes | The message object to display |
Returns: Promise<void>
Example:
const messages = await tappd.getInAppMessages();
if (messages.length > 0) {
await tappd.displayInAppMessage(messages[0]);
}displayPendingMessages()
Fetch and display all pending messages that are ready to be shown.
Returns: Promise<void>
Example:
// Manually trigger message display
await tappd.displayPendingMessages();dismissMessage(messageId)
Dismiss a message and track the dismissal event.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
messageId | string | Yes | The ID of the message to dismiss |
Returns: Promise<void>
Example:
await tappd.dismissMessage('message_id_123');trackMessageEvent(messageId, eventType, metadata)
Track a custom message interaction event.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
messageId | string | Yes | The ID of the message |
eventType | string | Yes | Event type (e.g., 'viewed', 'clicked', 'dismissed') |
metadata | object | No | Additional event metadata |
Returns: Promise<void>
Example:
await tappd.trackMessageEvent('message_id_123', 'clicked', {
buttonText: 'Get Started',
buttonLink: '/signup'
});Complete Example
Here's a complete example showing how to integrate in-app messages in a React Native app:
import React, { useState, useEffect } from 'react';
import { View, StyleSheet } from 'react-native';
import TappdSDK from '@tappd/mobile-sdk';
import { MessageRenderer } from '@tappd/mobile-sdk/src/renderers/MessageRenderer';
import type { InAppMessage } from '@tappd/mobile-sdk/src/types/inAppMessage';
// Initialize SDK with in-app messages enabled
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk',
enableInAppMessages: true,
autoDisplayMessages: true,
messagePollingInterval: 30,
debug: true
});
export default function App() {
const [currentMessage, setCurrentMessage] = useState<InAppMessage | null>(null);
useEffect(() => {
// Set callback for rendering messages
tappd.setMessageRenderCallback((message: InAppMessage) => {
setCurrentMessage(message);
});
// Identify user - messages will be fetched automatically
tappd.identify({
external_id: 'user_123',
email: 'john@example.com',
name: 'John Doe'
});
return () => {
// Cleanup
tappd.setMessageRenderCallback(() => {});
};
}, []);
const handleDismiss = async (messageId: string) => {
await tappd.dismissMessage(messageId);
setCurrentMessage(null);
};
const handleButtonClick = async (
messageId: string,
link: string,
text: string
) => {
// Handle button click - you can navigate, open URL, etc.
console.log('Button clicked:', { messageId, link, text });
// Example: Open URL
if (link && link !== '#') {
Linking.openURL(link);
}
// Dismiss message after handling click
await handleDismiss(messageId);
};
return (
<View style={styles.container}>
{/* Your app content */}
{/* Render in-app message */}
{currentMessage && (
<MessageRenderer
message={currentMessage}
onDismiss={handleDismiss}
onButtonClick={handleButtonClick}
/>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});Integration with React Navigation
You can integrate messages with React Navigation by displaying them at the root level:
import { NavigationContainer } from '@react-navigation/native';
import TappdSDK from '@tappd/mobile-sdk';
import { MessageRenderer } from '@tappd/mobile-sdk/src/renderers/MessageRenderer';
function App() {
const [currentMessage, setCurrentMessage] = useState(null);
useEffect(() => {
tappd.setMessageRenderCallback((message) => {
setCurrentMessage(message);
});
}, []);
return (
<NavigationContainer>
{/* Your navigation structure */}
{/* Messages displayed at root level */}
{currentMessage && (
<MessageRenderer
message={currentMessage}
onDismiss={(id) => {
tappd.dismissMessage(id);
setCurrentMessage(null);
}}
/>
)}
</NavigationContainer>
);
}Styling
Message components use React Native StyleSheet for styling. You can customize styles by:
- Modifying the component styles - Edit the styles in
MessageRenderer.tsxandBlockRenderer.tsx - Using theme providers - Wrap message components with your theme provider
- Platform-specific styles - Use
Platform.OSfor iOS/Android specific styling
Best Practices
- Identify users early: Make sure to call
identify()as soon as users log in so messages can be personalized - Set render callback: Always set the render callback in your app's root component
- Handle navigation: Implement proper navigation logic in button click handlers
- Monitor message performance: Use the tracked events to measure message effectiveness
- Test on both platforms: Test messages on both iOS and Android devices
- Handle app state: Consider pausing message display when app goes to background
Troubleshooting
Messages not displaying
- Check that
enableInAppMessagesis set totrue - Verify the render callback is set using
setMessageRenderCallback() - Verify the user is identified (
identify()has been called) - Check console for errors (enable
debug: true) - Verify messages exist in the dashboard and are published
- Check trigger conditions are met
Messages displaying too frequently
- Adjust
messagePollingIntervalto reduce polling frequency - Check message expiration settings in the dashboard
- Ensure messages are being dismissed properly
Styling issues
- Check for style conflicts with your app's styles
- Ensure message components are rendered at the correct level in the component tree
- Test on both iOS and Android as styles may differ
Related Documentation
- API Reference - Complete API documentation
- Configuration - All configuration options
- Examples - Code examples
- React Navigation Integration - Integration guide
