react-native-target-kit
v1.3.3
Published
Zero-boilerplate Adobe Target & AJO Decisioning SDK for React Native with dynamic Firebase Remote Config and custom UI renderer support.
Maintainers
Readme
React Native Target Kit (react-native-target-kit)
An enterprise-grade, high-performance Server-Driven UI (SDUI) and Personalization SDK for React Native, designed for Adobe Target, Adobe Journey Optimizer (AJO) Decisioning, and Adobe Experience Platform (AEP) Edge Network.
Deliver personalized, dynamic UI experiences and execute real-time content experiments across mobile applications without requiring App Store or Google Play releases.
📑 Table of Contents
- Architectural Overview
- Key Capabilities
- Installation & Setup
- Core Integration Patterns
- Server-Driven UI (SDUI) Reference
- Extensibility: Registering Custom Renderers
- Automated Analytics & Telemetry Lifecycle
- Performance & Network Optimization
- API Reference
- License
🏛️ Architectural Overview
react-native-target-kit decouples marketing and product experimentation from client release cycles:
┌─────────────────────────────────────────────────────────────────────────┐
│ Adobe Experience Platform / Adobe Target Cloud │
│ (Activities, Automated Personalization, A/B Test Campaigns) │
└────────────────────────────────────┬────────────────────────────────────┘
│ Edge Delivery (JSON Proposition)
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ @adobe/react-native-aepoptimize │
│ (Adobe Mobile Core & Edge TurboModule) │
└────────────────────────────────────┬────────────────────────────────────┘
│ Proposition Map
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ react-native-target-kit Core Engine │
│ ┌───────────────────────────┐ ┌─────────────────────────────┐ │
│ │ TargetContentManager │ ◄─────► │ SelectorRegistry │ │
│ │ (1-Call Batching, Cache) │ │ (Remote Config / Mappings) │ │
│ └─────────────┬─────────────┘ └─────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────┐ ┌─────────────────────────────┐ │
│ │ Schema Validator (Zod) │ ◄─────► │ RendererRegistry │ │
│ │ (Fail-Safe Fallbacks) │ │ (SDUI & Bespoke Components) │ │
│ └─────────────┬─────────────┘ └──────────────┬──────────────┘ │
└────────────────┼──────────────────────────────────────┼─────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Native React Native UI Layers │
│ <TargetSlot /> ──► Dynamic SDUI / Carousels / Banking Suites │
│ Automated View Impressions (displayed) & Conversion Clicks (tapped)│
└─────────────────────────────────────────────────────────────────────────┘✨ Key Capabilities
- Zero-Boilerplate Declarative Slots: Render personalized experiences with
<TargetSlot selectorId="hero_banner" />. - Full-Spectrum Server-Driven UI (SDUI): Universal recursive layout engine supporting nested boxes, typography, cards, carousels, modals, and interactive buttons.
- Dynamic Multi-Button Action Routing: Handle 1, 2, or 3+ CTA buttons with automatic deep links, custom routes, and callback telemetry.
- 1-Call Request Batching: Consolidate multiple target slots across a screen into a single network call to the Adobe Edge Network via
<TargetProvider screen="..." />. - Fail-Safe Fallback System: Automatic schema validation prevents UI crashes; seamlessly serves bundled native fallbacks if offline or timed out.
- Automated Interaction Telemetry: Out-of-the-box impression tracking (
item.displayed) and conversion metric logging (item.tapped). - Dynamic Scope Re-routing: Change mbox-to-placement mappings at runtime via Firebase Remote Config or REST APIs without app updates.
- Pluggable Architecture: Easily switch between
RealOptimizeAdapterin production andMockOptimizeAdapterfor unit tests and Storybook development.
📦 Installation & Setup
1. Install Dependencies
npm install react-native-target-kit
# or
yarn add react-native-target-kit2. Peer Dependencies
Install the official Adobe Experience Platform Mobile SDK packages:
npm install @adobe/react-native-aepcore @adobe/react-native-aepedge @adobe/react-native-aepedgeidentity @adobe/react-native-aepoptimize(iOS Pod Installation):
cd ios && pod install && cd ..(Optional — for Firebase Remote Config integration):
npm install @react-native-firebase/app @react-native-firebase/remote-config3. Application Initialization
Initialize the Adobe SDK and configure TargetKit in your application's entry point (e.g., App.tsx or index.ts):
import { MobileCore, LogLevel } from '@adobe/react-native-aepcore';
import { Edge } from '@adobe/react-native-aepedge';
import { Identity } from '@adobe/react-native-aepedgeidentity';
import { Optimize } from '@adobe/react-native-aepoptimize';
import { TargetKit, RealOptimizeAdapter } from 'react-native-target-kit';
export async function initializePersonalization(): Promise<void> {
try {
MobileCore.setLogLevel(LogLevel.DEBUG);
// 1. Register Adobe Extensions
await MobileCore.registerExtensions([
Edge.extension,
Identity.extension,
Optimize.extension,
]);
// 2. Configure Adobe Core with Environment App ID
await MobileCore.configureWithAppId('YOUR_ADOBE_MOBILE_APP_ID');
// 3. Connect TargetKit to Adobe Optimize SDK
TargetKit.setAdapter(new RealOptimizeAdapter());
// 4. Register Placement-to-Scope Mappings (or use Remote Config)
TargetKit.hydrate('DashboardScreen', {
hero_placement: 'mbox_dashboard_hero',
credit_card_offer: 'mbox_credit_card_promo',
});
console.log('✅ Personalization engine initialized successfully');
} catch (error) {
console.error('❌ Personalization initialization failed:', error);
}
}🎯 Core Integration Patterns
1. Standard Declarative Slot
Drop <TargetSlot /> anywhere in your component tree. The SDK handles loading skeletons, proposition resolution, rendering, and impression logging automatically.
import React from 'react';
import { TargetSlot } from 'react-native-target-kit';
import { FallbackHeroBanner } from './components/FallbackHeroBanner';
export function DashboardHeader() {
return (
<TargetSlot
selectorId="hero_placement"
fallbackComponent={<FallbackHeroBanner />}
showShimmer={true}
/>
);
}2. Multi-Action & Deep Link Routing
When returning dynamic layouts containing multiple buttons or links, intercept user actions using the onTapped callback:
import React from 'react';
import { TargetSlot } from 'react-native-target-kit';
import { useNavigation } from '@react-navigation/native';
export function PromotionalSlot() {
const navigation = useNavigation();
return (
<TargetSlot
selectorId="promo_banner"
onTapped={(action, envelope) => {
console.log(`Action triggered: ${action} | Offer: ${envelope?.offerId}`);
switch (action) {
case 'action://apply_loan':
navigation.navigate('LoanApplicationScreen');
break;
case 'action://dismiss':
// Custom dismissal logic
break;
default:
// Handled automatically if standard URI (https:// or myapp://)
break;
}
}}
/>
);
}3. Headless / Render-Props Mode
For scenarios requiring customized animations, gesture handlers, or bespoke JSX layouts:
import React from 'react';
import { View, Text, TouchableOpacity, ActivityIndicator } from 'react-native';
import { TargetSlot } from 'react-native-target-kit';
export function CustomHeroSlot() {
return (
<TargetSlot selectorId="hero_placement">
{({ envelope, loading, onTapped }) => {
if (loading) return <ActivityIndicator size="small" color="#2563EB" />;
if (!envelope) return null;
const { headline, ctaText } = envelope.payload;
return (
<View style={styles.customCard}>
<Text style={styles.title}>{headline}</Text>
<TouchableOpacity onPress={() => onTapped?.('action://custom_press')}>
<Text style={styles.button}>{ctaText}</Text>
</TouchableOpacity>
</View>
);
}}
</TargetSlot>
);
}4. Screen-Level Selective Replacement
Wrap a native layout with <TargetSlot selectorId="screen_id">. Components with matching id props are dynamically replaced with Target offers; non-matching components render their native default UI:
import React from 'react';
import { TargetSlot } from 'react-native-target-kit';
import { NativeHeroBanner, NativeQuickActions, NativePromoCard } from './components';
export function HomeScreen() {
return (
<TargetSlot selectorId="homescreen_placement">
{/* If Target returns an offer for 'banner_hero', this Banner is replaced */}
<NativeHeroBanner id="banner_hero" />
{/* Renders default native view unless targeted by Adobe */}
<NativeQuickActions id="quick_actions" />
<NativePromoCard id="promo_card" />
</TargetSlot>
);
}🌲 Server-Driven UI (SDUI) Reference
Content Envelope Specification
Every JSON payload returned by Adobe Target must adhere to the ContentEnvelope contract:
interface ContentEnvelope<T = Record<string, unknown>> {
/** Contract specification version (currently '1.0') */
schemaVersion: '1.0';
/** Target slot identifier (maps to <TargetSlot selectorId="..." />) */
selectorId: string;
/** Adobe Target Activity / Offer ID (used for telemetry metrics) */
offerId: string;
/** Adobe Decision Scope (mbox) name */
decisionScope?: string;
/** UI Renderer key (e.g., 'dynamic_layout', 'banner', 'carousel') */
componentType: ComponentType;
/** Component-specific data model */
payload: T;
}SDUI Primitives Catalog
When using "componentType": "dynamic_layout", you can assemble UI layouts using recursive primitive nodes:
| Primitive Node | Description | Key JSON Properties | Example Use Case |
| :--- | :--- | :--- | :--- |
| box | Flexbox layout container with complete style token support | children, style (padding, bg, flex, gap, border) | Container wrappers, columns, rows |
| card | Elevated surface container with preset border radius | children, style, elevation, shadowColor | Floating promotional cards |
| text | Typography element with weight, size, color, & alignment | text, style (fontSize, color, fontWeight, textAlign) | Headings, subtext, disclaimers |
| image | Responsive remote image with aspect ratio control | url, aspectRatio, resizeMode, style | Product imagery, hero artwork |
| button | Interactive CTA with deep link / action handling | label, action, variant (primary, secondary, outline) | "Apply Now", "Learn More" |
| button_group | Multi-button grid / row (1, 2, or 3+ action buttons) | direction (row/column), buttons: Array<ButtonNode> | Dual CTAs ("Accept" / "Decline") |
| carousel | Horizontal scrollable card slider with pagination | items: Array<{ headline, imageUrl, action }>, showDots | Feature sliders, product carousels |
| modal | Interactive slide-up bottom sheet or dialog popup | triggerButtonText, presentationStyle, title, children | "View Terms & Conditions" sheet |
| badge / tag | Status chip indicator with themed styling | label, style, variant (success, warning, info) | "PRE-APPROVED", "LIMITED TIME" |
| accordion | Collapsible disclosure section with toggle state | title, defaultExpanded, children | FAQ sections, fee breakdowns |
| countdown_timer| Animated countdown timer linked to target timestamp | targetTimestamp, label, digitStyle, expiredMessage | "Offer expires in 02:45:10" |
| rating | 5-star review display with review count metric | rating (0-5), starSize, starColor, totalReviewsText | "4.9 ★ (1,420 Reviews)" |
| progress_bar | Horizontal completion track | progress (0.0 - 1.0), trackColor, progressColor | Credit limit usage, profile completion |
| divider / spacer| Structural layout spacing or hairline rule | color, thickness, size | Section separation |
Enterprise Banking & Domain Renderers
The SDK includes turnkey enterprise banking components auto-registered on import:
| componentType | Backing Renderer | Key Data Fields | Use Case |
| :--- | :--- | :--- | :--- |
| banner | BannerRenderer | imageUrl, headline, subheadline, ctaText, deepLink | General marketing banners |
| carousel | CarouselRenderer | items: Array<{ headline, imageUrl, deepLink }>, showDots | Product & feature carousels |
| text_block | TextBlockRenderer | title, body, actionText, deepLink, backgroundColor | Alerts, advisories, notifications |
| cta_deeplink | CtaRenderer | label, deepLink, style | Standalone action triggers |
| credit_card_offer | CreditCardOfferRenderer | cardName, creditLimit, cardImageUrl, perks, applyUrl | Pre-approved credit card offers |
| deposit_offer | DepositOfferRenderer | interestRate, maturityAmount, tenure, ctaUrl | High-yield FD/Savings booster |
| bill_reminder_offer | BillReminderRenderer | billerName, amountDue, dueDate, cashbackText, payUrl | Utility bill reminders |
| rewards_summary_offer| RewardsSummaryRenderer | pointsBalance, expiringPoints, expiryDate, partners | Loyalty reward point balances |
| wealth_sip_offer | WealthSipRenderer | fundName, monthlyAmount, expectedReturn, taxSaving | Mutual fund & SIP recommendations |
| instant_loan_offer | InstantLoanRenderer | loanAmount, interestRate, tenureMonths, monthlyEmi | Pre-approved loan with EMI preview |
🧩 Extensibility: Registering Custom Renderers
Add your own custom React Native components for any custom componentType:
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { RendererRegistry, RendererProps } from 'react-native-target-kit';
interface EmiCalculatorPayload {
maxAmount: number;
interestRate: number;
}
export function EmiCalculatorRenderer({
envelope,
onTapped,
}: RendererProps<EmiCalculatorPayload>) {
const { maxAmount, interestRate } = envelope.payload;
return (
<View style={styles.container}>
<Text style={styles.title}>Calculate Your Loan EMI</Text>
<Text style={styles.rate}>{interestRate}% p.a. up to ${maxAmount.toLocaleString()}</Text>
<TouchableOpacity
style={styles.button}
onPress={() => onTapped?.('action://open_calculator')}
>
<Text style={styles.buttonText}>Open Calculator</Text>
</TouchableOpacity>
</View>
);
}
// Register globally
RendererRegistry.register('loan_calculator', EmiCalculatorRenderer);📊 Automated Analytics & Telemetry Lifecycle
The SDK automatically coordinates proposition lifecycle events with the Adobe Optimize SDK:
- Impression Tracking (
displayed):- When a
<TargetSlot />renders an offer, the SDK triggersitem.displayed(proposition)automatically. - View metrics are immediately attributed to the active Adobe Target activity.
- When a
- Interaction Tracking (
tapped):- Tapping any dynamic button, link, or invoking
onTapped()automatically triggersitem.tapped(proposition). - Conversion metrics are recorded before forwarding the action to your application.
- Tapping any dynamic button, link, or invoking
⚡ Performance & Network Optimization
- 1-Call Request Batching: Wrap screens with
<TargetProvider screen="ScreenName">. The SDK analyzes all registered slots and executes a single batchedupdatePropositionscall to Adobe Edge. - Lazy Module Loading: Component renderers are loaded on-demand during render time, preventing startup overhead.
- In-Memory Caching: Resolved offers are cached in memory to eliminate layout flicker on subsequent screen visits.
📖 API Reference
<TargetSlot /> Props
| Prop | Type | Default | Description |
| :--- | :--- | :---: | :--- |
| selectorId | string | Required | Placement identifier (e.g. 'hero_banner') |
| onTapped | (action?: string, envelope?: ContentEnvelope) => void | undefined | Callback fired on user interaction |
| fallbackComponent | ReactNode | null | Fallback component rendered if offer is unavailable |
| loadingComponent | ReactNode | ShimmerSkeleton | Custom placeholder shown during loading |
| showShimmer | boolean | true | Enables animated shimmer skeleton |
| envelope | ContentEnvelope | undefined | Direct envelope override (useful for mock testing) |
<TargetProvider /> Props
| Prop | Type | Default | Description |
| :--- | :--- | :---: | :--- |
| screen | string | Required | Screen name for batching (e.g. 'HomeScreen') |
| children | ReactNode | Required | Child components containing <TargetSlot /> elements |
