Article

July 20, 2026 | 6 min read

Why I Replaced Disqus with Giscus (Privacy and Security)

I removed Disqus from this site and replaced it with Giscus. Here's why Disqus was a privacy problem, what Giscus does differently, and exactly how I wired it into my Astro site.

Why I Replaced Disqus with Giscus (Privacy and Security)

I just ripped Disqus off this site and replaced it with Giscus. Not because Disqus stopped working, it worked fine. But because it had turned into exactly the kind of tracking overhead I tell people to avoid. Here’s the reasoning, the comparison, and exactly how I wired it in.

The problem with Disqus

Disqus is free to use, and like most “free” tools, the business model is the giveaway. A few things pushed me to switch:

  • Third-party tracking. Disqus loads its own scripts, sets cookies, and profiles visitors across every site that embeds it, not just yours. That’s a tracking network riding on your blog.
  • Ads and data monetization. Depending on the plan, Disqus can show ads to visitors and monetize their data. Even without visible ads, the tracking infrastructure is still there.
  • GDPR friction. With EU visitors, Disqus effectively requires a cookie consent banner and a privacy policy disclosure just to load comments. That’s a lot of compliance overhead for a comment box.
  • Performance cost. Disqus injects an iframe plus a handful of external scripts, which noticeably slows page load, especially on mobile.

None of that matches what I actually need from comments: a simple, low-friction way for readers to react to a post.

Why Giscus

Giscus is an open-source comment system built on top of GitHub Discussions. Instead of a third-party tracking network, it stores comments as GitHub Discussion threads in a repository you control.

What that gets you:

  • No tracking, no ads, no cookies by default. Giscus doesn’t run its own analytics or ad network. The only “account” involved is the visitor’s own GitHub account, which they already control.
  • You own the data. Comments live in a GitHub repo as Discussions, exportable, readable, and not locked behind a vendor’s database.
  • Open source. You can read the exact code that runs, instead of trusting a black box.
  • Free, with no catch. No premium tier that removes ads, because there are no ads to begin with.

The trade-off is real and worth saying out loud: commenters need a GitHub account. For a blog aimed at technical people, which this one is, that’s a non-issue. For a general-audience site, it would filter out a chunk of potential commenters. Know your audience before you make this swap.

How I set it up

I went with a clean slate, no migration of old Disqus history, just a fresh start on Giscus. If your audience is small and your posts aren’t comment-heavy, that’s the pragmatic choice; migrating Disqus exports into GitHub Discussions is possible but fiddly and rarely worth the effort.

1. A dedicated repo for comments

Giscus needs a public GitHub repository, visitors can’t see the discussions otherwise. Instead of using my main site repo, I created a separate one just for this: erwinbierens/erwinbierens-comments. Keeping it separate means my actual site code stays clean and the comments repo can be reasoned about (and moderated) on its own.

2. Enable Discussions and install the giscus app

On that repo:

  • SettingsFeatures → enable Discussions.
  • Install the giscus GitHub App on the repo, so it can read and create discussions on visitors’ behalf.
  • Created a Comments category inside Discussions, so blog comments don’t mix with anything else.

3. Pull the config from giscus.app

giscus.app is the official configurator. Point it at your repo and category, and it generates the exact values you need: repo, repo-id, category, and category-id, plus your chosen mapping (I used pathname, so each post URL automatically gets its own discussion thread, created on first comment, no manual setup per post).

4. Centralize the config, not hardcoded per page

Rather than pasting a script tag into every article template, I centralized the giscus settings in src/data/site.ts:

giscus: {
  repo: "erwinbierens/erwinbierens-comments",
  repoId: "R_kgDOTeEYzQ",
  category: "Comments",
  categoryId: "DIC_kwDOTeEYzc4DBlF8",
  mapping: "pathname",
  strict: "0",
  reactionsEnabled: "1",
  emitMetadata: "0",
  inputPosition: "bottom",
  theme: "preferred_color_scheme",
  lang: "en",
  loading: "lazy"
}

And built a small GiscusComments.astro component that reads from that config and only renders anything once repo, repoId, category, and categoryId are all filled in:

---
import { site } from "../data/site";

const giscus = site.giscus;
const isConfigured = Boolean(giscus.repo && giscus.repoId && giscus.category && giscus.categoryId);
---

{isConfigured && (
  <section class="comments-shell">
    <div class="giscus"></div>
    <script is:inline define:vars={{ giscus }}>
      (() => {
        const script = document.createElement("script");
        script.src = "https://giscus.app/client.js";
        script.async = true;
        script.crossOrigin = "anonymous";
        script.setAttribute("data-repo", giscus.repo);
        script.setAttribute("data-repo-id", giscus.repoId);
        script.setAttribute("data-category", giscus.category);
        script.setAttribute("data-category-id", giscus.categoryId);
        script.setAttribute("data-mapping", giscus.mapping);
        script.setAttribute("data-theme", giscus.theme);
        script.setAttribute("data-loading", giscus.loading);
        document.body.appendChild(script);
      })();
    </script>
    <noscript>Please enable JavaScript to view the comments.</noscript>
  </section>
)}

The guard clause matters more than it looks: it means the component fails safe. If the config is ever incomplete, a bad deploy, a missing env value, no giscus script loads at all, instead of loading a broken or misconfigured embed.

5. Theme sync and lazy loading, for free

Two details I didn’t have to build myself:

  • theme: "preferred_color_scheme" makes giscus follow the visitor’s OS/browser dark mode automatically, so the comment widget never looks out of place against the rest of the page.
  • loading: "lazy" defers the iframe until it’s actually needed, which keeps the initial page load light, one of the exact problems Disqus had.

6. Update the paper trail

Comment systems touch more than code. I also updated:

  • privacy.md, the privacy policy no longer references Disqus or its data practices, and now describes what Giscus actually does (and doesn’t) collect.
  • README.md and MIGRATION.md, documented the switch for my own future reference, including the repo name and category used.

7. Verify

npm run build completed clean with no errors, which for a static Astro site is the real proof: no broken imports, no missing config crashing the build.

Was it worth it?

Yes. The comment section is lighter, faster, and doesn’t hand visitor data to a third party for a feature as small as “let people leave a reaction.” If you’re running a technical blog and your readers already live on GitHub, Giscus is a straightforward upgrade. Better privacy story, better performance, and one less cookie banner to justify.

Ads appear here only after advertising consent.