@getecho-ai/react-native-sdk
v1.1.3
Published
Echo AI Chat SDK for React Native - AI-powered e-commerce assistant
Maintainers
Readme
Echo React Native SDK
AI-powered chat and e-commerce SDK for React Native apps. Add an intelligent shopping assistant to your app in minutes.
Installation
npm install @getecho-ai/react-native-sdk react-native-webview @react-native-async-storage/async-storageExpo users:
npx expo install @getecho-ai/react-native-sdk react-native-webview @react-native-async-storage/async-storageQuick Start (< 5 minutes)
The fastest way to get started - uses the built-in useSimpleCart hook for automatic cart management:
import { EchoProvider, EchoChat, useSimpleCart } from '@getecho-ai/react-native-sdk';
function App() {
const { cart, callbacks } = useSimpleCart();
return (
<EchoProvider config={{ apiKey: 'your-api-key', callbacks }}>
<YourApp cart={cart} />
<EchoChat />
</EchoProvider>
);
}That's it! The AI assistant can now add products to cart and show cart contents.
Production Setup (Custom Cart)
For production apps with existing cart logic:
import { EchoProvider, EchoChat } from '@getecho-ai/react-native-sdk';
function App() {
return (
<EchoProvider
config={{
apiKey: 'your-api-key',
callbacks: {
// Required: Handle add to cart
onAddToCart: async (product, quantity = 1) => {
await yourCartService.add(product.id, quantity);
return {
success: true,
cartItemCount: yourCartService.getItemCount()
};
},
// Required: Return current cart
onGetCart: async () => {
const cart = await yourCartService.getCart();
return {
success: true,
cart: {
items: cart.items.map(item => ({
productId: item.id,
quantity: item.qty,
product: item.product,
})),
itemCount: cart.totalItems,
total: cart.totalPrice,
currency: 'TRY',
}
};
},
// Optional: Navigate to product detail
onNavigateToProduct: (productId) => {
navigation.navigate('ProductDetail', { id: productId });
},
// Optional: Navigate to checkout
onNavigateToCheckout: () => {
navigation.navigate('Checkout');
},
// Optional: Track order status
onTrackOrderState: async ({ orderId }) => {
const res = await fetch(`/api/orders/${orderId}`);
const order = await res.json();
return { success: res.ok, status: order.status, details: order };
},
// Optional: Get order history
onGetOrders: async () => {
const res = await fetch('/api/orders');
const data = await res.json();
return { success: res.ok, orders: data.orders };
},
},
}}
>
<YourApp />
<EchoChat />
</EchoProvider>
);
}Local Development
When developing locally with the Echo backend:
<EchoProvider
config={{
apiKey: 'your-api-key',
apiUrl: 'http://localhost:3000', // Auto-converts to 10.0.2.2 on Android emulator
callbacks,
}}
>The SDK automatically handles Android emulator's localhost quirk (converts localhost to 10.0.2.2).
For real devices, use your machine's local IP:
apiUrl: 'http://192.168.1.100:3000'Components
<EchoProvider>
Wrap your app with this provider. Required props:
| Prop | Type | Description |
|------|------|-------------|
| config.apiKey | string | Your Echo API key |
| config.callbacks | EchoCallbacks | Cart and navigation callbacks |
Optional props:
| Prop | Type | Description |
|------|------|-------------|
| config.apiUrl | string | Override API URL (default: production) |
| config.userId | string | Pre-set user ID |
| config.userEmail | string | User email for identification |
| config.userIdentifier | string | Custom user identifier |
| config.theme | EchoTheme | UI customization |
| config.uiSettings | UISettings | Control UI elements visibility |
| config.onEvent | (events: EchoEvent[]) => void | Callback fired when event batches flush |
<EchoChat>
The main chat component. Supports both modal (overlay) and inline (embedded) modes.
// Modal mode (default) - floating button + full-screen overlay
<EchoChat />
<EchoChat floating={false} />
<EchoChat position="bottom-left" />
// Inline mode - embedded directly in your layout
<EchoChat mode="inline" />
<EchoChat
mode="inline"
inlineProps={{
showHeader: true,
headerTitle: "Support Chat",
onClose: () => closeChat()
}}
/>Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| mode | "modal" \| "inline" | "modal" | Display mode |
| floating | boolean | true | Show floating button (modal only) |
| position | "bottom-right" \| "bottom-left" | "bottom-right" | Button position |
| inlineProps | EchoChatInlineProps | - | Props for inline mode |
<EchoChatInline>
Inline chat component for embedding in screens or tabs. Does not use a modal wrapper.
import { useEffect } from 'react';
import { EchoChatInline, useEcho } from '@getecho-ai/react-native-sdk';
function ChatScreen() {
const { openChat, closeChat } = useEcho();
useEffect(() => {
openChat();
return closeChat;
}, [openChat, closeChat]);
return (
<View style={{ flex: 1 }}>
<EchoChatInline
showHeader
headerTitle="Support Chat"
onClose={closeChat}
style={{ backgroundColor: '#f5f5f5' }}
/>
</View>
);
}Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| showHeader | boolean | false | Show header bar |
| headerTitle | string | "AI Asistan" | Header title text |
| onClose | () => void | - | Close button callback (shown when showHeader=true) |
| style | ViewStyle | - | Container style |
<EchoChatModal>
Full-screen modal chat component. Reads visibility from useEcho() context. Use openChat() / closeChat() to control it.
<EchoChatModal /><EchoChatButton>
Standalone chat button for custom layouts:
// Basic usage
<EchoChatButton
onPress={() => setModalVisible(true)}
position="bottom-left"
/>
// Custom icon (emoji)
<EchoChatButton
onPress={() => setModalVisible(true)}
icon="🤖"
iconSize={28}
color="#FF5722"
/>
// Custom icon (Image)
<EchoChatButton
onPress={() => setModalVisible(true)}
icon={<Image source={require('./chat-icon.png')} style={{ width: 32, height: 32 }} />}
color="#6366f1"
/>
// Custom icon (Vector Icon)
import Icon from 'react-native-vector-icons/MaterialIcons';
<EchoChatButton
onPress={() => setModalVisible(true)}
icon={<Icon name="chat" size={28} color="#fff" />}
color="#1e88e5"
/>Props:
onPress: () => void- Button press handlerposition?: "bottom-right" | "bottom-left"- Button position (default: "bottom-right")color?: string- Background color (default: "#007AFF")icon?: React.ReactNode | string- Custom icon (emoji string or React component) (default: "💬")iconSize?: number- Icon size for text/emoji icons (default: 24)unreadCount?: number- Show unread message badge
Hooks
useEcho()
Access Echo context anywhere in your app:
const {
// State
config, // EchoConfig
userId, // string
chatId, // string
isReady, // boolean
isChatOpen, // boolean
// Chat Control
sendMessage, // (message: string) => void
searchProducts, // (query: string) => void
openChat, // () => void
closeChat, // () => void
// User Identity
identify, // (params: IdentifyParams) => Promise<IdentifyResult>
logout, // () => Promise<void>
// Recommendations
getRecommendations, // (request: RecommendationRequest) => Promise<RecommendationResult>
// Event Tracking
trackPageView, // (data: { url: string; title?: string }) => void
viewedProduct, // (data: { productId: string }) => void
showRecommendation, // (productId: string) => void
clickRecommendation, // (productId: string) => void
trackAddToCart, // (data: AddToCartEventData) => void
trackPurchase, // (data: PurchaseEventData) => void
trackEvent, // (eventType: string, eventData?: Record<string, unknown>) => void
} = useEcho();useSimpleCart(options?)
Built-in cart management for quick prototyping:
const {
cart, // Current cart state
setCart, // Direct cart setter
clearCart, // Clear all items
removeItem, // Remove by productId
updateQuantity, // Update item quantity
callbacks, // Ready-to-use EchoCallbacks
} = useSimpleCart({
initialCart: { items: [], itemCount: 0 },
onCartChange: (cart) => console.log('Cart updated:', cart),
onNavigateToProduct: (id) => navigation.navigate('Product', { id }),
onNavigateToCheckout: () => navigation.navigate('Checkout'),
onAuthRequired: () => navigation.navigate('Login'),
onTrackOrderState: async ({ orderId }) => {
const res = await fetch(`/api/orders/${orderId}`);
const order = await res.json();
return { success: res.ok, status: order.status, details: order };
},
onGetOrders: async () => {
const res = await fetch('/api/orders');
const data = await res.json();
return { success: res.ok, orders: data.orders };
},
});Messaging
sendMessage(message)
Send a message to the chat programmatically. Opens the chat if closed:
const { sendMessage } = useEcho();
sendMessage('I need help finding a gift');searchProducts(query)
Trigger a product search in the chat. Opens the chat if closed:
const { searchProducts } = useEcho();
searchProducts('red summer dress');Events & Analytics
The SDK automatically tracks user interactions and provides methods for custom event tracking. Events are GA4-compatible and batched for performance.
Automatic Events
| Event | Trigger |
|-------|---------|
| widget_open | Chat opened |
| widget_close | Chat closed |
| new_chat | New chat session started |
| product_view | User taps a product in chat |
| product_click | User taps to visit a product URL |
Manual Tracking
const {
trackPageView,
viewedProduct,
showRecommendation,
clickRecommendation,
trackAddToCart,
trackPurchase,
trackEvent,
} = useEcho();
// Track screen views
trackPageView({ url: 'app://products/123', title: 'Product Detail' });
// Track product views
viewedProduct({ productId: 'SKU_123' });
// Track recommendations
showRecommendation('SKU_456');
clickRecommendation('SKU_456');
// GA4-compatible add to cart
trackAddToCart({
currency: 'USD',
value: 114.00,
items: [{ item_id: 'SKU_123', price: 114.00, item_name: 'Product Name', quantity: 1 }]
});
// GA4-compatible purchase
trackPurchase({
transaction_id: 'T_12345',
value: 129.99,
currency: 'USD',
items: [{ item_id: 'SKU_123', price: 114.00 }]
});
// Custom events
trackEvent('share_product', { productId: 'SKU_123', method: 'whatsapp' });Listening to Events
Forward events to your analytics provider:
<EchoProvider
config={{
apiKey: 'your-api-key',
callbacks,
onEvent: (events) => {
events.forEach(event => {
analytics.logEvent(event.eventType, event.eventData);
});
}
}}
>Events are batched: flushed after 5s of inactivity, when 10 events accumulate, or when the app backgrounds.
Recommendations
Fetch AI-powered product recommendations:
const { getRecommendations } = useEcho();
const result = await getRecommendations({
productIds: ['SKU_123'],
strategy: 'similar', // 'similar' | 'complementary' | 'bought_together' | 'cart'
limit: 8,
});
result.recommendations.forEach(product => {
console.log(product.title, product.primaryImage, product.priceAmount);
});UI Settings
Control visibility of UI elements:
<EchoProvider
config={{
apiKey: 'your-key',
callbacks,
uiSettings: {
showSidebar: false, // Hide conversation history sidebar
showExpandButton: false, // Hide expand/collapse button
showCartButton: true, // Show cart button in header
showHistoryButton: false, // Hide history/new chat button
showCloseButton: true, // Show close button
},
}}
>User Authentication
Echo SDK supports three user states:
- Anonymous - Default state. A random UUID is generated and persisted automatically.
- Identified - User is linked to an email or identifier. Chat history migrates from anonymous to identified user.
- Logged out - User is reset to a new anonymous state with a fresh UUID.
Identifying Users
Option 1: Via config (automatic)
Pass userEmail or userIdentifier in the provider config. The SDK auto-identifies on mount:
<EchoProvider
config={{
apiKey: 'your-key',
callbacks,
userEmail: user.email,
userIdentifier: user.id,
}}
>Option 2: Via hook (imperative)
Call identify() after login for full control:
const { identify } = useEcho();
const result = await identify({
email: '[email protected]',
userIdentifier: 'user-123',
firstName: 'John',
lastName: 'Doe',
phone: '+905551234567',
traits: { plan: 'premium' },
});
// result: { success: true, userId: '...', userIdChanged: true }Logging Out
Call logout() to reset to anonymous state. This generates a new anonymous UUID and clears chat history:
const { logout } = useEcho();
await logout();Utilities
resolveApiUrl(url?)
Platform-aware URL resolution for development:
import { resolveApiUrl } from '@getecho-ai/react-native-sdk';
const url = resolveApiUrl('http://localhost:3000');
// Android emulator: 'http://10.0.2.2:3000'
// iOS simulator: 'http://localhost:3000'
// Production URL: unchangedgetLocalhostUrl(port?)
Get the correct localhost URL for current platform:
import { getLocalhostUrl } from '@getecho-ai/react-native-sdk';
const url = getLocalhostUrl(3000);
// Android: 'http://10.0.2.2:3000'
// iOS: 'http://localhost:3000'Troubleshooting
"Network request failed" on Android emulator
The SDK should auto-convert localhost URLs. If issues persist:
// Explicitly use 10.0.2.2
apiUrl: 'http://10.0.2.2:3000'WebView not loading
Ensure peer dependencies are installed:
npm ls react-native-webview @react-native-async-storage/async-storageFor Expo, run npx expo install to get compatible versions.
Cart not updating
- Verify
onAddToCartreturns{ success: true, cartItemCount: N } - Check
onGetCartreturns valid cart structure - Add console.log in callbacks to debug
TypeScript errors
Import types explicitly:
import type { Product, Cart, EchoCallbacks } from '@getecho-ai/react-native-sdk';API Reference
Types
type Product = {
id: string;
title: string;
description?: string;
priceAmount?: number;
currency?: string;
primaryImage?: string;
images?: string[];
url?: string;
category?: string;
brand?: string;
inStock?: boolean;
};
type Cart = {
items: CartItem[];
total?: number;
currency?: string;
itemCount: number;
};
type CartItem = {
productId: string;
quantity: number;
product?: Product;
};
type AddToCartResult = {
success: boolean;
cartItemCount?: number;
error?: string;
};
type GetCartResult = {
success: boolean;
cart?: Cart;
error?: string;
};
type TrackOrderStateResult = {
success: boolean;
status?: string;
details?: any;
error?: string;
};
type GetOrdersResult = {
success: boolean;
orders?: any[];
error?: string;
};
type EchoCallbacks = {
onAddToCart: (product: Product, quantity?: number) => Promise<AddToCartResult>;
onGetCart: () => Promise<GetCartResult>;
onNavigateToProduct?: (productId: string) => void;
onNavigateToUrl?: (url: string) => void;
onNavigateToCheckout?: () => void;
onAuthRequired?: () => void;
onTrackOrderState?: (data: { orderId: string | number }) => Promise<TrackOrderStateResult>;
onGetOrders?: () => Promise<GetOrdersResult>;
};
type UISettings = {
showSidebar?: boolean;
showExpandButton?: boolean;
showCartButton?: boolean;
showHistoryButton?: boolean;
showCloseButton?: boolean;
};
type GA4Item = {
item_id: string;
price: number;
item_name?: string;
quantity?: number;
item_brand?: string;
item_category?: string;
item_variant?: string;
};
type AddToCartEventData = {
items: GA4Item[];
currency?: string;
value?: number;
};
type PurchaseEventData = {
transaction_id: string;
items: GA4Item[];
value?: number;
currency?: string;
tax?: number;
shipping?: number;
coupon?: string;
affiliation?: string;
};
type EchoEvent = {
chatId: string | null;
eventType: string;
eventData: Record<string, unknown>;
timestamp: string;
userEmail?: string;
userIdentifier?: string;
};
type IdentifyParams = {
email?: string;
userIdentifier?: string;
firstName?: string;
lastName?: string;
phone?: string;
traits?: Record<string, unknown>;
};
type IdentifyResult = {
success: boolean;
userId: string;
email?: string;
userIdentifier?: string;
userIdChanged: boolean;
};
type RecommendationRequest = {
productIds: string[];
strategy: 'similar' | 'complementary' | 'bought_together' | 'cart';
limit?: number;
threshold?: number;
minCount?: number;
weights?: {
semantic?: number;
color?: number;
price?: number;
category?: number;
};
};
type RecommendationResult = {
success: boolean;
strategy: string;
recommendations: RecommendedProduct[];
count: number;
message?: string;
error?: string;
};
type RecommendedProduct = {
id: string;
productId: string;
title: string;
brand?: string;
url?: string;
images: string[];
primaryImage?: string | null;
categoryBreadcrumb?: string[];
priceAmount?: string;
similarity?: number;
embeddingSimilarity?: number;
colorSimilarity?: number;
summary?: string | null;
};Example App
See the /example directory for a complete Expo demo app.
License
MIT
