Quickstart Guide

Clone the VapiBlocks template

Clone the VapiBlocks Next14 TailwindCSS starter kit for instant setup, pre-configured with Vapi hook & Orb component. Try copying over and swapping out Orb with other components. To get the starter running, run the following commands:

  1. Step One: Install starter dependencies and run
npm install
npm run dev
  1. Step Two: Configure your Vapi assistant using enviornment variables

Edit the .env file with Vapi Public Key and Vapi Assistant ID. You can configure your assistant and get these values from the Vapi AI Dashboard.

NEXT_PUBLIC_VAPI_PUBLIC_KEY=""
NEXT_PUBLIC_VAPI_ASSISTANT_ID=""

You can work directly in web by forking this codesandbox:

Edit cameronking4/next-tailwind-vapi-starter/main

Alternatively, you can fork this Repl:

Manual Setup

npx create-next-app@latest

After running the command, you will be prompted with a series of questions, this is where you can configure your project to use Vapi Blocks with NextJS and Tailwind CSS.

What is your project named? your-project-name
Would you like to use TypeScript? Yes
Would you like to use ESLint? Yes
Would you like to use Tailwind CSS? Yes
Would you like to use `src/` directory? No
Would you like to use App Router? Yes
Would you like to customize the default import alias No

npm install @vapi-ai/react

Lastly, copy over the use-vapi hook to your "hooks" folder (if using Next.js). If using Vanilla React, Vue or alternative framework copy over to "lib" or similar folder.

//hooks/use-vapi.ts
import { useEffect, useRef, useState, useCallback } from 'react';
import Vapi from '@vapi-ai/web';
 
const publicKey = process.env.VAPI_PUBLIC_KEY; // Replace with your actual public key
const assistantId = process.env.VAPI_ASSISTANT_ID; // Replace with your actual assistant ID
 
const useVapi = () => {
  const [volumeLevel, setVolumeLevel] = useState(0);
  const [isSessionActive, setIsSessionActive] = useState(false);
  const [conversation, setConversation] = useState<{ role: string, text: string }[]>([]);
  const vapiRef = useRef<any>(null);
 
  const initializeVapi = useCallback(() => {
    if (!vapiRef.current) {
      const vapiInstance = new Vapi(publicKey);
      vapiRef.current = vapiInstance;
 
      vapiInstance.on('call-start', () => {
        setIsSessionActive(true);
      });
 
      vapiInstance.on('call-end', () => {
        setIsSessionActive(false);
        setConversation([]); // Reset conversation on call end
      });
 
      vapiInstance.on('volume-level', (volume: number) => {
        setVolumeLevel(volume);
      });
 
      vapiInstance.on('message', (message: any) => {
        if (message.type === 'transcript' && message.transcriptType === 'final') {
          setConversation((prev) => [
            ...prev,
            { role: message.role, text: message.transcript },
          ]);
        }
      });
 
      vapiInstance.on('error', (e: Error) => {
        console.error('Vapi error:', e);
      });
    }
  }, []);
 
  useEffect(() => {
    initializeVapi();
 
    // Cleanup function to end call and dispose Vapi instance
    return () => {
      if (vapiRef.current) {
        vapiRef.current.stop();
        vapiRef.current = null;
      }
    };
  }, [initializeVapi]);
 
  const toggleCall = async () => {
    try {
      if (isSessionActive) {
        await vapiRef.current.stop();
      } else {
        await vapiRef.current.start(assistantId);
      }
    } catch (err) {
      console.error('Error toggling Vapi session:', err);
    }
  };
 
  return { volumeLevel, isSessionActive, conversation, toggleCall };
};
 
export default useVapi;
 

This hook can be extended with advanced function-calling and more.