adobe-dynamic-target
v1.1.0
Published
Dynamic, headless Adobe Target and Experience Platform integration for React Native with pluggable remote configuration providers.
Maintainers
Readme
adobe-dynamic-target
Dynamic, headless Adobe Target and Experience Platform (AEP) integration for React Native with pluggable remote configuration providers (Firebase Remote Config, LaunchDarkly, Statsig, REST APIs, or local config).
✨ Features
- 🚀 Zero-Code Native Setup: Automatically registers native AEP Mobile SDK extensions on Android (
androidx.startup) and iOS without modifyingMainApplication.ktorAppDelegate. - 🎯 Headless Placements (
<TargetPlacement />): Render personalized offers with 100% UI freedom — native components, custom JSON cards, or interactive HTML WebViews. - 🔄 Dynamic Scope Resolution: Decouple hardcoded mbox names from your codebase using pluggable placement resolvers (e.g. Firebase Remote Config).
- 📊 Automatic Impression & Click Tracking: Handles display tracking (
trackOfferDisplay) and engagement analytics (trackOfferTap) out of the box. - 📱 Screen-Level Tracking Hook: Track page views on navigation focus using
useScreenTracking. - 🔐 Identity Management: Hash and sync authenticated user IDs (e.g. Email) to AEP Edge Identity with cache clearing.
- 🛠️ Adobe Assurance Ready: Built-in support for Adobe Assurance PIN verification via deep links.
📦 Installation
npm install adobe-dynamic-targetPeer Dependencies
Install the required Adobe Mobile SDK packages:
npm install @adobe/react-native-aepcore @adobe/react-native-aepedge @adobe/react-native-aepedgeidentity @adobe/react-native-aepoptimize @adobe/react-native-aepassurance @adobe/react-native-aepedgeconsent @react-navigation/native react-native-safe-area-context react-native-screensiOS Note: Run
pod installin yourios/folder:cd ios && pod install
⚡ Quick Start
1. Configure the Provider at App Root
Wrap your root application with <AdobeTargetProvider>:
import React from 'react';
import { AdobeTargetProvider } from 'adobe-dynamic-target';
import { NavigationContainer } from '@react-navigation/native';
import { RootNavigator } from './src/navigation/RootNavigator';
const ADOBE_CONFIG = {
environmentId: 'your-launch-environment-id',
defaultDatastreamId: 'your-datastream-id',
orgId: 'YOUR_ORG_ID@AdobeOrg',
// Optional: Assurance session URL for validation
assuranceSessionUrl: 'myapp://?adb_validation_sessionid=...',
};
// Optional fallback placement mappings
const FALLBACK_MAPPINGS = {
dashboard: {
p1: 'mbox_dashboard_hero',
p2: 'mbox_dashboard_offers',
},
credit_cards: {
p3: 'mbox_cards_featured',
},
};
export default function App() {
return (
<AdobeTargetProvider
config={ADOBE_CONFIG}
fallbackMappings={FALLBACK_MAPPINGS}
// Pluggable resolver function (Firebase Remote Config, REST API, etc.)
placementResolver={async () => {
// e.g. return fetchRemoteConfigMappings();
return FALLBACK_MAPPINGS;
}}
>
<NavigationContainer>
<RootNavigator />
</NavigationContainer>
</AdobeTargetProvider>
);
}2. Render Target Placements in Screens
Use <TargetPlacement /> to render offers with complete UI freedom:
import React from 'react';
import { View, Text, TouchableOpacity, ActivityIndicator, StyleSheet } from 'react-native';
import { TargetPlacement, useScreenTracking } from 'adobe-dynamic-target';
export const DashboardScreen: React.FC = () => {
// Automatically tracks page view on screen focus
const { trackClick: trackAction } = useScreenTracking('dashboard_page', 'dashboard');
return (
<View style={styles.container}>
<Text style={styles.heading}>Welcome to Digital Bank</Text>
{/* Dynamic Target Offer Placement */}
<TargetPlacement screen="dashboard" placement="p1">
{({ content, isLoading, isHtml, trackClick, scope }) => {
if (isLoading) {
return <ActivityIndicator color="#0066cc" />;
}
// Case 1: Live Adobe Target Proposition
if (content) {
return (
<TouchableOpacity activeOpacity={0.85} onPress={trackClick} style={styles.offerCard}>
<Text style={styles.badge}>Live Offer {scope ? `(${scope})` : ''}</Text>
<Text style={styles.title}>{content.heading || content.title || 'Special Deal'}</Text>
<Text style={styles.desc}>{content.subHeading || content.description}</Text>
<View style={styles.button}>
<Text style={styles.buttonText}>{content.cta || 'Claim Offer'}</Text>
</View>
</TouchableOpacity>
);
}
// Case 2: Fallback UI when no offer qualifies
return (
<View style={styles.fallbackCard}>
<Text style={styles.title}>Pre-approved Credit Card</Text>
<Text style={styles.desc}>Unlock travel perks curated for your account.</Text>
</View>
);
}}
</TargetPlacement>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, padding: 16 },
heading: { fontSize: 22, fontWeight: 'bold', marginBottom: 16 },
offerCard: { backgroundColor: '#fff', borderRadius: 14, padding: 18, elevation: 3 },
fallbackCard: { backgroundColor: '#f2f2f7', borderRadius: 14, padding: 18 },
badge: { color: '#00875A', fontWeight: 'bold', fontSize: 11, marginBottom: 4 },
title: { fontSize: 18, fontWeight: 'bold', color: '#1a1a1a', marginBottom: 6 },
desc: { fontSize: 14, color: '#555', marginBottom: 12 },
button: { backgroundColor: '#0066cc', paddingVertical: 10, paddingHorizontal: 16, borderRadius: 8, alignSelf: 'flex-start' },
buttonText: { color: '#fff', fontWeight: 'bold' },
});3. User Login & Identity Sync
When a user logs in, synchronize their identity (e.g. Email) to AEP Edge Identity with SHA-256 hashing and cache invalidation:
import { syncUserIdentity, resetUserIdentity } from 'adobe-dynamic-target';
// On Login:
await syncUserIdentity('[email protected]', 'Email');
// On Logout:
await resetUserIdentity();🔌 Dynamic Configuration with Firebase Remote Config
You can dynamically update target placement mbox names in real time without publishing app updates:
Firebase Remote Config Parameter
Create a parameter in Firebase Console:
- Key:
rn_target_placement_mappings - Type:
JSONorString - Value:
{
"dashboard": {
"p1": "mbox_db_123",
"p2": ""
},
"credit_cards": {
"p3": "mbox_db_123",
"p4": "mbox_db_234"
}
}Resolver Code:
import remoteConfig from '@react-native-firebase/remote-config';
export const resolveRemoteConfigMappings = async () => {
try {
await remoteConfig().fetchAndActivate();
const rawJson = remoteConfig().getValue('rn_target_placement_mappings').asString();
if (rawJson) {
return JSON.parse(rawJson);
}
} catch (error) {
console.warn('Failed to fetch remote config:', error);
}
return FALLBACK_MAPPINGS;
};Pass resolveRemoteConfigMappings to <AdobeTargetProvider placementResolver={resolveRemoteConfigMappings} />.
📖 API Reference
<AdobeTargetProvider />
| Prop | Type | Required | Description |
|---|---|---|---|
| config | AdobeSDKConfig | Yes | Adobe Launch / Experience Platform configuration object. |
| placementResolver | () => Promise<PlacementMappings> | No | Dynamic async function to resolve screen $\rightarrow$ placement mbox mappings. |
| fallbackMappings | PlacementMappings | No | Initial static mapping used before remote resolver loads. |
AdobeSDKConfig
| Field | Type | Description |
|---|---|---|
| environmentId | string | Adobe Launch Environment / Mobile App ID. |
| defaultDatastreamId | string | AEP Edge Datastream ID. |
| orgId | string | Adobe Experience Cloud Organization ID (...@AdobeOrg). |
| assuranceSessionUrl | string? | Optional Assurance URL to connect automatically on boot. |
| logLevel | 'debug' \| 'warning' \| 'error' | Log level for Adobe SDK (default: 'debug'). |
<TargetPlacement />
Render-props component for headless target offer rendering.
| Prop | Type | Description |
|---|---|---|
| screen | string | Screen key (e.g. 'dashboard', 'credit_cards'). |
| placement | string | Placement identifier within the screen (e.g. 'p1', 'p2'). |
| scopeOverride | string? | Optional manual mbox scope name overriding remote config. |
| profileParameters| Record<string, string>? | Profile parameters for Target query. |
| mboxParameters | Record<string, string>? | Mbox parameters for Target query. |
| autoTrackDisplay | boolean? | Automatically track impression on mount (default: true). |
Render Prop Callback Arguments:
content: Parsed JSON object, string, ornull.rawContent: Raw string payload from Adobe Target.isHtml:trueif the content contains HTML tags.isLoading:truewhile resolving mapping or querying propositions.scope: The resolved mbox scope name (e.g.'mbox_db_123').trackClick(): Function to track engagement click event.trackDisplay(): Function to manually record impression.refresh(): Function to refetch the proposition.
Hooks & Utilities
useScreenTracking(pageName, siteSection, extraData): Automatically track screen page view on focus.useTargetPlacement({ screen, placement, ... }): Headless hook version of<TargetPlacement />.syncUserIdentity(identifier, namespace?): Hashing and syncing user identity to Edge.resetUserIdentity(): Clear user identities and Target cached propositions.startAssuranceSession(url): Start Adobe Assurance session.
📄 License
MIT © Devaraj
