Project setup
One CSS import, a couple of bundler settings and a config file.
CSS setup
Add these lines to your global CSS file (for example src/index.css or app/globals.css) - once:
@tailwind base;@tailwind components;@tailwind utilities;@import "@realtimexsco/live-chat/styles.css";That's everything chat needs. styles.cssis pre-compiled, so there's no @source, no @theme and no chat-specific Tailwind config. The @tailwindlines are only for your own app - leave them out if you don't use Tailwind. Set the brand color with the themeColor prop.
Vite - vite.config.ts
Only the chat-related parts - merge them into your existing config:
import path from "path";import { defineConfig } from "vite";import react from "@vitejs/plugin-react"; export default defineConfig({ plugins: [react()], resolve: { alias: { "@": path.join(__dirname, "src") }, // Keep a single copy so the chat shares your app's React, store and socket. dedupe: ["react", "react-dom", "@realtimexsco/live-chat"], }, optimizeDeps: { exclude: ["@realtimexsco/live-chat"], // live-chat stays excluded, but Vite must still pre-bundle its nested // deps (CJS interop, needed under pnpm). Nested `>` paths mean you do // NOT add these to your own package.json. include: [ "@realtimexsco/live-chat > socket.io-client", "@realtimexsco/live-chat > zustand", "@realtimexsco/live-chat > @videosdk.live/react-sdk", ], }, server: { proxy: { // Optional local-dev proxy for the chat REST API (avoids CORS). // Point `apiUrl` at "/chat-api" when running locally. "/chat-api": { target: "https://realtimex.softwareco.com", changeOrigin: true, secure: true, rewrite: (p) => p.replace(/^\/chat-api/, "/api/v1"), }, }, },});Next.js - next.config.ts
import type { NextConfig } from "next"; const nextConfig: NextConfig = { transpilePackages: ["@realtimexsco/live-chat"],}; export default nextConfig;Add "use client" at the top of any file that imports chat.
Project config file
Create src/configs/chat.config.ts:
/** Optional: read _id from the JWT so it always matches the token */function userIdFromToken(token: string): string | undefined { try { const payload = JSON.parse( atob(token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")) ); return payload._id || payload.id; } catch { return undefined; }} const accessToken = "YOUR_JWT_ACCESS_TOKEN"; export const chatConfig = { clientId: "YOUR_CLIENT_ID", accessToken, loggedUserDetails: { _id: userIdFromToken(accessToken) ?? "YOUR_USER_ID", name: "Your Name", email: "you@example.com", }, apiUrl: "https://realtimex.softwareco.com/api/v1", socketUrl: "https://realtimex.softwareco.com", // optional - derived from apiUrl themeColor: "#6366f1",} as const;Environment variables
Optional - read them in chat.config.ts:
# .env.local (Next.js) or .env (Vite, with the VITE_ prefix)NEXT_PUBLIC_CHAT_CLIENT_ID=your-client-idNEXT_PUBLIC_API_V1_BASE_URL=https://realtimex.softwareco.com/api/v1NEXT_PUBLIC_SOCKET_URL=https://realtimex.softwareco.comexport const chatConfig = { clientId: process.env.NEXT_PUBLIC_CHAT_CLIENT_ID ?? "", accessToken: "YOUR_JWT_ACCESS_TOKEN", apiUrl: process.env.NEXT_PUBLIC_API_V1_BASE_URL ?? "", socketUrl: process.env.NEXT_PUBLIC_SOCKET_URL ?? (process.env.NEXT_PUBLIC_API_V1_BASE_URL ?? "").replace(/\/api\/v1\/?$/, ""), // ...};Vite uses import.meta.env.VITE_* instead of NEXT_PUBLIC_*.
Dev proxy (CORS)
If the API blocks browser requests during local development, proxy them through your dev server (Vite):
server: { proxy: { "/chat-api": { target: "https://YOUR_API_HOST", changeOrigin: true, rewrite: (path) => path.replace(/^\/chat-api/, "/api/v1"), }, },},Then set apiUrl: "/chat-api" in chat.config.ts for local development.