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

@sammy-labs/success

v0.2.2

Published

Sammy Labs Toolkit: AI Customer Success

Readme

SAMMY Labs – AI Customer Success Toolkit

The AI engine powering post-sales success by generating personalized walkthroughs, documentation, and onboarding experiences that continuously evolve with your product—keeping users delighted, reducing churn, and driving long-term customer success.

SAMMY is an AI that navigates your app or website exactly like a real user, mapping every possible click to generate and personalize content for each user. It automatically updates all training materials, documentation, video tutorials, and user onboarding flows whenever your product changes—so your team never has to worry about outdated help content again.


Why SAMMY?

Future of Product-Led Growth (PLG)

  • Enhanced User Experience
    Users decide within minutes if your software meets their needs. SAMMY customizes every aspect of the help experience based on user context, ensuring a frictionless, relevant user journey that boosts adoption.

  • Auto-Generated Documentation & Training
    Every time your product updates, SAMMY regenerates context-aware documents, walkthroughs, and video tutorials.

  • AI-Powered Issue Detection
    SAMMY spots UI or feature bugs by continuously exploring your product, connecting issues to real user pain points.

  • Seamless Integrations
    Integrate with Slack, Intercom, HubSpot, Zendesk, Jira, and Notion.


Key Features

  • AI Chatbot
    Conversational UI for users, with SSE streaming responses and optional live-human escalation.

  • Interactive Walkthroughs
    Provide step-by-step in-app guidance, with AI-driven element matching and fallback logic.

  • Auto-Updated Documentation
    Centralized knowledge base auto-syncs with your product's UI changes.

  • Context-Aware Help Center
    A floating panel that unifies Chat, Docs, and Interactive Flows into one experience.

  • Theme Support
    Built-in light/dark mode with system detection, easily customized.

  • JWT Expiry Handling
    Callback onTokenExpired to handle short-lived tokens and prompt for re-authentication.

  • Continuous UI Testing
    Automatic issue detection that correlates user conversations with potential UI bugs.

  • Onboarding Dashboard & Progress Tracking
    A dedicated "Walkthroughs" screen shows onboarding sections, real-time progress bars, and lets users resume or restart any flow.

  • Chat-Generated Walkthroughs
    Ask the bot "Show me how to…". Sammy will instantly generate an interactive walkthrough using the @sammy-labs/walkthroughs engine and launch it.


Installation

npm install @sammy-labs/success
# or
yarn add @sammy-labs/success
# or
pnpm add @sammy-labs/success

Don't forget to import the CSS file in your application:

import "@sammy-labs/success/dist/success.css";

Optional Preflight Reset

If your project doesn't already reset element defaults (or you'd like Sammy's minimal scoped reset), import:

import "@sammy-labs/success/preflight.css";

Quick Start

Below is a minimal example:

import React from "react";
import { SammyProvider } from "@sammy-labs/success";
import "@sammy-labs/success/dist/success.css";

export function App() {
  // Typically, your token is a short-lived JWT from your backend
  const token = "YOUR_JWT_TOKEN";

  // Optionally, if you have a callback for token expiry:
  const handleTokenExpired = () => {
    // e.g. redirect to login or refresh token
    console.warn("Token expired! Re-authenticate user.");
  };

  return (
    <div>
      <SammyProvider
        // Main required fields
        baseUrl="https://api.yourapp.com"
        token={token}
        // These can be extracted from the token, or overridden:
        orgId="ORG_ID" // optional override
        user={{
          id: "USER_ID",
          email: "[email protected]",
          role: "user",
        }}
        // Additional UI & behavior props
        width="450px"
        height="700px"
        position="bottom-right"
        initialView="home"
        initialChatText="Hello! How can I help you today?"
        // Optional callback if token is invalid/expired
        onTokenExpired={handleTokenExpired}
        // Provide a custom logo, or fallback to your brand
        logo="https://yourapp.com/logo.png"
        botImage="https://yourapp.com/chat-bot.png"
        // Customize the button shape, theming, etc.
        buttonRoundedCorners="rounded-full"
        animated
        enableOnboarding={BOOLEAN}
        walkthroughOverrideDomainUrl="{OVERRIDE_BASE_URL}"
      />
      {/* The rest of your application */}
      <YourApp />
    </div>
  );
}

