cuoral-ionic
v0.0.9
Published
Cuoral Ionic Framework Library - silent churn prevention platform for Ionic apps. Provides screen recording, user interaction capture, and support widget integration for enhanced customer support experiences.
Maintainers
Readme
Cuoral Ionic Library
Proactive customer success platform integration for Ionic/Capacitor applications. Cuoral provides support ticketing, customer intelligence, screen recording, and comprehensive customer engagement tools.
Features
✅ Customer Support - Integrated support ticketing system
✅ Customer Intelligence - Track and analyze customer behavior automatically
✅ Native Crash Tracking - Capture native Android & iOS crashes
✅ Screen Recording - Native screen recording for issue reproduction
✅ Modal Display - Full-screen modal with floating chat button
✅ TypeScript Support - Full type definitions included
✅ Simple API - Just pass your public key and optional user info
✅ Zero Configuration - Everything handled automatically
Installation
npm install cuoral-ionicAfter installing, sync your Capacitor project:
npx cap syncPlatform Setup
Android Setup
The Android plugin automatically declares required permissions. Ensure your AndroidManifest.xml includes:
<!-- Required for support widget and intelligence tracking -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Required for screen recording with audio -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Required for screen recording on Android 9 and below -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />Note: These permissions are automatically added by Capacitor when you run npx cap sync android. The INTERNET permission is auto-granted by the system. RECORD_AUDIO requires user approval at runtime.
iOS Setup
Add to your Info.plist:
<!-- Required for screen recording with audio -->
<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone to record audio with screen recordings</string>Note: Screen recording permission is requested automatically by iOS when recording starts. No additional permissions are needed for crash tracking or intelligence features.
📱 Google Play Store Declaration (Android Only)
IMPORTANT: When submitting your app to Google Play Store, you'll be asked to declare why your app uses FOREGROUND_SERVICE_MEDIA_PROJECTION (screen recording permission).
Quick Action:
- Go to Play Console → Policy → App Content → Foreground Service Types
- Find
FOREGROUND_SERVICE_MEDIA_PROJECTION→ Click Manage - Select category: Customer Support / Bug Reporting
- Use the justification text from PLAY_STORE_QUICK_GUIDE.md
Why This is Required:
- Screen recording is a "sensitive permission" that requires declaration
- Google wants to ensure it's used appropriately (which it is - user-initiated support)
- This is a simple form, not a special approval process
- No code changes needed - your app is already configured correctly
📄 Documentation:
- Quick Guide: PLAY_STORE_QUICK_GUIDE.md - Copy-paste justification text
- Full Guide: PLAY_STORE_DECLARATION.md - Complete information and privacy policy updates
Note: iOS App Store does not require this declaration.
Quick Start
Option 1: Modal with Floating Button (Recommended)
The easiest way to integrate Cuoral - displays a floating chat button that opens the widget in a full-screen modal.
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Cuoral } from 'cuoral-ionic';
@Component({
selector: 'app-home',
template: `
<ion-content>
<!-- Your app content -->
<h1>Welcome to Support</h1>
<!-- Optional: Custom button to open widget -->
<ion-button (click)="openSupport()"> Contact Support </ion-button>
</ion-content>
`,
})
export class HomePage implements OnInit, OnDestroy {
private cuoral: Cuoral;
constructor() {
this.cuoral = new Cuoral({
publicKey: 'your-public-key-here',
email: '[email protected]', // Optional
firstName: 'John', // Optional
lastName: 'Doe', // Optional
showFloatingButton: true, // Show floating chat button
useModal: true, // Use modal display mode
});
}
ngOnInit() {
this.cuoral.initialize();
}
ngOnDestroy() {
this.cuoral.destroy();
}
// Open modal programmatically
openSupport() {
this.cuoral.openModal();
}
}Features:
- 🎈 Floating blue chat button in bottom-right corner
- 📱 Opens widget in full-screen modal with small margins
- ❌ Close button in top-right
- 🎨 Smooth animations and transitions
- 🖱️ Click backdrop to close
Option 2: Embedded Iframe - Not Recommended
For more control over widget placement:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { Cuoral } from 'cuoral-ionic';
@Component({
selector: 'app-support',
template: `
<ion-content>
<iframe [src]="widgetUrl" style="width: 100%; height: 600px; border: none;"> </iframe>
</ion-content>
`,
})
export class SupportPage implements OnInit, OnDestroy {
widgetUrl: SafeResourceUrl;
private cuoral: Cuoral;
constructor(private sanitizer: DomSanitizer) {
this.cuoral = new Cuoral({
publicKey: 'your-public-key-here',
useModal: false, // Disable modal mode
});
const url = this.cuoral.getWidgetUrl();
this.widgetUrl = this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
ngOnInit() {
this.cuoral.initialize();
}
ngOnDestroy() {
this.cuoral.destroy();
}
}Enable Page View Tracking (One-Time Setup)
To automatically track page views, add router tracking to your app.component.ts (or main app component):
import { Component } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { Cuoral } from 'cuoral-ionic';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
})
export class AppComponent {
private cuoral: Cuoral;
constructor(private router: Router) {
this.cuoral = new Cuoral({
publicKey: 'your-public-key-here',
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
});
}
async ngOnInit() {
// Initialize Cuoral (intelligence auto-enabled from dashboard)
await this.cuoral.initialize();
// Track all page navigation automatically
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.cuoral.trackPageView(event.url);
}
});
}
}That's it! All page views are now automatically tracked. Console errors, network errors, and native crashes are tracked with zero additional setup.
User Logout & Session Management
When users log out, properly clear and end the session before destroying the Cuoral instance:
async logout() {
// Step 1: Clear and end the session
await this.cuoral.clearSession();
// Step 2: Destroy the Cuoral instance
this.cuoral.destroy();
// Step 3: Your logout logic
// Navigate to login, clear user data, etc.
}When a different user logs in on the same device, create a fresh Cuoral instance:
async login(email: string, firstName: string, lastName: string) {
// Create new instance for the new user
this.cuoral = new Cuoral({
publicKey: 'your-public-key-here',
email: email,
firstName: firstName,
lastName: lastName,
});
// Initialize for new user
await this.cuoral.initialize();
}Important Notes:
clearSession()marks the session as ended on the backenddestroy()cleans up local resources- Always call
clearSession()beforedestroy()on logout - Create a new Cuoral instance for each user login
- Email, first name, and last name are all required for identified users
Push Notifications
Cuoral integrates seamlessly with your existing push notification system using webhooks. When an agent sends a message, Cuoral sends a webhook to your backend, allowing you to send push notifications to users when the widget is closed.
How it works:
- Track widget state in your app (open/closed)
- Configure webhooks in your Cuoral dashboard
- Receive webhook when agent sends message
- Send FCM/APNs push if widget is closed
Example Implementation:
export class MyApp {
private isCuoralWidgetOpen = false;
// When user opens support
openSupport() {
this.isCuoralWidgetOpen = true;
this.cuoral.openModal();
}
// When user closes support
closeSupport() {
this.isCuoralWidgetOpen = false;
this.cuoral.closeModal();
}
// Handle incoming push notifications (your existing FCM handler)
async handlePushNotification(message: any) {
if (message.data.type === 'cuoral_message') {
// Don't show notification if widget is already open
if (this.isCuoralWidgetOpen) {
return; // User already sees the message
}
// Show notification to user
await this.showNotification({
title: 'New message from Support',
body: message.data.text,
});
// When user taps notification, open widget
this.openSupport();
}
}
}Setup:
- Configure your webhook URL in Cuoral Dashboard → Settings → Webhooks
- Cuoral sends webhooks for all new messages
- Your backend decides whether to send push based on your app's state
- User taps notification → your app calls
cuoral.openModal()
This approach works with your existing FCM/APNs setup - no additional SDK configuration needed!
Configuration
CuoralOptions
interface CuoralOptions {
publicKey: string; // Required: Your Cuoral public key
email?: string; // Optional: User email
firstName?: string; // Optional: User first name
lastName?: string; // Optional: User last name
debug?: boolean; // Optional: Enable debug logging (default: false)
widgetBaseUrl?: string; // Optional: Custom widget URL (default: CDN)
showFloatingButton?: boolean; // Optional: Show floating chat button (default: true)
useModal?: boolean; // Optional: Use modal display mode (default: true)
}Widget URL
By default, the widget loads from https://js.cuoral.com/mobile.html (production CDN).
Production (Default):
new Cuoral({ publicKey: 'your-key' });Custom URL (Optional):
If you need to use a custom widget URL for testing or self-hosting:
new Cuoral({
publicKey: 'your-key',
widgetBaseUrl: 'https://your-domain.com/mobile.html',
});API Reference
Cuoral Methods
// Initialize Cuoral
cuoral.initialize(): Promise<void>
// Track page/screen view (for intelligence)
cuoral.trackPageView(screen: string, metadata?: any): void
// Track error manually (for intelligence)
cuoral.trackError(message: string, stackTrace?: string, metadata?: any): void
// Start native screen recording programmatically
cuoral.startRecording(): Promise<boolean>
// Stop native screen recording programmatically
cuoral.stopRecording(): Promise<{filePath?: string; duration?: number} | null>
// Get widget URL for iframe embedding
cuoral.getWidgetUrl(): string
// Open modal programmatically
cuoral.openModal(): void
// Close modal programmatically
cuoral.closeModal(): void
// Check if modal is open
cuoral.isModalOpen(): boolean
// Clear and end current session (call before logout)
cuoral.clearSession(): Promise<void>
// Clean up resources
cuoral.destroy(): voidProgrammatic Screen Recording
You can trigger native screen recording programmatically from your app code:
async startUserRecording() {
const started = await this.cuoral.startRecording();
if (started) {
console.log('Recording started successfully');
this.isRecording = true;
} else {
console.error('Failed to start recording');
}
}
async stopUserRecording() {
const result = await this.cuoral.stopRecording();
if (result) {
console.log('Recording stopped', {
filePath: result.filePath,
duration: result.duration
});
this.isRecording = false;
} else {
console.error('Failed to stop recording');
}
}Use Cases:
- Allow users to record their issue before contacting support
- Implement custom recording UI in your app
- Record specific user flows programmatically
- Create bug reporting features with automatic recording
Note: Recording still requires user permission on iOS (microphone access). The video file is automatically processed and available for playback in the support widget.
Manual Intelligence Tracking
Track custom events beyond automatic tracking:
// Track page/screen view
this.cuoral.trackPageView('/checkout', {
cart_items: 3,
total_value: 99.99
});
// Track error manually
this.cuoral.trackError(
'Payment failed',
error.stack,
{ payment_method: 'credit_card', amount: 99.99 }
);What Gets Handled Automatically
- ✅ Support ticket creation and management
- ✅ Customer intelligence tracking (page views, errors, network failures)
- ✅ Native crash tracking (Android & iOS)
- ✅ Screen recording start/stop
- ✅ File path conversion for video playback
- ✅ Communication between widget and native code
- ✅ Video upload to Cuoral backend
- ✅ State management
- ✅ Permissions handling
Intelligence Features (Backend-Controlled)
Intelligence tracking is automatically enabled/disabled from your Cuoral dashboard. When enabled, the library automatically captures:
- Page Views - Track navigation (requires one-time router setup, see INTELLIGENCE.md)
- Console Errors - JavaScript errors and unhandled exceptions
- Network Errors - Failed API calls (4xx, 5xx responses)
- Native Crashes - Native Android (Java/Kotlin) and iOS (Swift/Objective-C) crashes
For detailed intelligence setup and features, see INTELLIGENCE.md
Troubleshooting
Recording doesn't start
Check iOS permissions:
- Verify
NSMicrophoneUsageDescriptionis in Info.plist - System will prompt user automatically on first recording
Enable debug mode:
new Cuoral({
publicKey: 'your-key',
debug: true, // See console logs
});Widget not appearing
Modal mode:
- Make sure you called
cuoral.initialize() - Check that
useModal: trueis set (default) - Look for the blue floating button in bottom-right
Iframe mode:
- Verify
widgetUrlis properly sanitized withDomSanitizer - Check browser console for CORS errors
- Ensure iframe has proper dimensions in CSS
Build errors
iOS Pod Issues:
cd ios
pod deintegrate
pod install
cd ..
npx cap sync iosClean build:
rm -rf node_modules dist
npm install
npx cap syncSupport
- 📧 Email: [email protected]
- 📖 Docs: https://docs.cuoral.com
- 🐛 Issues: https://github.com/cuoral/cuoral-ionic/issues
License
MIT License - see LICENSE file
Built with ❤️ by Cuoral
