Next.js Integration Guide
This guide shows you how to add Heyo to your Next.js application. Compatible with both App Router (Next.js 13+) and Pages Router.
Installation
App Router (Next.js 13+)
Option 1: JavaScript SDK (Recommended)
Install the SDK:
npm install @heyo.so/js
Create a client component components/chat-widget.tsx:
'use client';
import { useEffect } from 'react';
import HEYO from '@heyo.so/js'; // or: import { HEYO } from '@heyo.so/js'
export const ChatWidget = () => {
useEffect(() => {
HEYO.init({ projectId: 'YOUR_PROJECT_ID' });
}, []);
return null;
};
Then add it to your app/layout.tsx:
import { ChatWidget } from '@/components/chat-widget';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<ChatWidget />
</body>
</html>
);
}
Option 2: Script Tag in Layout
Add the Heyo script to app/layout.tsx:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<script
src="https://heyo.so/embed/script"
defer
data-project-id="YOUR_PROJECT_ID"
/>
</head>
<body>{children}</body>
</html>
);
}
Pages Router
Option 1: JavaScript SDK
Install the SDK and create a client component as shown above, then add to pages/_app.tsx:
import { ChatWidget } from '@/components/chat-widget';
export default function App({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<ChatWidget />
</>
);
}
Option 2: Script Tag in Document
Add the script to pages/_document.tsx:
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html lang="en">
<Head>
<script
src="https://heyo.so/embed/script"
defer
data-project-id="YOUR_PROJECT_ID"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
TypeScript Support
Heyo works seamlessly with TypeScript. Install the SDK for full type safety:
npm install @heyo.so/js
// Both import styles work
import HEYO from '@heyo.so/js';
// or: import { HEYO } from '@heyo.so/js';
HEYO.init({ projectId: 'YOUR_PROJECT_ID' });
Advanced Usage
Dynamic Widget Control
Control the widget based on routes or user state:
'use client';
import { useEffect } from 'react';
import { usePathname } from 'next/navigation';
export const ChatWidget = () => {
const pathname = usePathname();
useEffect(() => {
// Hide chat on checkout pages
if (pathname?.includes('/checkout')) {
window.HEYO?.hide();
} else {
window.HEYO?.show();
}
}, [pathname]);
useEffect(() => {
HEYO.init({ projectId: 'YOUR_PROJECT_ID' });
}, []);
return null;
};
Pass Server Data to Widget
Use server components to pass data to the chat widget:
// app/layout.tsx
import { ChatWidget } from '@/components/chat-widget';
import { getUser } from '@/lib/auth';
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const user = await getUser();
return (
<html lang="en">
<body>
{children}
<ChatWidget user={user} />
</body>
</html>
);
}
// components/chat-widget.tsx
'use client';
import { useEffect } from 'react';
import HEYO from '@heyo.so/js'; // or: import { HEYO } from '@heyo.so/js'
export const ChatWidget = ({ user }: { user: any }) => {
useEffect(() => {
HEYO.init({
projectId: 'YOUR_PROJECT_ID',
user: user
? {
name: user.name,
email: user.email,
}
: undefined,
});
}, [user]);
return null;
};
Performance Optimization
Lazy Loading
For optimal performance, lazy load the chat widget:
'use client';
import dynamic from 'next/dynamic';
const ChatWidget = dynamic(() => import('@/components/chat-widget'), {
ssr: false,
});
export default ChatWidget;
Core Web Vitals
Heyo is optimized to have minimal impact on your Core Web Vitals:
- Loads asynchronously with
defer - Minimal bundle size
- No render-blocking resources
Best Practices
- Add Heyo to your root layout for site-wide availability
- Use client components when you need programmatic control
- Leverage Next.js routing to show/hide chat on specific pages
- Pass user context for personalized support experiences
Troubleshooting
Script not loading in production
Ensure the script tag is in the <head> of your document, not in a component that might be conditionally rendered.
Hydration mismatch
If using the script tag in a client component, you may see hydration warnings. Use the SDK method instead.
Widget not persisting across routes
Make sure Heyo is initialized in your root layout, not in individual pages.