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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@brander/sdk

v0.3.15

Published

BranderUX SDK - Transform AI chat into interactive interfaces

Readme

@brander/sdk

Beta

Official React SDK for embedding BranderUX AI-powered UI widgets in your application.

⚠️ CLOSED BETA - Beta Access Required

This package is currently in closed beta. A beta API token is required to use the widget. Without a valid token, you'll see "Access denied" errors.

To request beta access: Sign in at branderux.com and submit a request through the contact form.

Installation

npm install @brander/sdk
# or
yarn add @brander/sdk

Note: Installation is public, but usage requires a beta access token. Sign in at branderux.com and submit a request through the contact form.

Components

  • Brander - Inline embeddable widget component
  • BranderChatWidget - Floating chat widget with trigger button

Quick Start (Beta Partners)

import Brander from "@brander/sdk";

function App() {
  const handleQuery = async (params) => {
    // Call YOUR AI (OpenAI, Anthropic, etc.)
    // BranderUX instructions are included in params.messages
    const response = await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "gpt-4",
        messages: params.messages,
        max_tokens: params.max_tokens || 2000,
      }),
    });

    const data = await response.json();

    return {
      content: [
        {
          type: "text",
          text: data.choices[0].message.content,
        },
      ],
    };
  };

  return <Brander apiKey="bux_dp_your_beta_token" projectId="your_project_id" onQuery={handleQuery} />;
}

Don't have a token? Sign in at branderux.com and submit a request through the contact form.

Conversation History

The widget automatically manages conversation history with a built-in chat history drawer. Users can create, switch, and delete conversations. Optionally persist conversations across sessions:

import Brander from "@brander/sdk";
import { useState, useEffect } from "react";

function App() {
  const [conversations, setConversations] = useState([]);
  const [activeId, setActiveId] = useState(null);

  // Load from storage on mount
  useEffect(() => {
    const saved = localStorage.getItem("brander_conversations");
    if (saved) {
      const state = JSON.parse(saved);
      setConversations(state.conversations);
      setActiveId(state.activeConversationId);
    }
  }, []);

  return (
    <Brander
      apiKey="bux_dp_your_beta_token"
      projectId="your_project_id"
      onQuery={handleQuery}
      conversations={conversations}
      activeConversationId={activeId}
      onConversationsChange={(state) => {
        setConversations(state.conversations);
        setActiveId(state.activeConversationId);
        localStorage.setItem("brander_conversations", JSON.stringify(state));
      }}
    />
  );
}

Props

Required Props

apiKey: string

Your BranderUX beta API token (format: bux_dp_xxxxx). Get this from your beta access email.

projectId: string

Your BranderUX project ID. Get this from your BranderUX dashboard.

onQuery: (params: CustomerAIParams) => Promise<CustomerAIResponse>

Your AI handler function. Called when BranderUX needs AI processing.

BranderUX instructions are included in params.messages. Simply pass them to your AI.

Example:

const onQuery = async (params) => {
  // Pass messages directly to your AI - BranderUX instructions are included
  const response = await yourAI.chat({
    messages: params.messages,
    max_tokens: params.max_tokens || 2000,
  });
  return { content: [{ type: "text", text: response.text }] };
};

Optional Props

conversations?: Conversation[]

Initial conversations to load. Use with activeConversationId and onConversationsChange for persistence.

activeConversationId?: string

ID of the currently active conversation. Use with conversations and onConversationsChange.

onConversationsChange?: (state: ConversationsState) => void

Callback when conversations change. Use to save conversation state to storage or backend.

customPages?: CustomPage[]

Custom navigation pages to show in the UI.

Example:

customPages={[
  { id: '1', name: 'Dashboard', query: 'Show admin dashboard' },
  { id: '2', name: 'Analytics', query: 'Show sales analytics' }
]}

exampleQueries?: string[]

Example queries to suggest to users.

Example:

exampleQueries={[
  'Show sales report',
  'Display customer list',
  'Show analytics dashboard'
]}

enableQueryEnhancement?: boolean

Enable automatic query optimization. Default: false

useTools?: boolean

Enable Anthropic Tools API. Default: false

variant?: "hybrid" | "classic" | "chat"

Display variant of the Brander component. Default: "classic"

  • "hybrid": Full playground experience with scroll-snapping and query badges
  • "classic": Clean site-focused view with conversation sidebar
  • "chat": Chat-style interface with inline messages

defaultSidebarOpen?: boolean

Default state of the conversation sidebar in "classic" variant only. Default: true

When true, the sidebar is open by default. When false, the sidebar is closed and users must click to open it.

Note: On mobile devices, the sidebar is always closed initially regardless of this setting, and appears as a drawer overlay when opened.

Only applicable when variant is "classic". Ignored for "hybrid" and "chat" variants.

width?: string

Widget width. Default: "100%"

height?: string

Widget height. Default: "600px"

className?: string

CSS class name for the container.

style?: React.CSSProperties

Inline styles for the container.

Full Example

import Brander from "@brander/sdk";

function MyApp() {
  return (
    <div className="app">
      <h1>My Application</h1>

      <Brander
        apiKey="bux_dp_your_beta_token"
        projectId="my-project-id"
        onQuery={async (params) => {
          const response = await fetch("/api/ai", {
            method: "POST",
            body: JSON.stringify(params),
          });
          return response.json();
        }}
        customPages={[
          { id: "1", name: "Dashboard", query: "Show dashboard" },
          { id: "2", name: "Reports", query: "Show reports" },
        ]}
        exampleQueries={["Show today's sales", "Display top customers"]}
        width="100%"
        height="700px"
        className="branderux-widget"
      />
    </div>
  );
}

BranderChatWidget Component

Floating chat widget with customizable trigger button and position.

Import

