obi-loader
v0.8.3
Published
Lightweight loader for Obi Assistant
Downloads
11,898
Maintainers
Readme
Obi Loader
A lightweight loader for the Obi Assistant widget. This package is designed to be as small as possible while still providing the functionality to load the full Obi Assistant from a CDN.
Why Use This Package?
Lightweight Loader: Use this small package to dynamically load the full SDK from a CDN
Benefits of the lightweight loader:
- Significantly smaller bundle size (~5KB vs the full SDK)
- Always loads the latest version of Obi (no need to update for bug fixes)
- Simple API that matches the full SDK's initialization
Installation
npm install obi-loaderTypeScript Support
The package includes full TypeScript support with type definitions for all configuration options.
Using Types with NPM Installation
import { initObi, updateObi, openObiCourses, type ObiAssistantConfig, type ObiUpdateConfig } from "obi-loader"
// Type-safe configuration
const config: ObiAssistantConfig = {
apiKey: "your-api-key",
position: "bottom-right",
user: {
id: "user-123",
email: "[email protected]",
first_name: "John",
last_name: "Doe",
company: "Acme Corp",
metadata: {
plan: "premium",
},
},
}
initObi(config)
// Type-safe updates using the dedicated function (NPM only)
updateObi({
position: "bottom-left",
primaryColor: "#ff6b35",
user: {
id: "user-123",
email: "[email protected]",
first_name: "Jane",
last_name: "Smith",
company: "TechCorp Inc",
metadata: { plan: "enterprise" },
},
// apiKey: "new-key" // ❌ TypeScript error - cannot update apiKey
})
// Open course menu with one function call
openObiCourses()
// Or use the global function if preferred
window.ObiSDK("update", {
position: "top-right",
primaryColor: "#e91e63",
})Using Types with CDN Script
If you're using the CDN script approach but want TypeScript support in your development environment, you can install the package just for types:
npm install --save-dev obi-loaderThe package now includes global type declarations, so you automatically get type safety for both configuration and updates:
// Your TypeScript code with full type safety
window.obiWidgetConfig = {
apiKey: "your-api-key", // ✅ Type-safe
position: "bottom-right", // ✅ Autocomplete works
user: {
id: "user-123",
metadata: { plan: "premium" },
},
}
// Type-safe updates (apiKey automatically excluded)
window.ObiSDK("update", {
position: "top-right", // ✅ Autocomplete for valid positions
primaryColor: "#e91e63", // ✅ Type-checked
// apiKey: "new-key" // ❌ TypeScript error - cannot update apiKey
})TypeScript Support for Updates
For detailed TypeScript type information and usage examples, see the TypeScript Support section above.
Usage
import { initObi } from "obi-loader"
// Initialize Obi with your configuration
initObi({
apiKey: "your-api-key",
position: "bottom-right",
user: {
id: "user-123",
email: "[email protected]",
metadata: {
plan: "premium",
},
},
})API Methods
initObi(config: ObiAssistantConfig)
Initializes the Obi widget with the provided configuration. This should be called once when your application loads.
updateObi(config: Partial<ObiUpdateConfig>) (NPM only)
Updates the widget configuration after initialization. This is a type-safe alternative to using window.ObiSDK("update", config).
import { updateObi } from "obi-loader"
updateObi({
position: "bottom-left",
primaryColor: "#ff6b35",
user: {
id: "user-123",
email: "[email protected]",
},
})Note: The apiKey, urlBlacklist, and linkOnlyAccess options cannot be updated after initialization.
openObiCourses() (NPM only)
Opens the Obi course menu programmatically. This is a convenience function equivalent to updateObi({ showMenu: true }).
import { openObiCourses } from "obi-loader"
// In React
function TrainingButton() {
return <button onClick={openObiCourses}>View Training Courses</button>
}
// In Vue
export default {
methods: {
openCourseMenu: openObiCourses,
},
}
// In vanilla JavaScript
document.getElementById("training-btn").addEventListener("click", openObiCourses)For CDN users: Use window.ObiSDK("update", { showMenu: true }) instead.
CDN Script Alternative
If you prefer not to install the npm package, you can use the CDN script approach directly in your HTML. This method has the same lightweight benefits and automatically loads the latest Obi SDK.
CDN Setup
<!DOCTYPE html>
<html>
<head>
<title>Your Website</title>
</head>
<body>
<!-- Your website content -->
<!-- Configure Obi -->
<script>
window.obiWidgetConfig = {
apiKey: "your-api-key",
position: "bottom-right",
}
</script>
<!-- Load Obi Loader Script -->
<script>
!(function () {
"use strict"
var t = window
!(function () {
var n, o
try {
;(n = new URLSearchParams(location.search)),
(o = {}),
n.forEach(function (t, n) {
o[n] = t
}),
Object.keys(o).length && localStorage.setItem("obi-url-params", JSON.stringify(o))
} catch (t) {}
;(t.ObiSDK =
t.ObiSDK ||
function () {
return (t.ObiSDK.q = t.ObiSDK.q || []), t.ObiSDK.q.push(arguments)
}),
t.ObiSDK("update", t.obiWidgetConfig || {}),
fetch("https://registry.npmjs.org/obi-sdk/latest")
.then(function (t) {
return t.json()
})
.then(function (t) {
return t.version
})
.catch(function () {
return "latest"
})
.then(function (t) {
var n = document.createElement("script")
;(n.defer = !0),
(n.src = "https://unpkg.com/obi-sdk@" + t + "/dist/obi-sdk.standalone.iife.js"),
document.head.appendChild(n)
})
})()
})()
</script>
</body>
</html>CDN Script Benefits
- No build step required: Just add scripts to your HTML
- Zero bundle impact: Scripts load asynchronously without affecting your app's bundle size
- Always up-to-date: Automatically uses the latest Obi SDK version
- Backwards compatible: Works with any website, framework, or CMS
- Lightweight: The loader script itself is under 2KB
Configuration Options
The initObi function accepts the following configuration options:
| Option | Type | Required | Description |
| -------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| apiKey | string | Yes | Your Obi API key |
| position | string | No | Widget position on the screen. Options: 'bottom-right', 'bottom-left', 'bottom-center', 'top-right', 'top-left', 'top-center', 'middle-left', 'middle-right'. Default: 'bottom-right' |
| user | object | No | User information object containing: |
| | | | - id: string (required) - Unique identifier for the user |
| | | | - email: string (optional) - User's email address |
| | | | - first_name: string (optional) - User's first name |
| | | | - last_name: string (optional) - User's last name |
| | | | - company: string (optional) - User's company name |
| | | | - metadata: object (optional) - Additional custom user data |
| isActive | boolean | No | Whether the widget should be active on load. Can be used to filter experience to certain users. Default: true |
| linkOnlyAccess | boolean | No | Hide the widget unless accessed via a session link. Perfect for trial periods where only customers with direct links should see the widget. Initialization only - cannot be updated after widget loads. Default: false |
| showMenu | boolean | No | Manually show the widget menu. If the widget is not mounted, it will mount the widget and show the menu. Default: false |
| primaryColor | string | No | Custom primary color (hex code, e.g. '#9500ff'). Default: '#9500ff' |
| urlBlacklist | string[] | No | Array of URL glob patterns where the widget should not appear. Supports wildcards (* and **) for flexible URL matching. Initialization only - cannot be updated after widget loads. Default: [] |
Example with All Options
initObi({
apiKey: "your-api-key",
position: "bottom-right",
isActive: true,
linkOnlyAccess: false, // Set to true for trial mode
showMenu: false, // Set to true to mount widget and show menu immediately
primaryColor: "#123456", // Custom primary color
urlBlacklist: [
"example.com/admin*", // Block all admin pages
"example.com/private/**", // Block all private section pages
"*/checkout", // Block checkout pages on any subdomain
"staging.*.com/**", // Block all staging environments
],
user: {
id: "user-123",
email: "[email protected]",
first_name: "John",
last_name: "Doe",
company: "Acme Inc", // Now a primary field!
metadata: {
plan: "premium",
role: "admin",
// ... any additional custom user data
},
},
})URL Blacklisting
The urlBlacklist option allows you to specify URL patterns where the widget should not appear. This is useful for excluding admin pages, checkout flows, or other sensitive areas of your website.
Glob Pattern Support
The blacklist supports glob patterns for flexible URL matching:
*- matches any characters except forward slashes**- matches any characters including forward slashes?- matches any single character
Examples
window.obiWidgetConfig = {
apiKey: "YOUR_API_KEY",
urlBlacklist: [
"example.com/admin*", // Block all admin pages
"example.com/checkout/**", // Block entire checkout flow
"*/login", // Block login pages on any subdomain
"staging.*.com/**", // Block all staging environments
"example.com/dashboard/billing", // Block specific billing page
],
}Behaviour
- The widget will not render on pages matching any blacklist pattern
- URL matching is case-insensitive
- Patterns are matched against both full URLs and domain-relative URLs
- In single-page applications, the widget will show/hide dynamically as users navigate
- Blacklist is set at initialization and cannot be changed at runtime for security
Updating Configuration After Mount
Once the Obi widget is loaded, you can dynamically update its configuration using the global ObiSDK function.
TypeScript Support for Updates
For detailed TypeScript type information and usage examples, see the TypeScript Support section above.
Using the Global ObiSDK Function
// Update user information
window.ObiSDK("update", {
user: {
id: "user-456",
email: "[email protected]",
metadata: {
subscription: "premium",
lastActivity: Date.now(),
},
},
})
// Update widget position
window.ObiSDK("update", {
position: "bottom-left",
})
// Toggle widget visibility
window.ObiSDK("update", {
isActive: false,
})
// Show menu (will mount widget if not already mounted)
window.ObiSDK("update", {
showMenu: true,
})
// Update primary colour
window.ObiSDK("update", {
primaryColor: "#ff6b35",
})
// Update multiple config options at once
window.ObiSDK("update", {
position: "top-right",
primaryColor: "#00bcd4",
isActive: true,
showMenu: true,
user: {
id: "user-123",
email: "[email protected]",
metadata: {
plan: "enterprise",
lastLogin: new Date().toISOString(),
},
},
})Using After NPM Installation
When using the npm package, you can use either the dedicated updateObi function or the global function:
import { initObi, updateObi } from "obi-loader"
// After initialization
initObi({
apiKey: "your-api-key",
user: { id: "user-123" },
})
// Option 1: Use the dedicated updateObi function (cleaner for TypeScript)
updateObi({
user: {
id: "user-123",
email: "[email protected]",
first_name: "John",
last_name: "Doe",
company: "Enterprise Corp",
metadata: {
plan: "enterprise",
},
},
position: "bottom-left",
primaryColor: "#ff6b35",
showMenu: true, // Mount widget and show menu
})
// Option 2: Use the global function (works everywhere)
window.ObiSDK("update", {
position: "top-right",
primaryColor: "#00bcd4",
})CDN Script Configuration Updates
When using the CDN script approach, you can update configuration using the global ObiSDK function:
<script>
// Update configuration dynamically
window.ObiSDK("update", {
primaryColor: "#e91e63",
position: "middle-right",
isActive: true,
showMenu: false,
})
// Update user context
window.ObiSDK("update", {
user: {
id: "current-user-id",
email: "[email protected]",
first_name: "Alex",
last_name: "Johnson",
company: "Tech Solutions Inc",
metadata: {
role: "admin",
department: "engineering",
},
},
})
</script>Configuration Update Options
All configuration options from the initial setup can be updated dynamically:
| Updatable Option | Method | Description |
| ---------------- | -------------------------- | ------------------------------------------ |
| user | update({ user }) | Update user ID, email, and metadata |
| position | update({ position }) | Change widget position on screen |
| isActive | update({ isActive }) | Show/hide widget |
| showMenu | update({ showMenu }) | Show widget menu (mounts widget if needed) |
| primaryColor | update({ primaryColor }) | Change the widget's primary colour |
Note: The apiKey, urlBlacklist, and linkOnlyAccess cannot be updated after initialization. If you need to change these values, you'll need to reinitialize the widget.
Programmatic Commands
Beyond configuration updates, the Obi widget supports several programmatic commands for controlling sessions and interactions. These commands are available through the global window.ObiSDK() function.
Start Session
Start an onboarding session programmatically. You can optionally specify which plan to launch and whether to enable the microphone automatically.
NPM Installation:
// Start a session with a specific plan and enable microphone
window.ObiSDK("startSession", {
planUuid: "your-plan-uuid-here",
withMicrophone: true,
})
// Start a session without specifying a plan (user can choose)
window.ObiSDK("startSession")
// Start with microphone enabled but no specific plan
window.ObiSDK("startSession", { withMicrophone: true })CDN Installation:
<!-- Button to start session with specific plan -->
<button onclick="window.ObiSDK('startSession', { planUuid: 'your-plan-uuid-here', withMicrophone: true })">
Start Training
</button>
<!-- Button to start session without specific plan -->
<button onclick="window.ObiSDK('startSession')">Launch Obi</button>Parameters:
planUuid(optional): The UUID of the specific onboarding plan to start. If not provided, the user can select from available plans.withMicrophone(optional): Boolean to automatically enable the user's microphone when the session starts. Defaults tofalse.
Notes:
- When
planUuidis provided, the SDK validates it against available plans for the user. If the plan is not found or not accessible, a warning is logged. - Starting a session automatically sets
isActivetotrue, making the widget visible. - If a session is already active, this command will start a new session.
Send Message
Send a text message to the Obi agent during an active session. This is useful for programmatically triggering specific interactions or providing context.
NPM Installation:
// Send a message to the agent
window.ObiSDK("say", "Can you help me with the dashboard features?")
// Send contextual help request
window.ObiSDK("say", "I'm stuck on the checkout page")CDN Installation:
<!-- Button to request help on specific topic -->
<button onclick="window.ObiSDK('say', 'Show me how to create a new project')">Help: Create Project</button>
<!-- Link to ask about current page -->
<a href="javascript:window.ObiSDK('say', 'Explain this page to me')">Get Help</a>Parameters:
message(required): A string containing the message to send to the agent.
Notes:
- This command requires an active session. If no session is running, the message will be queued or ignored.
- The message appears in the chat as if the user typed it.
- Useful for contextual help triggers based on user actions.
Stop Session
End the current onboarding session programmatically.
NPM Installation:
// Stop the current session
window.ObiSDK("stopSession")CDN Installation:
<!-- Button to end session -->
<button onclick="window.ObiSDK('stopSession')">End Training</button>Parameters:
None.
Notes:
- Cleanly disconnects from the agent and closes the session.
- The widget remains mounted and visible unless
isActiveis also set tofalse. - Session state is cleared from local storage.
TypeScript Support
All commands are fully typed with function overloads for autocomplete and type safety:
// TypeScript will provide autocomplete and type checking
window.ObiSDK("update", { showMenu: true }) // ✓ Valid
window.ObiSDK("startSession", { planUuid: "uuid", withMicrophone: true }) // ✓ Valid
window.ObiSDK("say", "Hello") // ✓ Valid
window.ObiSDK("stopSession") // ✓ Valid
// TypeScript will catch errors
window.ObiSDK("unknownCommand") // ❌ TypeScript error
window.ObiSDK("say", 123) // ❌ TypeScript error - message must be string
window.ObiSDK("startSession", { invalidOption: true }) // ❌ TypeScript errorCommon Use Cases
Contextual Help Triggers
Trigger help based on user actions or page context:
// React: Help button on specific page
function CheckoutPage() {
const handleHelp = () => {
window.ObiSDK("startSession", { withMicrophone: true })
window.ObiSDK("say", "I need help completing my purchase")
}
return <button onClick={handleHelp}>Get Checkout Help</button>
}
// Vue: Contextual help link
export default {
methods: {
requestHelp() {
window.ObiSDK("say", `Help me with ${this.currentFeature}`)
},
},
}Custom Training Launcher
Create custom UI for launching specific training sessions:
// Training dashboard with multiple courses
const trainingCourses = [
{ id: "plan-uuid-1", name: "Getting Started", duration: "5 min" },
{ id: "plan-uuid-2", name: "Advanced Features", duration: "10 min" },
{ id: "plan-uuid-3", name: "Best Practices", duration: "8 min" },
]
function TrainingDashboard() {
const startCourse = (planUuid: string) => {
window.ObiSDK("startSession", {
planUuid,
withMicrophone: true,
})
}
return (
<div>
{trainingCourses.map((course) => (
<button key={course.id} onClick={() => startCourse(course.id)}>
{course.name} ({course.duration})
</button>
))}
</div>
)
}Timed Sessions
Automatically start or stop sessions based on time or user activity:
// Start onboarding after user has been inactive for 2 minutes
let inactivityTimer: NodeJS.Timeout
function resetInactivityTimer() {
clearTimeout(inactivityTimer)
inactivityTimer = setTimeout(() => {
window.ObiSDK("startSession")
window.ObiSDK("say", "It looks like you might need some help. How can I assist you?")
}, 120000) // 2 minutes
}
// Reset timer on user activity
document.addEventListener("mousemove", resetInactivityTimer)
document.addEventListener("keypress", resetInactivityTimer)
// Auto-stop session after 30 minutes
function startTimedSession() {
window.ObiSDK("startSession")
setTimeout(() => {
window.ObiSDK("stopSession")
alert("Your training session has ended due to time limit.")
}, 1800000) // 30 minutes
}Interactive Help System
Build an interactive help system that guides users through tasks:
// Multi-step guided tour
const tourSteps = [
"Let me show you around. First, let's look at your dashboard.",
"Now, let me explain how to create a new project.",
"Next, I'll show you how to invite team members.",
"Finally, let's review the settings page.",
]
function startGuidedTour() {
window.ObiSDK("startSession", { withMicrophone: false })
tourSteps.forEach((message, index) => {
setTimeout(() => {
window.ObiSDK("say", message)
}, index * 5000) // 5 seconds between steps
})
}
// Error recovery helper
function onError(errorType: string, errorDetails: any) {
window.ObiSDK("startSession")
window.ObiSDK(
"say",
`I encountered an error: ${errorType}. Can you help me understand what went wrong? Details: ${JSON.stringify(errorDetails)}`
)
}Common Use Cases
Opening Course Menu from Navigation
NPM Installation:
import { openObiCourses } from "obi-loader"
// React
function NavigationBar() {
return (
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<button onClick={openObiCourses}>Training</button>
</nav>
)
}
// Vue
export default {
methods: {
openTraining: openObiCourses,
},
}CDN Installation:
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="javascript:window.ObiSDK && window.ObiSDK('update', {showMenu: true})">Training</a>
</nav>Dynamic User Context Updates
// Update user context when user logs in
function onUserLogin(userData) {
updateObi({
user: {
id: userData.id,
email: userData.email,
metadata: {
plan: userData.subscription.plan,
joinDate: userData.createdAt,
},
},
})
}
// Update user context when user upgrades plan
function onPlanUpgrade(newPlan) {
updateObi({
user: {
id: currentUser.id,
email: currentUser.email,
metadata: {
...currentUser.metadata,
plan: newPlan,
upgradeDate: new Date().toISOString(),
},
},
})
}Conditional Widget Display
// Show widget only for certain user types
function updateWidgetVisibility(user) {
updateObi({
isActive: user.plan === "premium" || user.role === "admin",
})
}
// Hide widget during checkout process
function enterCheckout() {
updateObi({ isActive: false })
}
function exitCheckout() {
updateObi({ isActive: true })
}How It Works
This package doesn't bundle the full Obi SDK. Instead, it:
- Queries the NPM registry to find the latest version of the
obi-sdkpackage - Dynamically loads the standalone build from the UNPKG CDN
- Creates and initializes the Obi widget with your configuration
This approach ensures your application always uses the latest version of Obi while keeping your bundle size minimal.
Bundle Size Comparison
| Package | Minified Size | | ---------- | ------------- | | obi-sdk | ~200KB | | obi-loader | ~5KB |
License
See LICENSE.txt for details.
