0.2.1 • Published 7 months ago

@sammy-labs/success v0.2.1

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

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: "user@example.com",
          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: "demo@example.com",
      },
    };

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

PropTypeDefaultRequired?Description
baseUrlstringYesBase URL for your app's backend API, e.g., https://api.yourapp.com. This is where Sammy will fetch docs, chat, handle authentication, etc.
tokenstringYesShort-lived JWT used for auth. Must be valid for calls to the back-end. Stored in memory only.
onTokenExpired() => voidNoCallback triggered if the token is invalid/expired (HTTP 401). Typically used to prompt a re-login or refresh the token.
orgIdstringDerived from tokenNoIf you prefer to override the organization ID extracted from the token, pass it here.
userUserCredentialsDerived from tokenNoIf you prefer to override user fields from the token, pass them here (id, email, role, etc.).
theme"light" \| "dark"System autodetectNoOverrides the theme. If not provided, it follows the system preference, stored in context.
logostringNoURL for your company logo or brand icon.
botImagestringNoURL for the chatbot avatar.
initialChatTextstringNoA greeting or tagline shown in the chat panel initially.
widthnumber \| string400NoWidth of the help center (px or string).
heightnumber \| string600NoHeight of the help center (px or string).
fixedbooleantrueNoWhether the help center is rendered as a fixed overlay. If false, it will take up available space.
openbooleanfalseNoInitial open/close state of the help center.
initialView"home" \| "messages" \| "help" \| "walkthroughs""home"NoWhich 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"NoWhere the floating button and help center appear on the screen.
buttonRoundedCornersstring"rounded-full"NoTailwind classes for the main widget button shape.
animatedbooleanfalseNoIf true, the help center has small animations on open/close.
customStylesReact.CSSPropertiesNoAdditional inline styles for the help center container.
onOpenChange(open: boolean) => voidNoCallback triggered whenever the help center is opened or closed.
enableOnboardingbooleanfalseNoAdds an onboarding dashboard ("Walkthroughs" tab) and allows the chatbot to create new flows on demand.
walkthroughOverrideDomainUrlstring-NoAllows 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

PropertyDescriptionDefault Value
primaryMain brand color#F84000
secondarySecondary color#0074D9
accentAccent color for highlights#FFC107
errorError messages and indicators#DC2626
successSuccess messages and indicators#16A34A
backgroundBackground color#FFFFFF
foregroundText color#111111
borderBorder 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.