Comments on Static Sites — utterances, giscus & Alternatives
In this tutorial, you'll learn about Comments on Static Sites. We cover key concepts, practical examples, and best practices.
Adding comments to static sites requires third-party services since there is no database or server — GitHub-issue-based tools like utterances and giscus provide free, lightweight, privacy-respecting comment systems that sync with your repository.
What You'll Learn
Why It Matters
Comments drive engagement, provide reader feedback, and build community around your content. Traditional comment systems require a database and moderation backend, but static sites eliminate servers entirely. Third-party comment widgets fill this gap, and choosing the right one affects page load time, user privacy, moderation workflow, and data ownership.
Real-World Use
A developer blog uses utterances to store comments as GitHub Issues, keeping moderation within the existing GitHub workflow. A documentation site uses giscus with GitHub Discussions for threaded conversations and upvoting. A corporate blog chooses Hyvor Talk for its privacy compliance and custom moderation team features.
Comment System Architecture
flowchart TD
A[Static Page] --> B[Comment Widget JS]
B --> C{Backend Service}
C -->|utterances| D[GitHub Issues API]
C -->|giscus| E[GitHub Discussions API]
C -->|Disqus| F[Disqus Servers]
C -->|Hyvor Talk| G[Hyvor Cloud]
C -->|Self-hosted| H[Your Server]
D --> I[GitHub Repository]
E --> I
F --> J[Disqus Database]
G --> K[Hyvor Database]
H --> L[PostgreSQL/SQLite]
style C fill:#f90,color:#fff
Comment Platform Comparison
| Feature | utterances | giscus | Disqus | Hyvor Talk | Self-hosted (Isso) |
|---|---|---|---|---|---|
| Backend | GitHub Issues | GitHub Discussions | Proprietary | Proprietary | Python/PostgreSQL |
| Free tier | Yes | Yes | Yes (ads) | Limited | Yes |
| Privacy | High (no tracking) | High (no tracking) | Low (tracks users) | Medium | High |
| Moderation | Via GitHub | Via GitHub | Dashboard | Dashboard | Admin panel |
| Threading | Flat | Nested | Nested | Nested | Flat |
| Markdown | Yes | Yes (GFM) | Limited | Yes | Yes |
| SSO/LDAP | GitHub Auth | GitHub Auth | Social login | Yes | Self-managed |
| Spam filter | None | None | Built-in | Built-in | Akismet plugin |
| Load time | Very fast | Very fast | Slow (ads) | Fast | Fast |
| Data ownership | You (GitHub) | You (GitHub) | Disqus | Hyvor | You |
utterances Integration
utterances is a lightweight widget that uses GitHub Issues for comment storage. Each page gets its own issue, and readers comment using their GitHub account.
Setup Steps
- Install the utterances GitHub App in your repository
- Configure the widget with your repo mapping
JavaScript Integration
<div id="utterances-container"></div>
<script src="https://utteranc.es/client.js"
repo="yourusername/your-repo"
issue-term="pathname"
label="comments"
theme="github-light"
crossorigin="anonymous"
async>
</script>
Expected behavior: When the page loads, utterances creates or finds a GitHub Issue matching the page path. Readers sign in with GitHub to post comments, which appear as issue comments. All data lives in your repository.
Hugo Shortcode for utterances
{{/* layouts/shortcodes/utterances.html */}}
{{ if not .Site.IsServer }}
<div class="comments">
<h2>Comments</h2>
<script src="https://utteranc.es/client.js"
repo="{{ .Site.Params.utterancesRepo }}"
issue-term="{{ .Site.Params.utterancesTerm | default "pathname" }}"
label="comments"
theme="{{ .Site.Params.utterancesTheme | default "github-light" }}"
crossorigin="anonymous"
async>
</script>
</div>
{{ end }}
Expected behavior: The shortcode renders the utterances widget only in production (not during local development). Configuration values come from the site parameters, making it easy to switch repositories or themes.
giscus Integration
giscus uses GitHub Discussions instead of Issues, providing threaded conversations, upvotes, and a cleaner UI.
Setup Steps
- Install the giscus GitHub App in your repository
- Enable Discussions in your repository settings
- Get your configuration from the giscus website
JavaScript Integration
<div id="giscus-container"></div>
<script src="https://giscus.app/client.js"
data-repo="yourusername/your-repo"
data-repo-id="R_kgDO..."
data-category="Announcements"
data-category-id="DIC_kwDO..."
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="light"
data-lang="en"
crossorigin="anonymous"
async>
</script>
Expected behavior: giscus initializes with the provided configuration, loading comments from GitHub Discussions. Users authenticate via GitHub and can post comments, reply to threads, and add reactions.
giscus Configuration in Hugo
# hugo.toml — giscus parameters
[params]
giscusRepo = "yourusername/your-repo"
giscusRepoId = "R_kgDO..."
giscusCategory = "Announcements"
giscusCategoryId = "DIC_kwDO..."
giscusMapping = "pathname"
giscusTheme = "light"
Disqus Integration
Disqus is the most widely known comment platform but comes with privacy concerns and ad injection on the free tier. It also conflicts with GDPR requirements that static sites typically avoid.
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = "{{ .Permalink }}";
this.page.identifier = "{{ .RelPermalink }}";
};
(function() {
var d = document, s = d.createElement('script');
s.src = 'https://your-shortname.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>
Please enable JavaScript to view the
<a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a>
</noscript>
Privacy and GDPR Compliance
| Service | Cookies | Tracking | GDPR Safe | Alternative for EU |
|---|---|---|---|---|
| utterances | 0 | None | Yes | utterances (no cookies) |
| giscus | 0 | None | Yes | giscus (no cookies) |
| Disqus | 5+ | Behavioral ads | No | Disqus with Do Not Sell |
| Hyvor Talk | 2 | Analytics only | Yes | Hyvor Talk (EU hosting) |
| Isso | 0 | None | Yes | Isso (self-hosted) |
Common Errors
1. Comments Not Loading Due to Missing GitHub App Installation
If utterances or giscus comments do not appear, the GitHub App may not be installed in the repository. Verify the app is installed under your repository settings. Check the browser console for 401 or 403 errors.
2. Cross-Origin Errors with Comment Widgets
Comment widgets loaded from external domains may trigger CORS errors. Ensure the crossorigin="anonymous" attribute is present on the script tag. For utterances, verify the repo name format is owner/repo.
3. Comments Appearing on Wrong Pages
If issue-term is set to pathname but your site uses URL parameters or trailing slashes inconsistently, the same issue may map to multiple pages or the wrong page. Use url mapping or a custom term function for consistent mapping.
4. Rate Limiting with GitHub API
Free GitHub accounts have API rate limits (60 requests/hour for unauthenticated requests). If your site gets heavy traffic, comments may stop loading. utterances and giscus use authenticated requests through the GitHub App, which has higher limits (5,000 requests/hour).
5. Comment Data Loss When Repository Changes
If you rename or transfer the GitHub repository, all existing comment issues are lost. Plan repository names carefully before launching. Use a dedicated repository for comments that will not change.
Practice Questions
1. What is the difference between utterances and giscus?
utterances stores comments as GitHub Issues, while giscus uses GitHub Discussions. giscus supports threaded replies, upvotes, and a richer UI, but requires Discussions to be enabled in the repository.
2. Why is Disqus considered less privacy-friendly than alternatives?
Disqus sets multiple tracking cookies, serves targeted ads on the free tier, and shares user data with third-party ad networks. This violates GDPR requirements without explicit consent.
3. How does utterances map a page to its comment thread?
utterances uses an issue-term parameter that can be set to pathname, url, title, or a custom og:title value. It creates or finds a GitHub Issue matching that term.
4. What happens if the GitHub API rate limit is exceeded?
Comments stop loading temporarily. Authenticated requests (via GitHub App) have a 5,000 requests/hour limit, which is sufficient for most sites. Unauthenticated requests are limited to 60/hour.
5. Challenge: Set up a Hugo shortcode that conditionally renders utterances in production and giscus in a staging environment. Add a fallback message for when JavaScript is disabled. Test both comment systems on the same page.
Mini Project: Comment System Integration with Theme Support
Integrate a comment system into a Hugo theme:
- Create a partial
layouts/partials/comments.htmlthat supports utterances, giscus, and Disqus - Configure the comment system via
hugo.tomlparameters - Add a page-level frontmatter toggle to disable comments on specific pages (
comments: false) - Implement a dark mode theme that switches the comment widget theme dynamically
- Test the integration on a single page and verify comments appear, post correctly, and respect the dark mode setting
Example frontmatter:
---
title: "My Blog Post"
comments: true
commentSystem: giscus
---
The partial implementation:
{{/* layouts/partials/comments.html */}}
{{ if and .Params.comments (not .Site.IsServer) }}
<section class="comments">
<h2>Comments</h2>
{{ if eq .Params.commentSystem "giscus" }}
{{ partial "comments/giscus.html" . }}
{{ else if eq .Params.commentSystem "utterances" }}
{{ partial "comments/utterances.html" . }}
{{ else }}
{{ partial "comments/disqus.html" . }}
{{ end }}
</section>
{{ end }}
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro