Comments with giscus

Add GitHub-backed comments with giscus.

OINK supports giscus through a Hextra-compatible comments configuration under params.comments. giscus gives each content page a comment thread backed by GitHub Discussions and lets readers comment through GitHub OAuth.

How giscus works

When a page loads, giscus searches the configured repository for a Discussion that matches the page. If it does not find one, the giscus bot creates it when a reader submits the first comment or reaction. Maintainers moderate comments in GitHub Discussions.

Anyone can read a public thread. To comment, a reader selects Sign in with GitHub and authorizes the giscus app to post on their behalf. OINK never asks for or stores the reader’s GitHub password or access token.

Prepare GitHub

Before configuring OINK:

  1. Use a public GitHub repository for the comment threads. Visitors cannot read Discussions in a private repository.
  2. Enable GitHub Discussions under the repository’s Settings > Features.
  3. Install the giscus GitHub App for that repository. Without the app, visitors cannot comment or react.
  4. Choose a Discussion category. giscus recommends an Announcements category so that only maintainers and the giscus bot can create new Discussions.

The repository ID and category ID are public identifiers, not credentials. Do not add a GitHub personal access token, OAuth secret, or password to Hugo configuration.

Generate repository settings

Open giscus.app and complete its configuration form:

  1. Select the interface language.
  2. Enter the repository as OWNER/REPOSITORY and wait for the validation to succeed.
  3. Select the page-to-Discussion mapping. pathname is OINK’s default.
  4. Choose the Discussion category and optional features.
  5. Locate the generated <script> block.

Copy these generated values into OINK configuration:

Generated attribute OINK key
data-repo repo
data-repo-id repoId
data-category category
data-category-id categoryId

Choose a stable mapping

The mapping determines which Discussion belongs to each page. pathname is a good default when published paths are stable and the same repository serves multiple domains or preview environments.

Changing mapping, moving a page, or changing its permanent URL can make giscus look for a different Discussion. Choose the mapping before collecting comments and preserve redirects or Discussion titles during a migration. Enable strict matching when similar page paths could otherwise select the wrong thread.

Enable comments site-wide

Add the generated identifiers to the consuming site’s hugo.yml and set enable: true:

params:
  comments:
    enable: true
    type: giscus
    giscus:
      repo: OWNER/REPOSITORY
      repoId: REPOSITORY_ID
      category: Announcements
      categoryId: CATEGORY_ID
      mapping: pathname
      strict: 0
      reactionsEnabled: 1
      emitMetadata: 0
      inputPosition: top
      theme: auto
      loading: lazy

Replace all uppercase placeholders with the exact values generated by giscus.app. OINK requires repo, repoId, category, and categoryId before it renders giscus. Missing or blank required values produce a Hugo warning and skip giscus instead of failing the build.

Configuration reference

Key Default Purpose
enable false Enables the configured comment provider globally.
type giscus Selects giscus. Other provider names are not supported.
repo Public repository in OWNER/REPOSITORY form.
repoId Repository node ID generated by giscus.app.
category GitHub Discussions category name.
categoryId Category node ID generated by giscus.app.
mapping pathname Maps the current page to a Discussion.
term Supplies the term required by mappings such as specific or number.
strict 0 Uses strict Discussion-title matching when set to 1.
reactionsEnabled 1 Shows reactions for the Discussion’s main post.
emitMetadata 0 Sends Discussion metadata messages to the parent page.
inputPosition top Places the comment editor at top or bottom.
theme auto Follows the OINK theme, or selects a built-in/custom giscus theme.
lang Page language Overrides the automatically selected giscus interface language.
loading lazy Defers iframe loading until the reader approaches the comments.
ariaLabel Comments Labels the comments region for assistive technology.
errorMessage Load-error text Replaces the message shown when giscus cannot load.

Boolean-like feature values accept YAML booleans or giscus-style 0 and 1 values.

Locale, theme, and accessible text

OINK selects the giscus locale from the active Hugo language. Simplified, Traditional, and Hong Kong Chinese map to the corresponding giscus locales; unsupported languages fall back to English. Set lang only when the automatic choice is not appropriate.

With theme: auto, the iframe follows OINK’s light/dark selector and the browser’s preferred color scheme. A built-in giscus theme name or custom theme URL disables that automatic switch.

For a multilingual site, localize the comments-region label and load-error text under each language’s parameters. Language parameters merge with the global repository settings:

languages:
  en:
    params:
      comments:
        giscus:
          ariaLabel: Comments
          errorMessage: Comments could not be loaded.
  zh:
    params:
      comments:
        giscus:
          ariaLabel: 评论
          errorMessage: 评论加载失败。

Override one page

The comments front matter field overrides the global switch in either direction.

Enable one page

Keep the complete repository configuration in hugo.yml, leave the global switch off, and opt in selected pages:

---
title: Community design notes
comments: true
---

Disable one page

When comments are enabled globally, opt out pages that should remain static:

---
title: Security policy
comments: false
---

An explicit comments: false suppresses both giscus and legacy Disqus on that page.

Coexist with Disqus

OINK keeps existing Hugo Disqus configuration compatible during migration. When valid giscus configuration is active for a page, OINK suppresses Disqus so that only one comment system renders. If giscus is enabled but its required settings are incomplete, OINK warns, skips giscus, and can leave configured Disqus as a fallback.

Remove the Disqus service configuration after the migration is complete and every intended page uses giscus.

Content Security Policy

A strict Content Security Policy must permit giscus in both script-src and frame-src. Merge these sources into the site’s existing policy instead of replacing its other directives:

script-src 'self' https://giscus.app;
frame-src 'self' https://giscus.app;

OINK’s initializer remains a same-origin bundled asset and is included only on pages where giscus is active. If the external script fails or does not create an iframe, OINK clears the loading state and exposes errorMessage in a live status region.

Verify the integration

  1. Build the site and confirm there is no missing-key warning:

    hugo --minify
  2. Start a local preview and open a page where comments should be active:

    hugo server --disableFastRender
  3. Confirm that the giscus iframe shows Sign in with GitHub and uses the active page language.

  4. Toggle OINK between light and dark themes and confirm that the comment widget follows it when theme: auto.

  5. Open a page with comments: false and confirm that it has no giscus or Disqus widget.

  6. Submit one test comment, then confirm that the expected Discussion appears in the configured category and can be moderated on GitHub.

A browser-console message saying that the Discussion was not found is expected before the first comment or reaction creates it.

Troubleshooting

  • The build warns about missing keys: regenerate the configuration at giscus.app and copy all four required identifiers without renaming them.
  • The widget does not appear: check params.comments.enable, params.comments.type, the page’s comments front matter, and Hugo’s warning output.
  • GitHub sign-in or posting fails: confirm that the repository is public, Discussions are enabled, and the giscus GitHub App is installed for the repository.
  • The browser blocks giscus: inspect the console and response headers, then allow https://giscus.app in the applicable CSP directives.
  • An existing thread is not found: restore the original mapping and page path, or rename/migrate the Discussion deliberately before changing the URL.
  • The interface language is wrong: verify the Hugo language name and locale, or set params.comments.giscus.lang explicitly.