title: React & Next.js description: Integrate the Navigic widget into React and Next.js applications. order: 8
React & Next.js
The Navigic widget works in any React or Next.js app. This guide shows how to load the script, initialize the widget, and handle identity in a React-friendly way.
Basic Setup
Create a component that loads the embed script and initializes the widget:
"use client"; // Next.js App Router
import { useEffect } from "react";
const EMBED_SCRIPT_URL = "https://releases.navigic.ai/embed/embed.js?v=7";
const WORKSPACE_ID = "pk_wk_YOUR_KEY";
export function NavigicChat() {
useEffect(() => {
// Don't load twice
if (document.querySelector(`script[src^="${EMBED_SCRIPT_URL}"]`)) {
return;
}
const script = document.createElement("script");
script.src = EMBED_SCRIPT_URL;
script.async = true;
script.dataset.apiKey = WORKSPACE_ID;
script.dataset.manual = "true";
script.onload = () => {
window.NavigicWidget?.init({
workspaceId: WORKSPACE_ID,
displayMode: "bubble",
position: "bottom-right",
});
};
document.body.appendChild(script);
return () => {
window.NavigicWidget?.destroy();
};
}, []);
return null;
}Then render it in your layout:
// app/layout.tsx (Next.js App Router)
import { NavigicChat } from "@/components/navigic-chat";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<NavigicChat />
</body>
</html>
);
}TypeScript
Add a type declaration for the NavigicWidget global:
// types/navigic.d.ts
interface NavigicWidgetAPI {
init(config: {
workspaceId: string;
displayMode?: "bubble" | "panel" | "inline";
position?: "bottom-right" | "bottom-left";
primaryColor?: string;
title?: string;
greeting?: string;
gatewayUrl?: string;
panelWidth?: string;
panelSide?: "left" | "right";
targetElement?: string | HTMLElement;
mode?: "live" | "mock";
}): void;
destroy(): void;
open(): void;
close(): void;
identify(
userId: string,
traits?: Record<string, string>,
auth?: { userHash?: string },
): void;
reset(): void;
}
declare global {
interface Window {
NavigicWidget?: NavigicWidgetAPI;
}
}
export {};Identity with Auth Providers
If you use an auth provider (Clerk, NextAuth, Auth0, etc.), identify the user after they sign in.
With Clerk
"use client";
import { useEffect } from "react";
import { useUser } from "@clerk/nextjs";
export function NavigicIdentify() {
const { user, isSignedIn } = useUser();
useEffect(() => {
if (!isSignedIn || !user) return;
// Fetch HMAC from your API route
fetch("/api/embed-identity", { method: "POST" })
.then((res) => res.json())
.then(({ userHash }) => {
window.NavigicWidget?.identify(
user.id,
{
email: user.primaryEmailAddress?.emailAddress ?? "",
name: user.fullName ?? "",
},
{ userHash },
);
});
}, [isSignedIn, user]);
return null;
}With NextAuth
"use client";
import { useEffect } from "react";
import { useSession } from "next-auth/react";
export function NavigicIdentify() {
const { data: session } = useSession();
useEffect(() => {
if (!session?.user) return;
fetch("/api/embed-identity", { method: "POST" })
.then((res) => res.json())
.then(({ userHash }) => {
window.NavigicWidget?.identify(
session.user.id,
{
email: session.user.email ?? "",
name: session.user.name ?? "",
},
{ userHash },
);
});
}, [session]);
return null;
}Reset on Logout
Call reset() in your sign-out handler:
function handleSignOut() {
window.NavigicWidget?.reset();
// ... your sign-out logic
}Inline Mode in React
For inline mode, pass a ref to the container element:
"use client";
import { useEffect, useRef } from "react";
export function NavigicInline() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!containerRef.current) return;
const script = document.createElement("script");
script.src = "https://releases.navigic.ai/embed/embed.js?v=7";
script.async = true;
script.dataset.apiKey = "pk_wk_YOUR_KEY";
script.dataset.manual = "true";
script.onload = () => {
window.NavigicWidget?.init({
workspaceId: "pk_wk_YOUR_KEY",
displayMode: "inline",
targetElement: containerRef.current!,
});
};
document.body.appendChild(script);
return () => {
window.NavigicWidget?.destroy();
};
}, []);
return <div ref={containerRef} style={{ height: 600, width: "100%" }} />;
}Next.js Pages Router
If you're using the Pages Router instead of App Router, the setup is the same — just remove the "use client" directive and use _app.tsx:
// pages/_app.tsx
import type { AppProps } from "next/app";
import { NavigicChat } from "@/components/navigic-chat";
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<NavigicChat />
</>
);
}