@sammy-labs/success v0.2.1
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
CallbackonTokenExpiredto 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/walkthroughsengine and launch it.
Installation
npm install @sammy-labs/success
# or
yarn add @sammy-labs/success
# or
pnpm add @sammy-labs/successDon'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:
SammyProviderwraps your main app or a portion of it.tokenis a short-lived JWT; we do not store it inlocalStorageorsessionStorage, only in memory.- If
onTokenExpiredis provided, it is called whenever the token is invalid or has expired. orgIdandusercan 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:
| 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
401or token is deemed invalid, we callonTokenExpired. - 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
Text-to-Speech (TTS)
Built-in TTS support can be toggled by the user or code. Messages from the AI can be spoken aloud.Image Attachments
Chat UI supports uploading images, which are then sent to yourbaseUrlfor processing.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.Live Chat Escalation
Real-time chat with a human agent is supported if your backend is configured for live chat (via websockets/Socket.io).Docs & Help Center
A dynamic documents viewer is included, with embeddings-based search and markdown rendering.Onboarding Dashboard & Chat-Generated Walkthroughs
EnableenableOnboardingto 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 LABSTheming
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.