npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

obi-loader

v0.8.3

Published

Lightweight loader for Obi Assistant

Downloads

11,898

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-loader

TypeScript 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-loader

The 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 to false.

Notes:

  • When planUuid is 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 isActive to true, 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 isActive is also set to false.
  • 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 error

Common 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:

  1. Queries the NPM registry to find the latest version of the obi-sdk package
  2. Dynamically loads the standalone build from the UNPKG CDN
  3. 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.