In this example:

  1. SammyProvider wraps your main app or a portion of it.
  2. token is a short-lived JWT; we do not store it in localStorage or sessionStorage, only in memory.
  3. If onTokenExpired is provided, it is called whenever the token is invalid or has expired.
  4. orgId and user can either be explicitly passed or derived automatically from the token.

Once the user clicks on the Sammy help button, they'll see a chat panel with integrated docs, AI suggestions, and more.


Server-Side Token Generation

For secure authentication, you should generate JWT tokens on your server. Here's an example using a server action in Next.js:

"use server";

interface AuthResponse {
  token: string;
  expires_at: string;
}

interface AuthRequest {
  api_key?: string;
  org_id: string;
  user_data: {
    user_id: string;
    first_name: string;
    last_name: string;
    email: string;
  };
}

export async function generateToken(
  baseUrl: string
): Promise<AuthResponse | null> {
  try {
    // Get API key from environment variables
    const apiKey = process.env.API_KEY;

    if (!apiKey) {
      console.error("API_KEY is not defined in environment variables");
      return null;
    }

    // Prepare the request body according to the API schema
    const authRequest: AuthRequest = {
      org_id: process.env.ORG_ID || "00000000-0000-0000-0000-000000000000",
      user_data: {
        user_id: process.env.USER_ID || "00000000-0000-0000-0000-000000000001",
        first_name: "Demo",
        last_name: "User",
        email: "[email protected]",
      },
    };

    // Call the authentication endpoint to get a JWT token
    const response = await fetch(`${baseUrl}/authenticate`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify(authRequest),
    });

    if (!response.ok) {
      // Log more details about the error
      const errorText = await response.text();
      console.error(
        `Failed to generate token: ${response.status} ${response.statusText}`
      );
      console.error(`Error details: ${errorText}`);
      return null;
    }

    const data = await response.json();
    return {
      token: data.token,
      expires_at:
        data.expires_at || new Date(Date.now() + 240 * 60 * 1000).toISOString(), // Fallback if expires_at is not provided
    };
  } catch (error) {
    console.error("Error generating token:", error);
    return null;
  }
}

You can then use this function in your client component:

import { SammyProvider } from "@sammy-labs/success";
import "@sammy-labs/success/dist/success.css";
import { generateToken } from "./actions";
import { useEffect, useState } from "react";

export function App() {
  const [token, setToken] = useState<string | null>(null);

  useEffect(() => {
    async function fetchToken() {
      const authResponse = await generateToken("https://api.sammy-labs.com");
      if (authResponse) {
        setToken(authResponse.token);
      }
    }

    fetchToken();
  }, []);

  if (!token) return <div>Loading...</div>;

  return (
    <div>
      <SammyProvider
        baseUrl="https://api.sammy-labs.com"
        token={token}
        // Other props...
      />
      {/* The rest of your application */}
    </div>
  );
}

Configuration Reference

Below are the main props you can pass to SammyProvider:

| Prop | Type | Default | Required? | Description | | ---------------------- | -------------------------------------------------------------- | ------------------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | baseUrl | string | — | Yes | Base URL for your app's backend API, e.g., https://api.yourapp.com. This is where Sammy will fetch docs, chat, handle authentication, etc. | | token | string | — | Yes | Short-lived JWT used for auth. Must be valid for calls to the back-end. Stored in memory only. | | onTokenExpired | () => void | — | No | Callback triggered if the token is invalid/expired (HTTP 401). Typically used to prompt a re-login or refresh the token. | | orgId | string | Derived from token | No | If you prefer to override the organization ID extracted from the token, pass it here. | | user | UserCredentials | Derived from token | No | If you prefer to override user fields from the token, pass them here (id, email, role, etc.). | | theme | "light" \| "dark" | System autodetect | No | Overrides the theme. If not provided, it follows the system preference, stored in context. | | logo | string | — | No | URL for your company logo or brand icon. | | botImage | string | — | No | URL for the chatbot avatar. | | initialChatText | string | — | No | A greeting or tagline shown in the chat panel initially. | | width | number \| string | 400 | No | Width of the help center (px or string). | | height | number \| string | 600 | No | Height of the help center (px or string). | | fixed | boolean | true | No | Whether the help center is rendered as a fixed overlay. If false, it will take up available space. | | open | boolean | false | No | Initial open/close state of the help center. | | initialView | "home" \| "messages" \| "help" \| "walkthroughs" | "home" | No | Which tab is displayed when the help center is first opened. The "walkthroughs" option is only available when enableOnboarding is true. | | position | "bottom-right" \| "bottom-left" \| "top-right" \| "top-left" | "bottom-right" | No | Where the floating button and help center appear on the screen. | | buttonRoundedCorners | string | "rounded-full" | No | Tailwind classes for the main widget button shape. | | animated | boolean | false | No | If true, the help center has small animations on open/close. | | customStyles | React.CSSProperties | — | No | Additional inline styles for the help center container. | | onOpenChange | (open: boolean) => void | — | No | Callback triggered whenever the help center is opened or closed. | | enableOnboarding | boolean | false | No | Adds an onboarding dashboard ("Walkthroughs" tab) and allows the chatbot to create new flows on demand. | | walkthroughOverrideDomainUrl | string | - | No | Allows you to override the base url for walkthroughs. Useful if you want to test on local or staging environments. |


