Next.js Installation
Add Simple Commenter to your Next.js application using the built-in Script component. This guide covers both the App Router and Pages Router.
Important: The domain in your script must exactly match the domain you registered in your Simple Commenter dashboard. If they don't match, the widget won't load.
App Router (Next.js 13+)
Add the Script component to your root layout:
// app/layout.jsx
import Script from "next/script";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://simplecommenter.com/js/comments.min.js?domain=your-domain.com"
strategy="afterInteractive"
/>
</body>
</html>
);
}
Replace your-domain.com with your actual domain from the Simple Commenter dashboard.
Pages Router
Add to your custom App component:
// pages/_app.jsx
import Script from "next/script";
export default function App({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<Script
src="https://simplecommenter.com/js/comments.min.js?domain=your-domain.com"
strategy="afterInteractive"
/>
</>
);
}
Or add to your custom Document:
// pages/_document.jsx
import { Html, Head, Main, NextScript } from "next/document";
import Script from "next/script";
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
<Script
src="https://simplecommenter.com/js/comments.min.js?domain=your-domain.com"
strategy="beforeInteractive"
/>
</body>
</Html>
);
}
Script Strategies
Next.js Script component supports different loading strategies:
| Strategy | Description | Best For |
|---|---|---|
| afterInteractive | Loads after page is interactive | Most cases (recommended) |
| lazyOnload | Loads during browser idle time | Performance-focused apps |
| beforeInteractive | Loads before page hydration | Critical scripts |
// Recommended for most cases
<Script
src="https://simplecommenter.com/js/comments.min.js?domain=your-domain.com"
strategy="afterInteractive"
/>
// For better performance (slight delay)
<Script
src="https://simplecommenter.com/js/comments.min.js?domain=your-domain.com"
strategy="lazyOnload"
/>
Using Data Attribute
If you prefer the data-attribute method:
<Script
src="https://simplecommenter.com/js/comments.min.js"
data-domain="your-domain.com"
strategy="afterInteractive"
/>
Environment Variables
Store your domain in environment variables:
# .env.local
NEXT_PUBLIC_SC_DOMAIN=your-domain.com
// app/layout.jsx or pages/_app.jsx
<Script
src={`https://simplecommenter.com/js/comments.min.js?domain=${process.env.NEXT_PUBLIC_SC_DOMAIN}`}
strategy="afterInteractive"
/>
Conditional Loading
Only load on certain pages:
// app/layout.jsx
import Script from "next/script";
import { headers } from "next/headers";
export default function RootLayout({ children }) {
const headersList = headers();
const pathname = headersList.get("x-pathname") || "";
// Only load on certain paths
const showWidget = ["/", "/about", "/contact"].some(
(path) => pathname.startsWith(path)
);
return (
<html lang="en">
<body>
{children}
{showWidget && (
<Script
src="https://simplecommenter.com/js/comments.min.js?domain=your-domain.com"
strategy="afterInteractive"
/>
)}
</body>
</html>
);
}
For conditional loading, you may need middleware to set the pathname header.
Page-Specific Widget
To only add the widget to specific pages, import Script in that page:
// app/feedback/page.jsx
import Script from "next/script";
export default function FeedbackPage() {
return (
<>
<h1>Feedback</h1>
<p>Leave us your feedback!</p>
<Script
src="https://simplecommenter.com/js/comments.min.js?domain=your-domain.com"
strategy="afterInteractive"
/>
</>
);
}
Verifying Installation
- Run your development server (
npm run dev) - Open your app in the browser
- Look for the feedback widget button
- Check browser console (F12) for errors
- Test across different routes
Troubleshooting
Widget not appearing
- Verify the Script component is in your layout/app file
- Check the domain matches your dashboard settings exactly
- Ensure no Content Security Policy is blocking the script
- Try
beforeInteractivestrategy ifafterInteractivedoesn't work
Script loading twice
- Remove any duplicate Script components
- Don't add the script in both layout and individual pages
- Check if you have it in both
_app.jsxand_document.jsx
Hydration issues
If you see hydration warnings:
- Move the Script component inside
<body> - Use
afterInteractiveinstead ofbeforeInteractive - The widget itself doesn't cause hydration issues as it injects into the DOM after load
Static export (next export)
The widget works with static exports. The script loads client-side regardless of how the page is rendered.
Need help? Contact support.