Bit by Chatbyte and Next.js

This demo showcases how to integrate Bit by Chatbyte into your Next.js application. Bit is a powerful chat widget that can be easily embedded into any web application.

Important: Bit is designed to be flexible and can be implemented in many ways. We've chosen to use a React Context Provider pattern in this demo, but you can integrate it however fits your application architecture. We do not ship a BitProvider component—you'll need to implement your own integration based on your needs.

BitProvider Implementation

Here's the complete BitProvider implementation we use in this demo. For external users, load the Bit script from the CDN URL https://cdn.chatbyte.ai/bit/spark.min.js. You can copy and adapt this code for your own implementation:

'use client';
 
import React, {
  createContext,
  useContext,
  useEffect,
  useState,
  type ReactNode,
} from 'react';
import { useRouter } from 'next/navigation';
import type { Bit } from '@chatbyte-platform/bit-spark';
 
type BitState = 'initial' | 'loading' | 'done' | 'error';
 
interface BitContextValue {
  state: BitState;
  bit: Bit | null;
  error: Error | null;
}
 
const BitContext = createContext<BitContextValue | undefined>(undefined);
 
export interface BitProviderProps {
  agentId: string;
  apiOrigin: string;
  children: ReactNode;
}
 
export const BitProvider: React.FC<BitProviderProps> = ({
  agentId,
  apiOrigin,
  children,
}) => {
  const [state, setState] = useState<BitState>('initial');
  const [bit, setBit] = useState<Bit | null>(null);
  const [error, setError] = useState<Error | null>(null);
  const router = useRouter();
 
  useEffect(() => {
    let isMounted = true;
 
    const initializeBit = async () => {
      setError(null);
      try {
        setState('loading');
        const { createBit } = await import(
          /* webpackIgnore: true */
          'https://cdn.chatbyte.ai/bit/spark.min.js'
        );
 
        const bitInstance = await createBit(agentId, { 
          apiOrigin, 
          theme: 'dark' 
        });
 
        if (isMounted) {
          setBit(bitInstance);
          setState('done');
        }
      } catch (err) {
        if (isMounted) {
          setError(
            err instanceof Error 
              ? err 
              : new Error('Failed to initialize Bit'),
          );
          setState('error');
        }
      }
    };
 
    initializeBit();
 
    return () => {
      isMounted = false;
    };
  }, [agentId, apiOrigin]);
 
  // Set up navigation handler when bit is available
  useEffect(() => {
    if (!bit) return;
 
    bit.setNavigationHandler((url: string) => {
      router.push(url);
    });
  }, [bit, router]);
 
  return (
    <BitContext.Provider value={{ state, bit, error }}>
      {children}
    </BitContext.Provider>
  );
};
 
export const useBit = (): BitContextValue => {
  const context = useContext(BitContext);
 
  if (context === undefined) {
    throw new Error(
      'React hook \`useBit\` must be used within a \`<BitProvider />\`',
    );
  }
 
  if (context.state === 'error' && context.error) {
    throw context.error;
  }
 
  return context;
};

Using BitProvider

Wrap your application with the BitProvider component:

import { BitProvider } from './BitProvider';
 
export default function Layout({ children }) {
  return (
    <BitProvider
      agentId="your-agent-id"
      apiOrigin="https://app.chatbyte.ai"
    >
      {children}
    </BitProvider>
  );
}

Using the useBit Hook

Access the Bit instance using the useBit hook in any client component:

'use client';
 
import { useBit } from './BitProvider';
 
export function MyComponent() {
  const { bit, state } = useBit();
 
  if (state === 'loading') {
    return <div>Loading Bit...</div>;
  }
 
  return (
    <button onClick={() => bit?.open()}>
      Open Chat
    </button>
  );
}

Documentation

For more details about available functions, methods, and advanced configuration options, please refer to the official Bit documentation.

Next.js Specific Functionality

Bit can be integrated with Next.js-specific features to provide a seamless experience within your application.

Navigation Handler

For native navigation within your Next.js app, it makes sense to pass a function wrapped around router.push to Bit's navigation handler. This ensures that links clicked within Bit use Next.js's client-side navigation instead of full page reloads.

'use client';
 
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
 
// Inside your BitProvider component
const router = useRouter();
 
useEffect(() => {
  if (!bit) return;
 
  bit.setNavigationHandler((url: string) => {
    router.push(url);
  });
}, [bit, router]);

Try it out: Open Bit (using the button below) and look for a message with a "Navigate" link. Click it to see native navigation in action!

Try It Out

Use the buttons below to interact with Bit: