Next.js renders on the server and hydrates in the browser, so the one rule for adding realtime is simple: the realtime connection belongs in a client component. This guide shows the clean pattern, including a server route that hands the browser a token so your project key never ships to the client.
1. Install the SDK
npm install @nolag/js-sdk
2. Mint a token on the server
Never put a project key in browser code. Add a route handler that creates a token server-side and returns it. The NOLAG_API_KEY stays in your server environment.
// app/api/nolag-token/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
const res = await fetch('https://api.nolag.app/v1/actors', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NOLAG_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'Web Client', actorType: 'device' }),
})
const actor = await res.json()
return NextResponse.json({ token: actor.accessToken })
}
For production, prefer short-lived client tokens minted from your project signing keys so browser sessions get scoped, expiring credentials.
3. Connect from a client component
'use client'
import { useEffect, useState } from 'react'
import { NoLag } from '@nolag/js-sdk'
export default function Chat() {
const [messages, setMessages] = useState<any[]>([])
useEffect(() => {
let client: ReturnType<typeof NoLag> | undefined
let active = true
;(async () => {
const { token } = await fetch('/api/nolag-token').then((r) => r.json())
if (!active) return
client = NoLag(token)
await client.connect()
const room = client.setApp('chat').setRoom('general')
room.subscribe('message')
room.on('message', (data) => setMessages((m) => [...m, data]))
})()
return () => {
active = false
client?.disconnect?.()
}
}, [])
const send = () => {
// room.emit('message', { text: 'Hello!' })
}
return (
<ul>
{messages.map((m, i) => (
<li key={i}>{m.text}</li>
))}
</ul>
)
}
The active flag guards against React running effects twice in development and against a connection resolving after the component unmounts.
Why the client-component rule matters
The NoLag SDK opens a WebSocket, which only exists in the browser. Importing and connecting it in a server component or during SSR will fail. Keep the NoLag(...) call inside useEffect (or an event handler) in a 'use client' file and you avoid the whole class of hydration and "window is not defined" errors.
Next steps
- Read the 5-minute quick start for the full connect, subscribe, and publish flow.
- Skip the plumbing with the chat blueprint, which wraps rooms, typing, and history.
- Building agent features into your app? See the AI agents guide.