Handling JWT Authentication

Token Storage

  • We only store the short-lived JWT in memory.
  • No localStorage or sessionStorage usage.

onTokenExpired Callback

  • If your server returns a 401 or token is deemed invalid, we call onTokenExpired.
  • You can then refresh the token, redirect to login, or log the user out.

Token Derivation

By default, we extract orgId and basic user info from your JWT with:

import { extractUserFromToken } from "@sammy-labs/success";

But you can override these by explicitly passing orgId and user.


Advanced Usage

  1. Text-to-Speech (TTS)
    Built-in TTS support can be toggled by the user or code. Messages from the AI can be spoken aloud.

  2. Image Attachments
    Chat UI supports uploading images, which are then sent to your baseUrl for processing.

  3. Walkthrough & Element Highlighting
    AI can produce an in-app step-by-step guide. We use advanced element matching, including XPath, attribute matching, and fallback logic.

  4. Live Chat Escalation
    Real-time chat with a human agent is supported if your backend is configured for live chat (via websockets/Socket.io).

  5. Docs & Help Center
    A dynamic documents viewer is included, with embeddings-based search and markdown rendering.

  6. Onboarding Dashboard & Chat-Generated Walkthroughs
    Enable enableOnboarding to surface a "Walkthroughs" tab that tracks each user's progress and lets the chatbot spin up new interactive guides automatically.


License

MIT License - See LICENSE for details.

    __
___( o >
\     )
 `---'  SAMMY LABS

Theming

The Sammy package now supports custom theming through CSS variables. You can customize the colors of the UI by passing a themeColors prop to the SammyProvider component.

Example

import { SammyProvider } from "@sammy-labs/success";

function App() {
  return (
    <SammyProvider
      token="your-token"
      baseUrl="your-base-url"
      initialChatText="How can I help you today?"
      theme="light" // or "dark"
      themeColors={{
        primary: "#FF0000", // Main brand color
        secondary: "#0000FF", // Secondary color
        accent: "#00FF00", // Accent color for highlights
        error: "#FF0000", // Error messages and indicators
        success: "#00FF00", // Success messages and indicators
        background: "#FFFFFF", // Background color
        foreground: "#000000", // Text color
        border: "#CCCCCC", // Border color
      }}
    >
      {/* Your app content */}
    </SammyProvider>
  );
}

Available Theme Colors

| Property | Description | Default Value | | ---------- | ------------------------------- | ------------- | | primary | Main brand color | #F84000 | | secondary | Secondary color | #0074D9 | | accent | Accent color for highlights | #FFC107 | | error | Error messages and indicators | #DC2626 | | success | Success messages and indicators | #16A34A | | background | Background color | #FFFFFF | | foreground | Text color | #111111 | | border | Border color | #E2E8F0 |

Dark Mode

The package also supports a dark mode theme. You can enable it by setting the theme prop to "dark":

<SammyProvider
  token="your-token"
  baseUrl="your-base-url"
  initialChatText="How can I help you today?"
  theme="dark"
  themeColors={{
    // Optional: Override dark mode colors
    primary: "#FF6B35",
  }}
>
  {/* Your app content */}
</SammyProvider>

In dark mode, the default colors are automatically adjusted for better contrast and readability.