import { BranderChatWidget } from "@brander/sdk";

Basic Usage

import { BranderChatWidget } from "@brander/sdk";

function App() {
  const handleQuery = async (params) => {
    // Your AI integration
    const response = await fetch("/api/ai", {
      method: "POST",
      body: JSON.stringify(params),
    });
    return response.json();
  };

  return (
    <div>
      <h1>My Application</h1>

      <BranderChatWidget
        apiKey="bux_dp_your_beta_token"
        projectId="my-project-id"
        onQuery={handleQuery}
        position="bottom-right"
      >
        {/* Custom trigger button */}
        <button style={{ padding: "12px 24px", borderRadius: "50px" }}>Chat with AI</button>
      </BranderChatWidget>
    </div>
  );
}

Props

Required Props

Same as Brander component:

  • apiKey - Your BranderUX API token
  • projectId - Your BranderUX project ID
  • onQuery - Your AI handler function
  • children - Custom trigger button/element (React element)

Optional Props

Widget Configuration:

  • position - Widget position: "bottom-right" | "bottom-left" | "top-right" | "top-left" (default: "bottom-right")
  • offset - Offset from edges in pixels:
    offset={{ top: 24, bottom: 24, left: 24, right: 24 }}
    Default: { bottom: 24, right: 24 }
  • widgetSize - Widget popup dimensions:
    widgetSize={{ width: "400px", height: "650px" }}
    Default: { width: "400px", height: "650px" }

Behavior:

  • defaultOpen - Initially open state (default: false)
  • onOpen - Callback when widget opens
  • onClose - Callback when widget closes
  • showBackdrop - Show backdrop overlay when open (default: true)
  • backdropOpacity - Backdrop opacity 0-1 (default: 0.2)
  • closeOnBackdropClick - Close when clicking backdrop (default: true)

Styling:

  • zIndex - z-index for widget elements (default: 9999)
  • widgetClassName - CSS class for popup container
  • animationDuration - Animation duration in ms (default: 200)

Conversation History:

  • conversations - Initial conversations to load
  • activeConversationId - Currently active conversation ID
  • onConversationsChange - Callback for conversation state changes

AI Configuration:

  • customPages - Custom navigation pages
  • exampleQueries - Example queries to suggest
  • enableQueryEnhancement - Enable query optimization (default: false)
  • useTools - Enable Anthropic Tools API (default: false)
  • variant - Display variant: "hybrid" | "classic" | "chat" (default: "classic")
    • "hybrid": Full playground with scroll-snapping and query badges
    • "classic": Clean site-focused view with conversation sidebar
    • "chat": Chat-style scrolling with inline messages

Full Example

import { BranderChatWidget } from "@brander/sdk";
import { MessageCircle } from "lucide-react";

function App() {
  return (
    <div className="app">
      <h1>My Application</h1>

      <BranderChatWidget
        // Required
        apiKey="bux_dp_your_beta_token"
        projectId="my-project-id"
        onQuery={async (params) => {
          const response = await fetch("/api/ai", {
            method: "POST",
            body: JSON.stringify(params),
          });
          return response.json();
        }}
        // Widget Configuration
        position="bottom-right"
        offset={{ bottom: 24, right: 24 }}
        widgetSize={{ width: "450px", height: "700px" }}
        // Behavior
        defaultOpen={false}
        onOpen={() => console.log("Widget opened")}
        onClose={() => console.log("Widget closed")}
        showBackdrop={true}
        backdropOpacity={0.3}
        closeOnBackdropClick={true}
        // AI Configuration
        customPages={[
          { id: "1", name: "Dashboard", query: "Show dashboard" },
          { id: "2", name: "Reports", query: "Show reports" },
        ]}
        exampleQueries={["Show today's sales", "Display top customers"]}
      >
        {/* Custom trigger button */}
        <button
          style={{
            display: "flex",
            alignItems: "center",
            gap: "8px",
            padding: "14px 28px",
            backgroundColor: "#0066FF",
            color: "white",
            border: "none",
            borderRadius: "50px",
            fontSize: "16px",
            fontWeight: 600,
            cursor: "pointer",
            boxShadow: "0 4px 12px rgba(0, 102, 255, 0.3)",
          }}
        >
          <MessageCircle size={20} />
          Chat with AI
        </button>
      </BranderChatWidget>
    </div>
  );
}

TypeScript Support

Full TypeScript support included:

import Brander, {
  BranderProps,
  BranderChatWidget,
  BranderChatWidgetProps,
  CustomerAIParams,
  CustomerAIResponse,
  Conversation,
  ConversationsState,
} from "@brander/sdk";

// Conversation types
interface Conversation {
  id: string;
  title: string;
  createdAt: number;
  updatedAt: number;
  queryHistory: QueryHistoryItem[];
}

interface ConversationsState {
  conversations: Conversation[];
  activeConversationId: string | null;
}

Component Comparison

| Feature | Brander (Inline) | BranderChatWidget | | ---------------------- | ---------------- | -------------------- | | Integration | Inline embed | Floating chat widget | | Trigger Button | None | Custom (required) | | Position | Fixed in layout | Configurable | | Backdrop | No | Yes (optional) | | Custom Dimensions | Yes | Yes | | Use Case | Dashboard pages | Chat support | | Mobile Responsive | Yes | Yes |

FAQ

Why do I see "Access denied"?

The @brander/sdk is currently in closed beta. You need a beta access token (starting with bux_dp_) to use it. Sign in at branderux.com and submit a request through the contact form.

When will it be publicly available?

We're working with select beta partners to refine the platform. Public availability is coming soon - stay tuned for updates!

How do I get beta access?

Sign in at branderux.com and submit a request through the contact form. We'll review applications and reach out if there's a good fit.

License

Private - Authorized users only