Adding a Comment System to My Blog
A blog needs comments. But I didn’t want to set up a database and moderation system just for that. Giscus is the compromise.
This blog uses Giscus for comments. It’s based on GitHub Discussions. All comments live in the GitHub repo, no database needed, no third-party service.
Full Flow
User opens article page
↓
Loads giscus.app/client.js
↓
Giscus script reads data- attributes
↓
Uses mapping="pathname" to get current URL path
↓
Queries GitHub Discussions API for matching Discussion
↓
Found → renders comment box and existing comments
Not found → shows "leave a comment" input
↓
User writes comment → clicks submit
↓
Redirects to GitHub OAuth (first time only)
↓
Comment written to repo's Discussions via API
↓
Giscus WebSocket listens for changes → real-time updates
User never leaves the page. Entire flow is seamless.
Integration
Comment system embedded as a script tag in layouts/partials/comments.html:
<div class="blog-post-comments">
<script src="https://giscus.app/client.js"
data-repo="0x1428571429/time-friend.com"
data-repo-id="MDEwOlJlcG9zaXRvcjoxNTQ0NDY1NTc="
data-category="Announcements"
data-category-id="DIC_kwDOCTSq3c4DB723"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="noborder_dark"
data-lang="{{ if eq .Lang "zh" }}zh-CN{{ else }}en{{ end }}"
crossorigin="anonymous">
</script>
</div>
Data storage is GitHub repo 0x1428571429/time-friend.com. Giscus script reads/writes comments through GitHub’s Discussions API. No backend needed.
Reference in page template:
{{ partial "comments.html" . }}
Parameters Explained
data-repo
GitHub repo where comments are stored. 0x1428571429/time-friend.com.
data-repo-id
GitHub internal ID for the repo. MDEwOlJlcG9zaXRvcjoxNTQ0NDY1NTc=.
Fixed value, generated automatically when you enter your repo name at https://giscus.app. First time I set this up, I thought repo-id was just the repo name. Spent a while before realizing I needed the actual generated ID.
data-category / data-category-id
Discussion category. Using Announcements, category ID DIC_kwDOCTSq3c4DB723.
Setup steps:
- Enable Discussions in GitHub repo Settings > Features
- Go to repo’s Discussions tab, create a category
- Select the category on Giscus website, it generates the category-id
One thing: GitHub repo Discussions is not enabled by default. You have to go to Settings > Features and check the Discussions box. I spent a while debugging why Giscus wasn’t working, eventually found this was the issue.
data-mapping
How articles map to Discussions. Using pathname, the current URL path.
For example, user visits /en/archive/blog-architecture-overview, Giscus uses this path to match a Discussion.
Other options:
title: matches by page title. But if you change the title later, old comments are lost → not recommendedurl: matches by full URL. But if domain or protocol changes, comments are lostog:title: matches by Open Graph title
pathname is the most stable. As long as the URL path doesn’t change, the mapping holds. But the flip side is: if you change an article’s slug, all previous comments are gone. Don’t change slugs after publishing. Learned this the hard way.
data-strict
Strict matching. Set to 0, allows partial matching, better tolerance.
data-theme
Giscus theme. noborder_dark matches the blog’s dark theme.
Giscus offers multiple themes: light, dark, noborder_light, noborder_dark, preferred_color_scheme. Custom CSS themes also supported.
data-lang
Comment UI language. Dynamic based on current page:
zh → zh-CN (Chinese)
en → en (English)
Giscus supports dozens of languages.
Others
data-reactions-enabled="1": emoji reactions on commentsdata-emit-metadata="0": no metadata, privacy friendlydata-input-position="bottom": comment input at bottomcrossorigin="anonymous": cross-origin settingasync: non-blocking load
Data Management
All comments live in GitHub repo Discussions. Access at:
https://github.com/0x1428571429/time-friend.com/discussions
From GitHub you can:
- Browse comments: by category, sorted by time
- Manage comments: delete spam, edit or pin replies
- Reply to visitors: reply in Discussions, visitors see it
- Bulk operations: close Discussion, change category, mark as answer
Each article corresponds to one Discussion. Discussion title defaults to the page path, e.g. /en/archive/blog-architecture-overview. Easy to identify which article a comment belongs to.
Giscus internally uses GitHub’s GraphQL API:
- Uses
data-repoto locate repo - Uses
data-mapping(pathname) to build search query - Runs a
searchtype GraphQL query to find matching Discussion - Found → render, not found → show blank, auto-create on first comment
Markdown Support
Giscus comment box supports Markdown:
**bold**
`inline code`
\```javascript
const code = "code block";
\```
Code is auto-highlighted, consistent with the blog’s article style. Important for a tech blog — visitors can paste code when discussing technical issues.
Pros and Cons
Pros
Zero ops. No database, no server, no moderation backend. Comments live in your own GitHub repo, no third-party service shutdown risk.
Data ownership. Comments are repo Discussions. Exportable, migratable, backupable. Unlike Disqus where your data is locked in.
Good UX. GitHub account login, no extra registration. OAuth is handled by Giscus, developer writes zero code.
Real-time updates. WebSocket push, one visitor’s comment shows instantly to others viewing the same article.
Anti-spam. GitHub account has a registration barrier, much fewer spam comments compared to anonymous systems like Disqus.
Cons
Visitor needs GitHub account. Non-developers might not have one. But this blog’s audience is mostly developers, acceptable.
GitHub occasionally unstable in China. Giscus script loads from giscus.app, API calls go to GitHub. Access from China can be slow or timeout. Blog audience is mainly overseas, acceptable.