Banners
The Tappd Mobile SDK supports displaying banners created in your Tappd dashboard. Banners are placement-based content that can be rendered in your React Native app, with support for targeting, scheduling, frequency capping, and A/B testing.
Overview
Banners are different from in-app messages:
- Placement-based: Banners are attached to specific screens or components using placement identifiers
- Targeting: Support for customer segments, rules, and targeting conditions
- Scheduling: Start/end dates, active hours, and timezone support
- Frequency Capping: Control how often banners are shown to users
- A/B Testing: Multiple variants with traffic allocation
- Analytics: Track displays, clicks, dismissals, and conversions
Quick Start
The SDK handles all API calls and provides banner data. You can render banners using the provided data:
import TappdSDK from '@tappd/mobile-sdk';
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk'
});
// Identify user first (required for targeting)
await tappd.identify({
external_id: 'user_123',
email: 'john@example.com',
name: 'John Doe'
});
// Fetch banners for a placement
const banners = await tappd.getBanners('HomeScreen');
// Render banners in your UI
banners.forEach(({ banner, variant }) => {
// Render your banner component
});Banner Placement System
Banners use a placement system to attach to specific screens or components. In React Native, placements are typically screen names or component identifiers:
Placement Types
- Screen-based Placement: Attach banners to specific screens
- Component-based Placement: Attach banners to specific components
- Custom Placement: Use custom identifiers for placement
Example:
// Fetch banners for a specific screen
const banners = await tappd.getBanners('HomeScreen');
// Fetch banners for a component
const banners = await tappd.getBanners('header-banner');Fetching Banners
Fetch eligible banners for a specific placement:
// Fetch banners (with caching)
const banners = await tappd.getBanners('HomeScreen');
// Force refresh (bypass cache)
const banners = await tappd.getBanners('HomeScreen', { forceRefresh: true });The SDK automatically:
- Fetches banners from the API
- Caches results for 5 minutes
- Handles API errors gracefully
Banner Response Structure
The API returns an array of banner objects with the following structure:
[
{
banner: {
_id: "banner_id_123",
name: "Summer Sale Banner",
placement: {
type: "css_selector",
cssSelector: "HomeScreen",
dataAttribute: null,
dataAttributeValue: null
}
},
variant: {
_id: "variant_id_456",
name: "Variant A",
content: {
title: "Summer Sale",
message: "Get 50% off on all items!",
imageUrl: "https://example.com/banner.jpg",
link: "https://example.com/sale",
cta: {
text: "Shop Now",
link: "https://example.com/sale",
action: "link"
}
},
design: {
position: "top",
layout: "horizontal",
backgroundColor: "#ffffff",
textColor: "#000000",
ctaBackgroundColor: "#007bff",
ctaTextColor: "#ffffff",
fontFamily: "System",
fontSize: "16px",
padding: "16px",
margin: "0",
borderRadius: "4px"
},
config: {
dismissible: true,
autoHide: false,
autoHideDelay: 5000,
animation: "fade",
closeButton: true
}
}
}
]Rendering Banners in React Native
Create a reusable banner component:
import React, { useState, useEffect } from 'react';
import {
View,
Text,
Image,
TouchableOpacity,
StyleSheet,
Animated,
Linking
} from 'react-native';
import TappdSDK from '@tappd/mobile-sdk';
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk'
});
// Banner Component
function Banner({ banner, variant, onDismiss }) {
const [fadeAnim] = useState(new Animated.Value(0));
const [displayId, setDisplayId] = useState(null);
useEffect(() => {
// Track display
tappd.banners.display(banner._id, variant._id, banner.placement.cssSelector)
.then(id => setDisplayId(id));
// Animate in
Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true
}).start();
// Auto-hide if configured
if (variant.config.autoHide) {
const timer = setTimeout(() => {
handleDismiss();
}, variant.config.autoHideDelay);
return () => clearTimeout(timer);
}
}, []);
const handleDismiss = async () => {
if (displayId) {
await tappd.banners.dismiss(banner._id, displayId);
}
onDismiss();
};
const handleCTAClick = async () => {
if (displayId) {
await tappd.banners.click(banner._id, displayId);
}
// Handle CTA action
const cta = variant.content.cta;
if (cta.action === 'link' && cta.link) {
Linking.openURL(cta.link);
} else if (cta.action === 'close') {
handleDismiss();
}
};
const design = variant.design;
const content = variant.content;
return (
<Animated.View
style={[
styles.banner,
{
opacity: fadeAnim,
backgroundColor: design.backgroundColor,
padding: parseInt(design.padding) || 16,
borderRadius: parseInt(design.borderRadius) || 4,
margin: parseInt(design.margin) || 0
}
]}
>
<View style={styles.content}>
{/* Image */}
{content.imageUrl && (
<Image
source={{ uri: content.imageUrl }}
style={styles.image}
resizeMode="contain"
/>
)}
{/* Text Content */}
<View style={styles.textContainer}>
{content.title && (
<Text
style={[
styles.title,
{
color: design.textColor,
fontSize: parseInt(design.fontSize) || 16
}
]}
>
{content.title}
</Text>
)}
{content.message && (
<Text
style={[
styles.message,
{
color: design.textColor,
fontSize: parseInt(design.fontSize) || 14
}
]}
>
{content.message}
</Text>
)}
</View>
{/* CTA Button */}
{content.cta && content.cta.text && (
<TouchableOpacity
style={[
styles.ctaButton,
{
backgroundColor: design.ctaBackgroundColor,
borderRadius: parseInt(design.borderRadius) || 4
}
]}
onPress={handleCTAClick}
>
<Text
style={[
styles.ctaText,
{ color: design.ctaTextColor }
]}
>
{content.cta.text}
</Text>
</TouchableOpacity>
)}
{/* Close Button */}
{variant.config.dismissible && variant.config.closeButton && (
<TouchableOpacity
style={styles.closeButton}
onPress={handleDismiss}
>
<Text style={styles.closeButtonText}>×</Text>
</TouchableOpacity>
)}
</View>
</Animated.View>
);
}
const styles = StyleSheet.create({
banner: {
width: '100%',
marginBottom: 8
},
content: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between'
},
image: {
width: 60,
height: 60,
marginRight: 12
},
textContainer: {
flex: 1,
marginRight: 12
},
title: {
fontWeight: 'bold',
marginBottom: 4
},
message: {
fontSize: 14
},
ctaButton: {
paddingHorizontal: 16,
paddingVertical: 8,
marginLeft: 8
},
ctaText: {
fontWeight: '600',
fontSize: 14
},
closeButton: {
padding: 8,
marginLeft: 8
},
closeButtonText: {
fontSize: 24,
color: '#666'
}
});
export default Banner;Using Banners in Your App
Integrate banners into your screens:
import React, { useState, useEffect } from 'react';
import { View, StyleSheet, ScrollView } from 'react-native';
import TappdSDK from '@tappd/mobile-sdk';
import Banner from './Banner';
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk'
});
function HomeScreen() {
const [banners, setBanners] = useState([]);
useEffect(() => {
loadBanners();
}, []);
const loadBanners = async () => {
try {
const bannerData = await tappd.getBanners('HomeScreen');
setBanners(bannerData);
} catch (error) {
console.error('Failed to load banners:', error);
}
};
const handleDismiss = (bannerId) => {
setBanners(banners.filter(b => b.banner._id !== bannerId));
};
return (
<ScrollView style={styles.container}>
{/* Render banners at top */}
{banners.map(({ banner, variant }) => (
<Banner
key={banner._id}
banner={banner}
variant={variant}
onDismiss={() => handleDismiss(banner._id)}
/>
))}
{/* Your screen content */}
<View style={styles.content}>
{/* ... */}
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
},
content: {
padding: 16
}
});
export default HomeScreen;Manual Event Tracking
For custom implementations, you can manually track banner events:
Track Display
// Track banner display and get displayId
const displayId = await tappd.banners.display(
bannerId, // Banner ID
variantId, // Variant ID
selector // Placement selector (e.g., 'HomeScreen')
);Track Click
// Track banner click
await tappd.banners.click(bannerId, displayId);Track Dismiss
// Track banner dismiss
await tappd.banners.dismiss(bannerId, displayId);Banner Position Handling
Handle different banner positions:
function Banner({ banner, variant, ...props }) {
const design = variant.design;
const position = design.position || 'top';
const positionStyles = {
top: { position: 'absolute', top: 0, left: 0, right: 0, zIndex: 1000 },
bottom: { position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 1000 },
center: { alignItems: 'center', justifyContent: 'center' }
};
return (
<View style={[styles.banner, positionStyles[position]]}>
{/* Banner content */}
</View>
);
}Complete Example with React Navigation
Integrate banners with React Navigation:
import React, { useState, useEffect } from 'react';
import { View, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import TappdSDK from '@tappd/mobile-sdk';
import Banner from './components/Banner';
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk'
});
const Stack = createStackNavigator();
function App() {
const [banners, setBanners] = useState([]);
const [currentScreen, setCurrentScreen] = useState('Home');
useEffect(() => {
// Identify user
tappd.identify({
external_id: 'user_123',
email: 'john@example.com',
name: 'John Doe'
});
// Load banners for current screen
loadBanners(currentScreen);
}, [currentScreen]);
const loadBanners = async (screenName) => {
try {
const bannerData = await tappd.getBanners(screenName);
setBanners(bannerData);
} catch (error) {
console.error('Failed to load banners:', error);
}
};
const handleDismiss = (bannerId) => {
setBanners(banners.filter(b => b.banner._id !== bannerId));
};
return (
<NavigationContainer>
<View style={styles.container}>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
listeners={{
focus: () => setCurrentScreen('Home')
}}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
listeners={{
focus: () => setCurrentScreen('Profile')
}}
/>
</Stack.Navigator>
{/* Render banners */}
{banners.map(({ banner, variant }) => (
<Banner
key={banner._id}
banner={banner}
variant={variant}
onDismiss={() => handleDismiss(banner._id)}
/>
))}
</View>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
export default App;Banner Features
Targeting
Banners support customer targeting:
- Segments: Target specific customer segments
- Rules: Custom targeting rules based on customer attributes
- Enabled/Disabled: Toggle targeting on/off
Banners with targeting enabled will only be returned if the customer matches the targeting criteria.
Scheduling
Banners support scheduling:
- Start/End Dates: Set when banners should be active
- Active Hours: Define specific hours when banners should display
- Active Days: Define specific days of the week
- Timezone: Set timezone for schedule calculations
Frequency Capping
Control how often banners are shown:
- Max Displays: Maximum number of times to show a banner
- Period: Time period (session, hour, day, week, month)
- Enabled/Disabled: Toggle frequency capping
A/B Testing
Banners support A/B testing with variants:
- Multiple Variants: Create multiple banner variants
- Traffic Allocation: Control percentage of traffic for each variant
- Experiment Assignment: Automatic variant assignment based on customer ID
Analytics
Banners track comprehensive analytics:
- Views: Number of times banner was displayed
- Clicks: Number of times banner was clicked
- Dismissals: Number of times banner was dismissed
- Conversions: Number of conversions from banner
- CTR: Click-through rate (clicks / views)
Best Practices
- Identify Users Early: Call
identify()before fetching banners to enable targeting - Screen-based Placement: Use screen names as placement identifiers for easy management
- Track All Interactions: Use
banners.display(),banners.click(), andbanners.dismiss()for accurate analytics - Handle Navigation: Reload banners when navigating between screens
- Error Handling: Handle API errors gracefully
- Performance: SDK caches banners for 5 minutes to reduce API calls
- Responsive Design: Ensure banners work on different screen sizes
- Animation: Use React Native Animated API for smooth animations
Troubleshooting
Banners not displaying
- Check that user is identified (
identify()has been called) - Verify placement identifier matches screen/component name
- Check console for errors
- Verify banner is active and published in dashboard
- Check targeting conditions are met
- Verify schedule is active
- Check frequency capping hasn't been reached
Banners displaying incorrectly
- Check banner styles are applied correctly
- Verify container dimensions
- Check for style conflicts
- Ensure proper positioning styles
Tracking not working
- Verify API endpoints are correct (check
apiUrlconfig) - Check that
displayIdis stored and passed correctly - Check console for network errors
- Verify App ID is correct
API Reference
getBanners(selector, options?)
Fetch banners for a placement.
Parameters:
selector(string): Placement identifier (screen name, component name, etc.)options(object, optional):forceRefresh(boolean): Force refresh and bypass cache (default:false)
Returns: Promise<Banner[]> - Array of banner data
banners.display(bannerId, variantId, selector)
Manually track banner display.
Parameters:
bannerId(string): Banner IDvariantId(string): Variant IDselector(string): Placement selector
Returns: Promise<string> - Display ID for use with click/dismiss
banners.click(bannerId, displayId)
Manually track banner click.
Parameters:
bannerId(string): Banner IDdisplayId(string): Display ID frombanners.display()
Returns: Promise<void>
banners.dismiss(bannerId, displayId)
Manually track banner dismiss.
Parameters:
bannerId(string): Banner IDdisplayId(string): Display ID frombanners.display()
Returns: Promise<void>
Related Documentation
- In-App Messages - Different from banners, these are trigger-based messages
- API Reference - Complete API documentation
- Configuration - All configuration options
- Examples - Code examples
- React Navigation Integration - Integration guide
