When you're in the process of blog development, it's really important to include a comment section that enables interaction with your visitors and encourages receiving feedback. This becomes even more crucial if you're a beginner in writing - just like me - as such feedback can significantly contribute to your progress. When creating , I had a goal of launching it as soon as possible. However, considering including a comment feature, the implementation process could be time-consuming. That's when I started looking for a solution that was easy to set up yet provided essential commenting functionalities. It was during this search that I stumbled upon . my blog-centric personal portfolio Giscus What is Giscus? An open-source comments widget that harnesses the power of . giscus integrates seamlessly with GitHub repositories, making it convenient for developers who prefer using GitHub as a platform for managing their code and projects. In addition, it provides features such as thread-based discussions, Markdown support, reactions, and user authentication through GitHub accounts. Feel free to explore and experience it firsthand in the comment section below 👇. GitHub Discussions this post Giscus drew significant inspiration from , which utilize an issue-based comment system instead of discussions. I experimented with utterances initially, but I found it less convenient due to its reliance on an issue tracker for conversational purposes. utterances Opting for GitHub Discussions over issues offered numerous benefits: Enables organized and separated discussions in a dedicated space. Streamline conversations, promoting more transparent communication and reducing confusion compared to issue-based systems. Come with built-in features tailored for collaborative discussions, enabling a richer and more interactive commenting experience for content creators and visitors. As a result, Giscus offers numerous advantages compared to other services: The visitors can react to a post. The visitors can reply and react to a comment. Have a dozen of built-in themes (including ' ', which can be very useful if you have a dark/light theme on your website) and supports custom themes. preferred_color_scheme How does it work? When Giscus loads, it utilizes the GitHub Discussions Search API to find the corresponding Discussion associated with the current page, using various mappings like , , , etc. URL pathname title Giscus bot will automatically create a discussion on the first comment or reaction if a matching discussion cannot be found. For commenting, visitors need to authorize the Giscus app via the GitHub OAuth flow to post on their behalf. Alternatively, they can directly comment on the linked GitHub Discussion. Comment moderation can be managed on GitHub, giving you control over the comments. When to use it? Giscus is an ideal solution for static websites as it utilizes GitHub Discussions as the backend, eliminating the need to manage a separate backend. However, it can also be used for a backend website, making it adaptable for both scenarios. If your project is open-source, Giscus will function exclusively on public repositories. However, you do have the option to create a separate repository solely for discussions. giscus is particularly suitable for tech-related blogs where visitors are likelier to have a GitHub account. Creating a separate repository for discussions is often recommended, as it allows you the flexibility to direct your website to a different repository without the need to relocate your discussions. Setting up your github account By default, GitHub discussions are disabled. To enable them, navigate to your repository's tab and ensure the box is checked under the section. Settings Discussions Features To inform your community about the intended use of Discussions, you can create a welcome page by clicking . Set up discussions Once Discussions are enabled, installing the Giscus application is next. You can either click here to visit the app page or search for " " on the . giscus GitHub Marketplace Since I've already installed it, I have the button; if you didn't install it before, you should see a green button; click on it as the process is straightforward. configure Install Choose the repository in which you wish to utilize GitHub Discussions. In my case, it's nextjs-giscus-blog. I highly recommend granting access only to the repositories that require . Giscus Giscus configuration With our repository ready for use, the next step is configuring Giscus according to our requirements. To accomplish this, visit the and fill out the provided form. official Giscus app : Select the repository to which Giscus will connect, ensuring you provide the username and the repo name like this . Repository ayoubkhial/nextjs-giscus-blog If all criteria are met, you will see the message " " under the repository input. If you see an error message, re-check all the steps above. Success! This repository meets all of the above criteria. : Select the mapping method that connects the embedding page with the embedded Discussion. This mapping can be accomplished through the , , , and more. I will opt for the pathname in our particular setup as it guarantees uniqueness. Page ↔ Discussions Mapping pathname URL title : When GitHub Discussions are enabled, the repository will have default categories created. However, you can create your own categories according to your preferences. Discussion Category : You have the freedom to choose which features to enable. In our setup, I will allow reactions for the main post and prefer to position the comment box above the comments. This will allow visitors to write a comment without scrolling through previous comments. Features Make sure to enable the " " option. This ensures that Giscus widget is loaded only when the visitor scrolls down to the section where the Giscus instance is located on the page, typically near the bottom.Enabling this option can enhance the visitor experience. Load the comments lazily : Select a theme that complements the design of your website. If your website already supports dark/light mode, leaving it as the "preferred color scheme" may be convenient. Theme Based on your preferences, the tag will be automatically populated further down the Giscus configuration page. It will be similar to the following example. (Keep it close; we'll use it later in our Next.js app) script <script src="https://giscus.app/client.js" data-repo="ayoubkhial/nextjs-giscus-blog" data-repo-id="R_kgDOJlwoBA" data-category="Announcements" data-category-id="DIC_kwDOJlwoBM4CWpCu" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="1" data-input-position="top" data-theme="preferred_color_scheme" data-lang="en" data-loading="lazy" crossorigin="anonymous" async> </script> Alternatively, You can retrieve your repository information, such as and , using the instead. repoId categoryId GitHub GraphQL API Explorer Setup Giscus in your next.js blog Before creating the component, let's add some environment variables that store some of the repository data. If you're using one repository for each environment, you may consider adding the following variables to your file: Comments next.config.js const nextConfig = { env: { COMMENTS_REPO: 'ayoubkhial/nextjs-giscus-blog', COMMENTS_REPO_ID: 'R_kgDOJlwoBA', COMMENTS_CATEGORY: 'Announcements', COMMENT_CATEGORY_ID: 'DIC_kwDOJlwoBM4CWpCu', }, }; module.exports = nextConfig; Update the values with your repository information. Feel free to add any variables you require to be dynamic based on your environments. If you prefer a single repository for all your environments, you can directly utilize the variables in your component without storing them. Now, let's create a component where we wrap the script provided by Giscus. First, create a new file (or , if you're using Typescript) under the folder (or any folder you use to store your shared components). Comments comments.js .jsx .tsx components In fact, there are two methods to inject the into the HTML. Let's begin with the more generic approach. script DOM 'use client'; import { useEffect } from 'react'; const Comments = ({ repo, repoId, category, categoryId }) => { useEffect(() => { const script = document.createElement('script'); const commentsDiv = document.getElementById('post-comments'); script.async = true; script.setAttribute('src', 'https://giscus.app/client.js'); script.setAttribute('data-repo', repo); script.setAttribute('data-repo-id', repoId); script.setAttribute('data-category', category); script.setAttribute('data-category-id', categoryId); script.setAttribute('data-mapping', 'pathname'); script.setAttribute('data-strict', '0'); script.setAttribute('data-reactions-enabled', '1'); script.setAttribute('data-emit-metadata', '0'); script.setAttribute('data-input-position', 'top'); script.setAttribute('data-theme', 'preferred_color_scheme'); script.setAttribute('data-lang', 'en'); script.setAttribute('data-loading', 'lazy'); script.setAttribute('crossorigin', 'anonymous'); try { commentsDiv.appendChild(script); } catch (error) { console.error('Error while rendering giscus widget.', error); } }, []); return ( <div id="post-comments"> <h2>Comments</h2> </div> ); }; export default Comments; Since we use browser features like and , you must mark the component as a component. React Hooks DOM client We can obtain the same outcome by utilizing the , a wrapper for the identical script. This approach appears more streamlined and seamlessly integrates with the React ecosystem. Giscus React component First, you need to install package: @giscus/react # Replace "npm" with your preferred package manager. npm i @giscus/react Then change the component to use this package instead: Comments 'use client'; import Giscus from '@giscus/react'; const Comments = ({ repo, repoId, category, categoryId }) => { return ( <Giscus repo={repo} repoId={repoId} category={category} categoryId={categoryId} mapping="pathname" reactionsEnabled="1" emitMetadata="0" inputPosition="top" theme="preferred_color_scheme" lang="en" loading="lazy" /> ); }; export default Comments; The component accepts our environment variables as parameters. Since we're using a client component, we don't have direct access to those variables; therefore, we need to pass them when invoking this component fromthe component, which is a server component. You can access the environment variables in a server component through . Here's an example of what it may look like: Comments BlogPost process.env import Comment from '@/components/comment'; import dynamic from 'next/dynamic'; export default function BlogPost({ params }) { const { slug } = params; const Article = dynamic(() => import(`../../../content/${slug}.js`), { loading: () => <p>Loading...</p>, }); const repo = process.env.COMMENTS_REPO; const repoId = process.env.COMMENTS_REPO_ID; const category = process.env.COMMENTS_CATEGORY; const categoryId = process.env.COMMENTS_CATEGORY_ID; return ( <main> <div className="container"> <article className="blog__content"> <Article /> </article> <Comment repo={repo} repoId={repoId} category={category} categoryId={categoryId} /> </div> </main> ); } Instead of using files to store the post content in the content folder, it is generally preferred and customary to utilize format for storing your content. I'm using the here for simplicity. jsx MDX jsx During the build time, will inject values into the variables. However, it is important to note that you cannot utilize destructuring to access them due to the nature of . If you opt for the traditionalapproach of storing environment variables in a file, you can utilize destructuring to access them. Next.js Webpack .env . Read more on next.js documentation Based on your system's theme, the final result will be displayed in either dark or light mode. Feel free to experience it live in the comment section of . this article Advanced configuration Content Security Policy If you have a strict , you will encounter a " " error in your browser. To fix that, you must modify it to include within your policy's section. Content Security Policy violation of Content Security Policy giscus.app frame-src const ContentSecurityPolicy = ` default-src 'self' vercel.live; script-src 'self' 'unsafe-eval' 'unsafe-inline' vercel.live vitals.vercel-insights.com; style-src 'self' 'unsafe-inline'; img-src * blob: data:; media-src 'none'; frame-src giscus.app; connect-src *; font-src 'self'; `; const securityHeaders = [ { key: 'Content-Security-Policy', value: ContentSecurityPolicy.replace(/\n/g, ''), }, // Other security headers // ... ]; const nextConfig = { env: { COMMENTS_REPO: 'ayoubkhial/nextjs-giscus-blog', COMMENTS_REPO_ID: 'R_kgDOJlwoBA', COMMENTS_CATEGORY: 'Announcements', COMMENTS_CATEGORY_ID: 'DIC_kwDOJlwoBM4CWpCu', }, headers() { return [ { source: '/(.*)', headers: securityHeaders, }, ]; }, }; module.exports = nextConfig; Alternatively, you can add it as a fallback within the section. default-src Giscus configuration file You can configure two more options for your . For that, create a file under the root directory. giscus.app giscus.json { // Change the default comment ordering by configuring giscus.app // default: oldest "defaultCommentOrder": "newest", // restrict from which websites people can load your comments (a security layer) "origins": ["https://www.ayoubkhial.com"], // or use a regular expression instead "originsRegex": ["https?://([a-z0-9]+[.])ayoubkhial[.]com"] } Read more about Giscus advanced features on the . Advanced Usage page Conclusion Giscus provides a neat and reliable solution for managing your blog comments, eliminating the need to maintain your commenting system. It's a perfect fit, particularly for tech blogs 💎. You can find the complete code source in ; feel free to give it a star ⭐️. this repository Also published . here