Next.js gives you so many ways to render a page that the answer to "how do I add comments" depends on which version you're on and which architecture you've chosen. Here's a single approach that works for both the App Router and the Pages Router: a small client component that wraps the EchoThread widget (privacy-first, no ads, under 15 KB gzipped, free during beta).
1. Get an API key
Sign up at echothread.io, add your domain, copy the key.
2. Add to .env.local
NEXT_PUBLIC_ECHOTHREAD_API_KEY=YOUR_API_KEY
The NEXT_PUBLIC_ prefix is mandatory for client-side access.
3. Create components/EchoThread.tsx
"use client";
import Script from "next/script";
export default function EchoThread({ theme = "auto" }: { theme?: string }) {
const apiKey = process.env.NEXT_PUBLIC_ECHOTHREAD_API_KEY;
if (!apiKey) return null;
return (
<section
className="echothread-wrapper"
style={{ marginTop: "4rem", paddingTop: "2rem", minHeight: 400 }}
>
<div id="echothread" data-api-key={apiKey} data-theme={theme}></div>
<Script src="https://cdn.echothread.io/widget.js" strategy="lazyOnload" />
</section>
);
}
The lazyOnload strategy ensures the widget never blocks LCP.
4. Use it in your post page
App Router (app/blog/[slug]/page.tsx):
import EchoThread from "@/components/EchoThread";
export default async function Post({ params }) {
const post = await getPost(params.slug);
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
<EchoThread />
</article>
);
}
Pages Router is essentially identical — same component, just imported into your pages/blog/[slug].tsx.
5. Handle soft navigation
Next.js does client-side navigation between routes. To make sure the widget refreshes when readers click between posts, force a remount with a key prop:
"use client";
import { usePathname } from "next/navigation";
import EchoThread from "@/components/EchoThread";
export default function Wrapper() {
const pathname = usePathname();
return <EchoThread key={pathname} />;
}
For Pages Router, use useRouter().asPath instead.
Done
The widget identifies threads by page URL automatically. Server components stay server components — only the comment island hydrates.
Full guide with troubleshooting and CSP notes: echothread.io/docs/guides/nextjs
Top comments (0)