@arkesel/rn-kova-live-chat
v1.0.1
Published
A lightweight, zero-config chat widget for React Native with no native dependencies (except AsyncStorage). Works in Expo Go! and Integrates with KOVA-IQ Platform.
Maintainers
Readme
React Native Chat Widget 💬
A powerful, production-ready React Native chat widget with real-time messaging, customer info collection, and zero native dependencies. Perfect for customer support, live chat, and messaging features in your React Native apps.
✨ Features
- ✅ Real-time messaging via Socket.IO
- ✅ Zero native dependencies - Works with Expo Go
- ✅ Customer info collection with smart form handling
- ✅ 6 position options for floating action button
- ✅ Full customization - Colors, positions, themes
- ✅ Message status indicators (sent ✓, delivered ✓✓)
- ✅ File attachment display with download
- ✅ Emoji picker with 38 emojis
- ✅ Optimistic updates for instant message display
- ✅ Auto-persistence via AsyncStorage
- ✅ 30-second engagement alert with animations
- ✅ TypeScript support with full type definitions
- ✅ Pre-fill customer info for logged-in users
📦 Installation
npm install rn-kova-live-chat socket.io-client moment @react-native-async-storage/async-storageExpo Users:
npx expo install rn-kova-live-chat socket.io-client moment @react-native-async-storage/async-storage🚀 Quick Start
Basic Usage (Minimal Setup):
import React from 'react';
import { View } from 'react-native';
import ChatWidget from '@arkesel/rn-kova-live-chat';
export default function App() {
return (
<View style={{ flex: 1 }}>
<YourAppContent />
<ChatWidget
apiKey="your-api-key"
organizationId="your-organization-id"
/>
</View>
);
}That's it! Your chat widget is ready with only 2 required props! 🎉
🎨 Customization
Custom Colors & Position:
<ChatWidget
apiKey="your-api-key"
organizationId="your-organization-id"
primaryColor="#8B5CF6" // Header, button, user messages
secondaryColor="#EC4899" // Send button accent
position="top-right" // FAB position
/>Skip Form for Logged-In Users:
const { user } = useAuth();
<ChatWidget
apiKey="your-api-key"
organizationId="your-organization-id"
initialCustomerName={user?.name}
initialCustomerPhone={user?.phone}
// Form will be skipped automatically!
/>📖 Complete Props Documentation
Required Props:
| Prop | Type | Description |
|------|------|-------------|
| apiKey | string | Your API authentication key From KOVA dashboard |
| organizationId | string | Your organization identifier From KOVA dashboard |
Optional Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| primaryColor | string | "#142444" | Main color for header, FAB, user messages |
| secondaryColor | string | "#13cc7c" | Accent color for send button |
| position | string | "bottom-right" | FAB position: "top-right", "top-left", "bottom-right", "bottom-left", "middle-right", "middle-left" |
| initialCustomerName | string \| null | null | Pre-fill customer name (skips form if both name and phone provided) |
| initialCustomerPhone | string \| null | null | Pre-fill customer phone (skips form if both name and phone provided) |
| theme | object | {} | Reserved for future theming options |
📱 Usage Examples
1. E-commerce App
import React from 'react';
import { View } from 'react-native';
import ChatWidget from '@arkesel/rn-kova-live-chat';
export default function ShoppingApp() {
return (
<View style={{ flex: 1 }}>
<ProductCatalog />
<ChatWidget
apiKey={Config.CHAT_API_KEY}
organizationId={Config.ORG_ID}
primaryColor="#FF6B6B"
position="bottom-left"
/>
</View>
);
}2. Healthcare App with User Context
import React from 'react';
import { View } from 'react-native';
import ChatWidget from '@arkesel/rn-kova-live-chat';
import { usePatient } from './context/PatientContext';
export default function HealthcareApp() {
const { patient } = usePatient();
return (
<View style={{ flex: 1 }}>
<AppointmentScreen />
<ChatWidget
apiKey={Config.CHAT_API_KEY}
organizationId={Config.ORG_ID}
initialCustomerName={patient?.fullName}
initialCustomerPhone={patient?.phoneNumber}
primaryColor="#0EA5E9"
secondaryColor="#10B981"
/>
</View>
);
}3. Multi-tenant SaaS App
import React from 'react';
import { View } from 'react-native';
import ChatWidget from '@arkesel/rn-kova-live-chat';
import { useTenant } from './hooks/useTenant';
export default function MultiTenantApp() {
const { tenant, user } = useTenant();
return (
<View style={{ flex: 1 }}>
<TenantDashboard />
<ChatWidget
apiKey={tenant.chatApiKey} // Tenant-specific API key
organizationId={tenant.organizationId}
initialCustomerName={user?.name}
initialCustomerPhone={user?.phone}
primaryColor={tenant.brandColor} // Tenant branding
secondaryColor={tenant.accentColor}
position="middle-right"
/>
</View>
);
}4. Conditional Rendering by Screen
import React from 'react';
import { View } from 'react-native';
import { useRoute } from '@react-navigation/native';
import ChatWidget from '@arkesel/rn-kova-live-chat';
export default function App() {
const route = useRoute();
const showChat = ['Home', 'Products', 'Support'].includes(route.name);
return (
<View style={{ flex: 1 }}>
<Navigation />
{showChat && (
<ChatWidget
apiKey={Config.CHAT_API_KEY}
organizationId={Config.ORG_ID}
position={route.name === 'Support' ? 'middle-right' : 'bottom-right'}
/>
)}
</View>
);
}5. With Redux State
import React from 'react';
import { View } from 'react-native';
import { useSelector } from 'react-redux';
import ChatWidget from '@arkesel/rn-kova-live-chat';
export default function App() {
const user = useSelector(state => state.auth.user);
const theme = useSelector(state => state.settings.theme);
return (
<View style={{ flex: 1 }}>
<AppContent />
<ChatWidget
apiKey={Config.CHAT_API_KEY}
organizationId={Config.ORG_ID}
initialCustomerName={user?.displayName}
initialCustomerPhone={user?.phoneNumber}
primaryColor={theme.primaryColor}
secondaryColor={theme.secondaryColor}
/>
</View>
);
}6. Environment-based Configuration
import React from 'react';
import { View } from 'react-native';
import ChatWidget from '@arkesel/rn-kova-live-chat';
import Config from 'react-native-config';
export default function App() {
return (
<View style={{ flex: 1 }}>
<AppContent />
<ChatWidget
apiKey={Config.CHAT_API_KEY}
organizationId={Config.CHAT_ORG_ID}
primaryColor={Config.BRAND_PRIMARY}
secondaryColor={Config.BRAND_SECONDARY}
/>
</View>
);
}🎨 Position Options
The widget supports 6 different positions:
// Top positions
position="top-right" // Top right corner
position="top-left" // Top left corner
// Bottom positions (default)
position="bottom-right" // Bottom right corner (default)
position="bottom-left" // Bottom left corner
// Middle positions
position="middle-right" // Middle right edge
position="middle-left" // Middle left edge🎨 Color Customization Examples
Professional Blue:
primaryColor="#2563EB"
secondaryColor="#3B82F6"Vibrant Purple:
primaryColor="#8B5CF6"
secondaryColor="#A78BFA"Modern Green:
primaryColor="#059669"
secondaryColor="#10B981"Elegant Dark:
primaryColor="#1F2937"
secondaryColor="#6B7280"Bold Red:
primaryColor="#DC2626"
secondaryColor="#EF4444"🔧 Features in Detail
1. Customer Information Form
The widget automatically shows a form to collect:
- Customer name (required)
- Customer phone (required)
- Customer email (optional)
Skip the form: Provide both initialCustomerName AND initialCustomerPhone props:
<ChatWidget
apiKey="your-api-key"
organizationId="your-org-id"
initialCustomerName="John Doe"
initialCustomerPhone="+233 24 123 4567"
// Form is automatically skipped! ✅
/>Priority logic:
- If both props provided → Use props, skip form
- If data in AsyncStorage → Use stored data, skip form
- Otherwise → Show form
2. Real-time Messaging
- Instant message delivery via Socket.IO
- Optimistic updates (messages appear immediately)
- Message status indicators (✓ sent, ✓✓ delivered)
- Auto-scroll to latest message
- Support for text and file attachments
3. Message Status
✓ - Message sent
✓✓ - Message delivered (echoed by server)4. Engagement Alert
After 30 seconds of inactivity, an alert bubble appears:
💬 [Need help? Chat with us!] [✕]- Auto-hides when chat is opened
- Can be manually dismissed
- Smooth fade animations
- Shows only once per session
5. Emoji Picker
Built-in emoji picker with 38 popular emojis:
- 😀 😁 😂 🤣 😊 😍 😘 😎 😇 🙂
- 🙃 😉 😌 😴 🤔 🤗 😱 😭 😅 👍
- 👎 👏 🙏 🔥 🎉 ❤️ 💔 ✨ ⭐ 🌟
- 💡 ✅ ❌ 📎 📷 🖼️ 📁 📄
Toggle with the 😊 button in the input area.
6. File Attachments
Display file attachments from agent messages:
- Shows file name with download icon (⬇️)
- Click to open/download file
- Supports various file types
7. Data Persistence
Automatically stores in AsyncStorage:
- Chat ID (UUID)
- Customer name
- Customer phone
- Customer email
Data persists across app sessions.
🔌 Server Integration (Socket.IO)
Events Emitted by Widget:
1. join_chat
Emitted when widget connects:
{
chatId: "uuid-v4-string",
apiKey: "your-api-key",
organizationId: "your-org-id",
customerName?: "John Doe" // If available
}2. send_message
Emitted when user sends a message:
{
chatId: "uuid-v4-string",
message: "Hello, I need help",
sender: "user",
customerName?: "John Doe" // If available
}3. update_customer_info
Emitted when customer submits info form:
{
chatId: "uuid-v4-string",
customerName: "John Doe",
customerPhone: "+233 24 123 4567",
customerEmail?: "[email protected]" // If provided
}Events Received by Widget:
1. connect
Connection established.
2. chat_history
Receives previous messages:
[
{
_id: "msg-id",
text: "Hello!",
sender: "agent",
sender_name: "Support Agent",
createdAt: "2024-01-15T10:30:00Z",
status: "delivered"
},
// ... more messages
]3. new_message
Receives new message from agent:
{
_id: "msg-id",
text: "How can I help you?",
sender: "agent",
sender_name: "Sarah from Support",
createdAt: "2024-01-15T10:32:00Z",
status: "delivered",
file?: {
url: "https://cdn.example.com/file.pdf",
name: "Invoice.pdf",
mime: "application/pdf",
size: 1024000
}
}4. name_update
Confirmation of customer info update:
"success" // or error message string5. disconnect
Connection lost.
Message Object Schema:
interface Message {
_id: string; // Unique message ID
text: string; // Message content
sender: 'user' | 'agent'; // Who sent the message
sender_name?: string; // Agent name (for agent messages)
customerName?: string; // Customer name (for user messages)
createdAt: string; // ISO 8601 timestamp
status?: 'sent' | 'delivered'; // Message status
file?: { // Optional file attachment
url: string; // File URL
name: string; // File name
mime?: string; // MIME type
size?: number; // File size in bytes
};
}💾 AsyncStorage Keys
The widget uses these AsyncStorage keys:
| Key | Description | Example Value |
|-----|-------------|---------------|
| chatId | Unique chat session ID | "a1b2c3d4-e5f6-7890-abcd-ef1234567890" |
| customerName_{chatId} | Customer name for this chat | "John Doe" |
| customerPhone_{chatId} | Customer phone for this chat | "+233 24 123 4567" |
| customerEmail_{chatId} | Customer email for this chat | "[email protected]" |
🧹 Clearing Chat Data
To clear stored chat data (e.g., on logout):
import AsyncStorage from '@react-native-async-storage/async-storage';
// Clear all chat data
const clearChatData = async () => {
try {
const chatId = await AsyncStorage.getItem('chatId');
if (chatId) {
await AsyncStorage.multiRemove([
'chatId',
`customerName_${chatId}`,
`customerPhone_${chatId}`,
`customerEmail_${chatId}`,
]);
console.log('Chat data cleared');
}
} catch (error) {
console.error('Error clearing chat data:', error);
}
};
// Use on logout
const handleLogout = async () => {
await clearChatData();
// ... rest of logout logic
};🐛 Troubleshooting
1. Widget not appearing
Cause: Widget is positioned off-screen or behind other elements.
Solution:
- Ensure parent View has
flex: 1 - Try different
positionprop values - Check z-index of other components
<View style={{ flex: 1 }}> {/* ✅ flex: 1 required */}
<YourContent />
<ChatWidget {...props} />
</View>2. Form keeps showing
Cause: Both initialCustomerName and initialCustomerPhone not provided.
Solution: Provide BOTH props to skip form:
// ❌ Won't skip form (only one prop)
<ChatWidget
apiKey="key"
organizationId="org"
initialCustomerName="John"
/>
// ✅ Skips form (both props)
<ChatWidget
apiKey="key"
organizationId="org"
initialCustomerName="John"
initialCustomerPhone="+233241234567"
/>3. Messages not sending
Cause: Not connected to Socket.IO server or server not responding.
Solution:
- Check connection status in widget header
- Verify server is running and accessible
- Check console logs for connection errors
- Ensure firewall allows WebSocket connections
// Debug logs in console:
[ChatWidget] Socket connected with ID: abc123...
[ChatWidget] Emitted join_chat4. TypeScript errors
Cause: Missing or outdated type definitions.
Solution:
# Reinstall package
npm install rn-kova-live-chat@latest
# Or manually add types
npm install --save-dev @types/rn-kova-live-chat🔒 Security Best Practices
1. API Key Storage
Never hardcode API keys in your code:
// ❌ Bad - Hardcoded
<ChatWidget apiKey="sk_live_12345" />
// ✅ Good - Environment variable
import Config from 'react-native-config';
<ChatWidget apiKey={Config.CHAT_API_KEY} />
// ✅ Good - Secure storage
import * as SecureStore from 'expo-secure-store';
const apiKey = await SecureStore.getItemAsync('chat_api_key');
<ChatWidget apiKey={apiKey} />
// ✅ Good - From backend
const apiKey = user.chatCredentials.apiKey;
<ChatWidget apiKey={apiKey} />2. User Data
- Never log sensitive user information
- Use secure storage for credentials
- Clear data on logout
- Implement proper authentication
3. Network Security
- Always use WSS (WebSocket Secure) in production
- Validate SSL certificates
- Implement rate limiting on your server
- Use HTTPS for all API endpoints
📚 Advanced Usage
Custom Theme Object (Future)
The theme prop is reserved for future customization:
<ChatWidget
apiKey="key"
organizationId="org"
theme={{
// Future theme options will go here
fontFamily: 'CustomFont',
borderRadius: 12,
// etc.
}}
/>Multiple Widgets
You can render multiple widgets for different purposes:
function App() {
return (
<View style={{ flex: 1 }}>
<AppContent />
{/* Sales chat */}
<ChatWidget
apiKey={Config.SALES_API_KEY}
organizationId="sales-team"
primaryColor="#059669"
position="bottom-right"
/>
{/* Support chat */}
<ChatWidget
apiKey={Config.SUPPORT_API_KEY}
organizationId="support-team"
primaryColor="#2563EB"
position="bottom-left"
/>
</View>
);
}Programmatic Control
Control widget state from parent component:
import React, { useRef } from 'react';
import ChatWidget from '@arkesel/rn-kova-live-chat';
function App() {
const chatRef = useRef(null);
const openChat = () => {
// Future API (not yet available)
chatRef.current?.open();
};
return (
<View style={{ flex: 1 }}>
<Button title="Open Chat" onPress={openChat} />
<ChatWidget
ref={chatRef}
apiKey="key"
organizationId="org"
/>
</View>
);
}📦 Dependencies
The widget requires these peer dependencies:
| Package | Version | Purpose |
|---------|---------|---------|
| react | >=16.8.0 | React framework |
| react-native | >=0.60.0 | React Native framework |
| socket.io-client | >=4.5.0 | Real-time communication |
| @react-native-async-storage/async-storage | >=1.17.0 | Data persistence |
| moment | >=2.29.0 | Date/time formatting |
All dependencies are installed automatically with the package.
🌐 Platform Support
| Platform | Support | Notes | |----------|---------|-------| | iOS | ✅ Full | iOS 11+ | | Android | ✅ Full | Android 5.0+ (API 21+) | | Expo Go | ✅ Full | No native code required | | Web | ⚠️ Partial | Works but not optimized |
🧪 Testing
Test Basic Integration:
import React from 'react';
import { render } from '@testing-library/react-native';
import ChatWidget from '@arkesel/rn-kova-live-chat';
describe('ChatWidget', () => {
it('renders without crashing', () => {
const { getByText } = render(
<ChatWidget
apiKey="test-key"
organizationId="test-org"
/>
);
expect(getByText).toBeDefined();
});
});📊 Performance
The widget is optimized for performance:
- Bundle size: ~7.8KB (minified + gzipped)
- Dependencies: Only peer dependencies required
- Memory: Minimal footprint (~2-5MB)
- Native modules: Zero (pure JavaScript)
- Render performance: 60 FPS animations
🔄 Migration Guide
From v1.0.x to v1.1.x:
Breaking Changes: None! Version 1.1.x simplifies the API by moving backend configuration internal.
Old code (still works):
<ChatWidget
apiKey="key"
organizationId="org"
webSocketUrl="wss://server.com" // Ignored in v1.1.x
cdnBaseUrl="https://cdn.com" // Ignored in v1.1.x
crmWebsiteUrl="https://crm.com" // Ignored in v1.1.x
/>New code (recommended):
<ChatWidget
apiKey="key"
organizationId="org"
// Backend URLs are now internal - no need to provide!
/>🗺️ Roadmap
Upcoming features:
- [ ] Voice message support
- [ ] Image/video upload
- [ ] Push notifications
- [ ] Typing indicators
- [ ] Read receipts
- [ ] Message reactions
- [ ] File upload from device
- [ ] Chat history export
- [ ] Custom message templates
- [ ] Multi-language support
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Development Setup:
# Clone the repository
git clone https://github.com/yourusername/rn-kova-live-chat.git
cd rn-kova-live-chat
# Install dependencies
npm install
# Run tests
npm test
# Build package
npm run build📄 License
MIT License - see LICENSE file for details.
🆘 Support
- GitHub Issues: Report bugs or request features
- Documentation: Full API documentation
- Stack Overflow: Tag questions with
rn-kova-live-chat
📝 Changelog
v1.1.0 (2024-01-15)
- ✨ Simplified API - only 2 required props
- ✨ Backend URLs now internal (no configuration needed)
- 🐛 Fixed message display with optimistic updates
- 🐛 Fixed 30-second alert timer
- 🐛 Fixed customer form visibility
- 🐛 Removed crypto dependency (UUID generator)
v1.0.0 (2024-01-10)
- 🎉 Initial release
- ✅ Real-time messaging
- ✅ Customer info collection
- ✅ 6 position options
- ✅ Color customization
- ✅ Emoji picker
- ✅ File attachments
- ✅ TypeScript support
⭐ Show Your Support
If you find this package helpful, please give it a ⭐ on GitHub!
👨💻 Author
Your Name
- GitHub: @yourusername
- Email: [email protected]
🙏 Acknowledgments
Built with:
- Socket.IO - Real-time communication
- React Native - Mobile framework
- AsyncStorage - Data persistence
- Moment.js - Date/time handling
Made with ❤️ for the React Native community
