UNPKG

saltfish

Version:

An interactive video-guided tour system for web applications

654 lines (485 loc) 14.4 kB
# Saltfish Interactive video-guided tours for web applications. Create engaging onboarding experiences with synchronized video playback, interactive overlays, and smart triggering. [![npm version](https://img.shields.io/npm/v/saltfish.svg)](https://www.npmjs.com/package/saltfish) [![License](https://img.shields.io/npm/l/saltfish.svg)](https://github.com/Saltfish-AB/playlist-player/blob/main/LICENSE) ## Features - 🎥 **Video-Guided Tours** - Synchronized video content with interactive UI overlays - 🎯 **Smart Triggers** - Automatic playlist triggering based on URL, user behavior, and custom conditions - 📱 **Responsive** - Automatically adapts to different screen sizes and devices - 🎨 **Shadow DOM** - Complete style isolation prevents CSS conflicts - 📊 **Analytics** - Built-in tracking for user engagement and completion rates - 🔄 **State Persistence** - Resume tours where users left off - 🌐 **Multi-language** - User-specific language preferences - ⚡ **Lightweight** - Minimal bundle size with efficient loading ## Installation ### CDN (Recommended) ```html <script src="https://storage.saltfish.ai/player/player.js"></script> ``` ### NPM ```bash npm install saltfish ``` ## Quick Start ### Basic Setup (CDN) ```html <!DOCTYPE html> <html> <head> <title>My App</title> </head> <body> <h1>Welcome to My App</h1> <!-- Load Saltfish --> <script src="https://storage.saltfish.ai/player/player.js"></script> <script> // 1. Initialize with your token saltfish.init({ token: 'YOUR_TOKEN_HERE', enableAnalytics: true }); // 2. Identify the user saltfish.identify('user-123', { email: 'user@example.com', name: 'John Doe', language: 'en' }); // 3. (Optional) Manually start a playlist saltfish.startPlaylist('playlist-id'); </script> </body> </html> ``` ### NPM/ES Modules ```javascript import saltfish from 'saltfish'; // Initialize saltfish.init({ token: 'YOUR_TOKEN_HERE', enableAnalytics: true }); // Identify user saltfish.identify('user-123', { email: 'user@example.com', language: 'en' }); // Start playlist saltfish.startPlaylist('playlist-id'); ``` ## API Reference ### `saltfish.init(config)` Initialize the Saltfish player. Must be called before any other methods. **Parameters:** - `config` (Object or String): - If string: Your API token - If object: - `token` (String, required): Your API token from Saltfish dashboard - `enableAnalytics` (Boolean, optional): Enable/disable analytics tracking (default: `true`) **Returns:** `Promise<void>` (can be called without await) **Examples:** ```javascript // Simple initialization with token only saltfish.init('YOUR_TOKEN_HERE'); // With configuration object saltfish.init({ token: 'YOUR_TOKEN_HERE', enableAnalytics: false // Disable analytics for development }); // Using async/await await saltfish.init('YOUR_TOKEN_HERE'); // Using events saltfish.on('initialized', () => { console.log('Saltfish ready!'); }); saltfish.init('YOUR_TOKEN_HERE'); ``` ### `saltfish.identify(userId, attributes)` Identify the current user. This enables playlist triggers, progress tracking, and personalized experiences. **Parameters:** - `userId` (String, required): Unique identifier for the user - `attributes` (Object, optional): - `email` (String): User's email address - `name` (String): User's display name - `language` (String): Language preference (`'en'`, `'sv'`, `'es'`, `'fr'`, `'de'`, or `'auto'` for browser detection) - Any custom attributes you want to track **Examples:** ```javascript // Basic identification saltfish.identify('user-123'); // With email and name saltfish.identify('user-123', { email: 'user@example.com', name: 'John Doe' }); // With language preference saltfish.identify('user-123', { email: 'user@example.com', language: 'sv' // Swedish }); // Auto-detect language from browser saltfish.identify('user-123', { language: 'auto' }); // With custom attributes saltfish.identify('user-123', { email: 'user@example.com', plan: 'premium', signupDate: '2024-01-15' }); ``` ### `saltfish.identifyAnonymous(attributes)` Identify anonymous users without backend communication. Uses localStorage for progress tracking and trigger evaluation. **Parameters:** - `attributes` (Object, optional): Same as `identify()` method **Examples:** ```javascript // Anonymous user with language preference saltfish.identifyAnonymous({ language: 'en' }); // Anonymous user with no data saltfish.identifyAnonymous(); // With custom tracking data saltfish.identifyAnonymous({ language: 'auto', theme: 'dark' }); ``` ### `saltfish.startPlaylist(playlistId, options)` Manually start a specific playlist. If a playlist is already running, it will be reset and the new one started. **Parameters:** - `playlistId` (String, required): The playlist ID from your Saltfish dashboard - `options` (Object, optional): - `startNodeId` (String): Start from a specific step instead of the beginning - `position` (String): Player position (`'bottom-left'` or `'bottom-right'`) **Returns:** `Promise<void>` (can be called without await) **Examples:** ```javascript // Basic usage saltfish.startPlaylist('playlist-123'); // Start from a specific step saltfish.startPlaylist('playlist-123', { startNodeId: 'step-5' }); // With custom position saltfish.startPlaylist('playlist-123', { position: 'bottom-right' }); // Using async/await await saltfish.startPlaylist('playlist-123'); // Using events saltfish.on('playlistStarted', (data) => { console.log('Started:', data.playlist.id); }); saltfish.startPlaylist('playlist-123'); ``` ### Event Listeners Listen to player events using `on()` and remove listeners with `off()`. #### `saltfish.on(eventName, handler)` Register an event listener. **Available Events:** - `'initialized'` - Player initialized successfully - `'playlistStarted'` - Playlist has started playing - `'playlistEnded'` - Playlist completed - `'playlistDismissed'` - User dismissed/closed the playlist - `'stepStarted'` - New step/video started - `'stepEnded'` - Step/video completed - `'error'` - An error occurred **Examples:** ```javascript // Listen for playlist completion saltfish.on('playlistEnded', (data) => { console.log('Playlist completed:', data.playlist.id); console.log('Completion rate:', data.completionRate); }); // Listen for step changes saltfish.on('stepStarted', (data) => { console.log('Now on step:', data.step.id); }); // Listen for errors saltfish.on('error', (data) => { console.error('Player error:', data.message); }); // Listen for initialization saltfish.on('initialized', () => { console.log('Player ready!'); }); ``` #### `saltfish.off(eventName, handler)` Remove an event listener. **Returns:** `boolean` - `true` if listener was removed, `false` if not found **Example:** ```javascript function onPlaylistEnd(data) { console.log('Playlist ended:', data.playlist.id); } // Add listener saltfish.on('playlistEnded', onPlaylistEnd); // Remove listener saltfish.off('playlistEnded', onPlaylistEnd); ``` ### Other Methods #### `saltfish.getSessionId()` Get the current session ID. **Returns:** `String` ```javascript const sessionId = saltfish.getSessionId(); console.log('Session ID:', sessionId); ``` #### `saltfish.getRunId()` Get the current run ID (unique per playlist execution). **Returns:** `String | null` ```javascript const runId = saltfish.getRunId(); console.log('Run ID:', runId); ``` #### `saltfish.resetPlaylist()` Reset the current playlist to its initial state. ```javascript saltfish.resetPlaylist(); ``` #### `saltfish.destroy()` Destroy the player instance and clean up all resources. ```javascript saltfish.destroy(); ``` #### `saltfish.version()` Get the current Saltfish player version. **Returns:** `String` ```javascript const version = saltfish.version(); console.log('Saltfish version:', version); ``` ## Playlist Triggers Playlists can be automatically triggered based on conditions you configure in the Saltfish CMS. No code changes needed! ### Trigger Types #### URL-Based Triggers Automatically show playlists when users visit specific URLs: ```javascript // Just initialize and identify - triggers happen automatically saltfish.init('YOUR_TOKEN'); saltfish.identify('user-123'); // Playlist will auto-trigger when user navigates to configured URLs // e.g., "/dashboard", "/pricing", "/features/*" ``` **CMS Configuration Examples:** - **Exact match**: `/dashboard` - Only triggers on exactly `/dashboard` - **Contains**: `/dashboard` with "contains" mode - Triggers on `/dashboard`, `/dashboard/settings`, etc. - **Wildcard**: `/products/*` - Triggers on any product page - **Regex**: `/playlist-[0-9]+` - Triggers on `/playlist-1`, `/playlist-42`, etc. #### Element Click Triggers Trigger playlists when users click specific elements: ```html <button id="help-button">Help</button> <button class="support-btn">Support</button> <button data-action="guide">Guide</button> <script> saltfish.init('YOUR_TOKEN'); saltfish.identify('user-123'); // Configure in CMS with CSS selector: // #help-button, .support-btn, [data-action="guide"] </script> ``` #### Conditional Triggers Configure complex trigger logic in the CMS: - **Once per user**: Show playlist only once, never again - **Seen/Not seen**: Trigger based on whether user has seen other playlists - **A/B Testing**: Show different playlists to different user segments - **Combine conditions**: URL + click + seen/not seen with AND/OR logic ### Manual Override You can always manually start a playlist even if triggers are configured: ```javascript // Manually start any playlist saltfish.startPlaylist('onboarding-tour'); ``` ## Common Use Cases ### Onboarding Flow ```javascript // Initialize on page load saltfish.init({ token: 'YOUR_TOKEN', enableAnalytics: true }); // Identify user after signup saltfish.identify(userId, { email: userEmail, language: 'auto', plan: 'free' }); // Backend triggers will automatically show onboarding // when configured in CMS for new users ``` ### Feature Announcement ```javascript saltfish.init('YOUR_TOKEN'); saltfish.identify(userId); // Configure in CMS to trigger on /new-feature page // Playlist auto-plays when user visits ``` ### Help Button ```html <button id="help-btn">Help</button> <script> saltfish.init('YOUR_TOKEN'); saltfish.identify(userId); // Configure in CMS with element selector: #help-btn // Playlist auto-triggers when user clicks </script> ``` ### Context-Specific Tours ```javascript // Different tours for different pages saltfish.init('YOUR_TOKEN'); saltfish.identify(userId); // Configure in CMS: // - "/dashboard" → dashboard-tour // - "/settings" → settings-tour // - "/billing" → billing-tour // Tours trigger automatically based on URL ``` ## Framework Integration ### React ```jsx import { useEffect } from 'react'; import saltfish from 'saltfish'; function App() { useEffect(() => { // Initialize Saltfish saltfish.init({ token: process.env.REACT_APP_SALTFISH_TOKEN, enableAnalytics: true }); // Identify user when auth state changes if (user) { saltfish.identify(user.id, { email: user.email, name: user.name, language: 'auto' }); } // Cleanup on unmount return () => { saltfish.destroy(); }; }, [user]); return <div>Your App</div>; } ``` ### Vue ```vue <template> <div>Your App</div> </template> <script> import saltfish from 'saltfish'; export default { mounted() { saltfish.init({ token: process.env.VUE_APP_SALTFISH_TOKEN, enableAnalytics: true }); if (this.user) { saltfish.identify(this.user.id, { email: this.user.email, language: 'auto' }); } }, beforeUnmount() { saltfish.destroy(); } }; </script> ``` ### Angular ```typescript import { Component, OnInit, OnDestroy } from '@angular/core'; import saltfish from 'saltfish'; @Component({ selector: 'app-root', template: '<div>Your App</div>' }) export class AppComponent implements OnInit, OnDestroy { ngOnInit() { saltfish.init({ token: environment.saltfishToken, enableAnalytics: true }); if (this.authService.user) { saltfish.identify(this.authService.user.id, { email: this.authService.user.email, language: 'auto' }); } } ngOnDestroy() { saltfish.destroy(); } } ``` ### Next.js ```javascript // app/layout.js or pages/_app.js 'use client'; import { useEffect } from 'react'; import saltfish from 'saltfish'; export default function RootLayout({ children }) { useEffect(() => { if (typeof window !== 'undefined') { saltfish.init({ token: process.env.NEXT_PUBLIC_SALTFISH_TOKEN, enableAnalytics: true }); // Identify user if logged in // saltfish.identify(userId, { email, language: 'auto' }); } return () => { if (typeof window !== 'undefined') { saltfish.destroy(); } }; }, []); return <html><body>{children}</body></html>; } ``` ## TypeScript Support Full TypeScript definitions included: ```typescript import saltfish, { SaltfishAPI } from 'saltfish'; // All methods are fully typed saltfish.init({ token: 'YOUR_TOKEN', enableAnalytics: true }); saltfish.identify('user-123', { email: 'user@example.com', language: 'en' }); saltfish.startPlaylist('playlist-id', { startNodeId: 'step-2' }); // Event handlers are typed saltfish.on('playlistEnded', (data) => { console.log(data.playlist.id); // Fully typed console.log(data.completionRate); }); ``` ## Browser Support - Chrome/Edge 90+ - Firefox 88+ - Safari 14+ - Opera 76+ ## Getting Started 1. **Sign up** at [saltfish.ai](https://saltfish.ai) 2. **Get your token** from the dashboard 3. **Create playlists** using the CMS 4. **Configure triggers** (optional) for automatic playback 5. **Install** Saltfish in your app ## Support - 📧 Email: [support@saltfish.ai](mailto:support@saltfish.ai) - 🐛 Issues: [GitHub Issues](https://github.com/Saltfish-AB/playlist-player/issues) - 📚 Documentation: [docs.saltfish.ai](https://docs.saltfish.ai) ## License PROPRIETARY - See [LICENSE](./LICENSE) file for details. --- Made with ❤️ by [Saltfish AB](https://saltfish.ai)