How to Add a Comment Widget to Ghost
Members-only replies, or anyone signed in with Google. Pick one, then paste one line.
Ghost has had native comments since August 2022, and they are members-only by design: a reader has to sign up for your site and be logged in before the reply box appears. That is the right trade for a paid newsletter and the wrong one for an open blog, where most of the people with something to say will never make an account. If you want drive-by readers to post, you add a third-party comment widget instead: one script tag in Settings > Advanced > Code Injection, one <div> wherever the thread belongs, and no Ghost(Pro) tier to upgrade to first.
Ghost ships comments already, and that is the whole decision
The native system runs on your membership list. Ghost states it plainly: commenting is limited to logged-in members. You switch it on at Settings > Membership > Access, click Edit, and the choices are All members or Paid-members only. There is no third option for anonymous readers, and Ghost's own help pages close that door by pointing you at third-party integrations if anonymous commenting is what you need.
That gate is a feature when the thread is part of what people pay for. Subscribers arguing under a paywalled essay is a good room, and requiring a login keeps it that way. It is the wrong gate on an open blog. Someone who landed on your benchmark writeup from an aggregator and wants to tell you the numbers are off will not make an account to do it. The thread stays empty, and you conclude nobody reads.
Pick the system that matches your traffic
| Ghost native comments | BootSignal comments | |
|---|---|---|
| Who can post | Members of your site, logged in. Anonymous commenting is not supported. | Anyone with a Google account. No membership on your site. |
| Turned on at | Settings > Membership > Access, set to All members or Paid-members only | A loader in Code Injection plus a mount <div> |
| Theme requirement | An up-to-date official theme, or {{comments}} added to a custom theme post template | None. The <div> renders where you paste it. |
| Moderation | Hide, show and pin from Ghost admin, with filters and full-text search | Delete a comment or block a poster from the BootSignal dashboard |
| Where the data lives | Your Ghost site | BootSignal, tied to the domains you registered |
| Cost | Community comments are listed as included on every Ghost(Pro) tier | $20 per month or $200 per year per registered domain, every widget included |
Worth saying out loud: Ghost's native moderation is good. Staff can hide and unhide comments, pin one to the top, filter by post, author, visibility or date, and search the full text. If the people you want talking are already members, do not replace that. Add a widget when they are not members and never will be.
The plan gate here is on themes, not on scripts
Code injection is not a paid add-on. Ghost(Pro)'s plan comparison table has no code injection row at all: the Site Header and Site Footer fields sit under Settings > Advanced on every tier, and self-hosted Ghost has no tiers to gate anything with. Community comments are listed as included on every tier too, so neither system is what you would be upgrading to unlock.
The theme file is the gated part. Ghost(Pro) lists custom themes and marketplace themes as unavailable on Starter and available from Publisher upward, so the post.hbs route below needs Publisher or above on Ghost(Pro). The HTML card route and the per-post injection route work on any tier, and on self-hosted Ghost all three are open. Decide which route you are taking before you start. It does not change the snippet, only where the snippet goes.
What the thread looks like on a post
2 comments
- M
One line and done, did not expect setup to be this easy!
- J
Shared sign-in means nothing else to wire up. 👍
What sits under your article once the div is in place. The comments in it are samples.
One loader, pasted once, in Site Footer
Ghost(Pro) and self-hosted start on different hostnames
Work out which address readers actually reach before you type anything into the BootSignal dashboard, because Ghost has two answers to that. Every Ghost(Pro) site comes with a free
ghost.iosubdomain by default and takes a custom domain later through a CNAME record, so a Pro publication usually spends its early weeks answering onyourpublication.ghost.ioand moves house once the DNS is ready. Self-hosted Ghost has no vendor subdomain to fall back on: it answers on whatever hostname you gave it at install time, often ablog.subdomain sitting next to a marketing site you already run. Register the one readers are on, and register both while a Pro site is mid-move, since the widget matcheslocation.hostnameagainst the list on your site id and stays quiet on anything that is not in it. A leadingwww.is stripped from both sides of that comparison, sowww.example.comneeds no entry of its own, and a registered apex covers its subdomains. What the dashboard gives back is a site id, and that string is what Ghost Admin asks for next.Paste the loader into Site Footer
In Ghost Admin, go to Settings > Advanced > Code Injection. Site Header code is output inside
<head>, Site Footer code just before the closing</body>tag, and Ghost's own tutorial sends JavaScript to Site Footer so it loads properly. The fields are raw HTML, not JS-only, so you supply the<script>tag yourself. Injected code loads after the theme styles and scripts, which is where you want it, and thedeferattribute on the tag keeps it clear of parsing and first render. One loader is all a publication ever needs; anything you mount later is markup, not a second request.<script src="https://bootsignal.com/bootsignal.js" data-site-id="YOUR_SITE_ID" data-lang="en" defer></script>
Three places the mount div can go
Code injection can only write into <head> or immediately before </body>, and that single constraint decides this section. A mount div dropped into Site Footer renders at the very bottom of the page, below your site footer, on the home page and the tag and author archives too, because site-wide injection fires on every single page. So the loader goes in code injection and the div goes somewhere with an opinion about position.
The HTML card, for one post at a time
In the editor, click the + button or type / on a new line, choose the HTML card, and paste the div. Ghost documents HTML cards as the place for embedding external content and integrating third-party tools, and its own Typeform integration uses this exact move. The card sits inline in the post body, so the thread lands under your last paragraph rather than under the site footer.
<div data-bootsignal="comments" data-thread-id="my-post-slug"></div>post.hbs, for every post at the same spot
Ghost's official Disqus integration is the reference pattern, and it applies here unchanged: put the div in post.hbs after the content, and in an official theme, remove the {{#if comments}} block and replace the {{comments}} helper with your markup. Then upload the modified theme and restart Ghost, or make the edit in the in-browser theme editor you reach by clicking Edit code. This is the route that needs custom theme access, so on Ghost(Pro) Starter it is closed.
{{!-- post.hbs, where {{comments}} used to be --}}
<div data-bootsignal="comments" data-thread-id="{{slug}}"></div>Per-post code injection, for a one-off page
Every post has its own Code Injection section in the editor sidebar, with separate Header and Footer fields that apply to that post and nothing else (shipped in Ghost 1.5). Placement follows the same rule, so the thread lands at the bottom of the page rather than under the article: fine on a landing page, wrong on a blog post. Reach for it when you want a thread on one page without touching the theme.
Give every post its own thread id
The data-thread-id attribute separates one page's comments from another's. The widget keys on that value, not on the URL, so two posts carrying the same id share one conversation, and a post whose id changes appears to lose its comments. In an HTML card you type the value by hand, which is fine because you are already inside that post. In post.hbs you are in the post context, so print the post's own slug into the attribute and every article gets its own thread from one template edit.
The catch with slugs is renames. Change a published post's URL and the thread key moves with it, so if you retitle often, bind the attribute to something that never moves, such as the post id. Not every widget needs one: comments, ratings, polls, guestbook, upvote, reactions, viewcount, newsletter and feedback take a thread id, while a reading bar or a table of contents has nothing per-page to store.
Two comment boxes is one too many
All official Ghost themes support member comments by default, so if commenting is enabled you can end up with the native thread and your widget stacked under the same article. Pick one. Turning native comments off at Settings > Membership > Access is the fastest fix and works on any tier. In a custom theme you can instead delete the {{#if comments}} block from the post template, which is the same edit the Disqus pattern asks for. On Starter, where custom themes are not available, the settings toggle is the only lever you have.
Running both is defensible in one case: members-only replies on paid posts, a public thread on the free ones. Ghost scopes HTML cards and code injection per post, so that split needs no theme fork.
What this costs on our side
Comments are part of the BootSignal subscription: $20 per month or $200 per year per registered domain, with all 31 paid widgets included and nothing that scales with traffic. Adding a reading bar next month does not change the bill, and widgets released after you subscribe are included too. Extra domains are bought separately from the dashboard, worth knowing if you keep the ghost.io address registered alongside the custom one after a move. The pricing page has the details, and the alternatives section compares hosted comment systems against each other.
One line in Site Footer, one div in an HTML card.
Two more widgets for a long Ghost post
These two earn their place on the kind of long essay that draws comments in the first place, and both mount exactly the way the thread did: an HTML card in the post, or a line in the template. Neither takes a thread id, and neither adds a request, because the loader in Site Footer is already on the page.
A slim top bar that fills as visitors read
Reading progress: a slim bar that fills as visitors move down a long essay.
Auto contents · highlights the current section
Table of contents, built from your headings, highlighting the section being read.
<div data-bootsignal="reading"></div>
<div data-bootsignal="toc"></div>Six ways a Ghost install goes quiet
- Nothing renders anywhere: you are looking at the editor, not the published page. Update the post and open the live URL.
- It works on
yoursite.ghost.iobut not on your custom domain, or the reverse: the widget checkslocation.hostnamefirst, and each hostname has to be registered against your site id. - You see the thread but a logged-out reader does not: check the eye icon on the HTML card. Member-restricted cards are hidden from public visitors entirely.
- Two posts show the same comments: they share a
data-thread-id. Give each one its own value, or bind the attribute to the post slug in the template. - The thread renders at the very bottom of the page, under the footer: the div went into a code injection field, which can only write before
</body>. Move it into an HTML card or intopost.hbs. - Comments load but nobody can post: the reply box asks for a Google sign-in, shared across every BootSignal widget on the domain.
Questions people ask
- Do I need a paid Ghost plan to add a comment widget?
- No. Ghost(Pro)'s plan comparison table has no code injection row, so the Site Header and Site Footer fields under Settings > Advanced are there on every tier, including Starter, and self-hosted Ghost has no plan gate at all. The one route that is gated is editing
post.hbs, because custom themes and marketplace themes are listed as unavailable on Starter. On that tier, mount the widget with an HTML card or per-post code injection instead. - Can I put a thread on a Ghost page, not just a post?
- Yes. An HTML card behaves the same inside a page as inside a post, so a thread under an about page or a changelog needs nothing beyond its own
data-thread-id. The template route is the one that does not carry over, sincepost.hbsrenders posts and pages come from their own template file, so threads on both means either mounting pages by hand with cards or repeating the edit in the page template. Ghost documents native comments as a post-level feature and does not say anywhere whether they render on pages, so this is one place where the widget is the more predictable of the two. - My posts go out as an email newsletter too. Do subscribers see the thread in the email?
- No, and no widget can change that. Email clients do not run JavaScript, so the mount div arrives as inert markup and the loader never executes, whatever Ghost puts in the email body. The conversation only exists on the web version of the post. If most of your audience reads in the inbox, that is an argument for the HTML card route: put one line of copy directly above the card telling newsletter readers to open the post in a browser if they want to reply.
- Can I keep Ghost member comments and add a public widget too?
- Technically yes, and on an official theme both threads will render under the same post unless you intervene. The useful version of this is per-post: keep native member comments on paid posts, and drop the widget into the free ones through an HTML card. If you only want one system everywhere, turn native commenting off at Settings > Membership > Access.
- Do readers have to become members of my site to comment?
- Not with the widget. They sign in with Google, and that sign-in is shared across every BootSignal widget on your domain. Ghost native comments are the opposite: membership plus a login, with a name and expertise prompt the first time someone posts.
- I switched themes and the thread disappeared. Did the comments go with it?
- No. Comments are stored against the
data-thread-idvalue, not against your theme, so a new theme that has no mount div hides the thread without touching a word of it. Put the div back with the same id and the whole conversation is there again. This is the practical reason to prefer HTML cards on the posts you care about: card markup is part of the post, so it survives a theme swap, while apost.hbsedit belongs to the theme file and does not travel to the theme you switch to. - How do I moderate what people write?
- From the BootSignal dashboard, where you can delete a comment or block a poster. If you are comparing that against staying native, Ghost admin gives you hide and unhide, pinning, filtering by post, author, visibility or date, and full-text search across your comments.
Registration gives you the site id that goes into the Site Footer snippet.
Services in this guide
Read next
Where these numbers come from
- Ghost Help: Adding styles with code injection (Settings > Advanced, header and footer output) (checked 2026-08-25)
- Ghost Tutorials: How to use Code Injection in Ghost (wrap JavaScript in a script tag, Site Footer) (checked 2026-08-25)
- Ghost Changelog: Post Code Injection (per-post header and footer fields, Ghost 1.5) (checked 2026-08-25)
- Ghost Help: Editor cards (HTML card, the + button and / command, card visibility) (checked 2026-08-25)
- Ghost: Official Ghost + Typeform integration (paste the JavaScript snippet into an HTML card) (checked 2026-08-25)
- Ghost: Official Ghost + Disqus integration (div in post.hbs, replace the comments helper, re-upload the theme) (checked 2026-08-25)
- Ghost Help: Comments (Settings > Membership > Access, All members or Paid-members only, moderation) (checked 2026-08-25)
- Ghost Changelog: Comments for Ghost (15 August 2022 launch, members only, comments helper) (checked 2026-08-25)
- Ghost(Pro) pricing (free ghost.io subdomain and CNAME custom domains, Custom themes No on Starter, Community comments on every tier, no code injection row) (checked 2026-08-25)