Skip to content

How to add comments to an Astro site

Integrate EchoThread comments into your Astro site with a reusable component. Works with content collections, MDX, and any rendering mode.

5 min setup No dependencies
On this page

Why Astro + EchoThread

Astro ships zero JavaScript by default, making it one of the fastest frameworks for content sites. EchoThread complements this philosophy: the widget is a single sub-20 KB gzipped script with no dependencies, no framework runtime, and no build-time integration needed.

Since Astro outputs static HTML, the widget loads exactly like it would on a plain HTML page — no hydration islands, no client directives, no SSR workarounds.

Prerequisites

Step 1 — Create the component

Create src/components/EchoThread.astro:

src/components/EchoThread.astro --- interface Props { pageId: string pageTitle: string pageUrl: string } const { pageId, pageTitle, pageUrl } = Astro.props --- <div id="echothread" data-api-key="YOUR_API_KEY" data-page-url={pageUrl} data-identifier={pageId} data-page-title={pageTitle} ></div> <script src="https://cdn.echothread.io/widget.js"></script>
No client directive needed. The EchoThread widget is a plain <script> tag, not a framework component. Astro renders the HTML at build time, and the script self-initializes in the browser. No client:load or client:only required.

Step 2 — Use in a layout

Import the component in your blog post layout:

src/layouts/BlogPost.astro --- import EchoThread from '../components/EchoThread.astro' const { frontmatter } = Astro.props --- <article> <h1>{frontmatter.title}</h1> <slot /> <EchoThread pageId={frontmatter.slug} pageTitle={frontmatter.title} pageUrl={Astro.url.href} /> </article>

Content collections

If you use Astro's content collections (the recommended approach since Astro v2), pass the collection entry's slug as the identifier:

src/pages/blog/[...slug].astro --- import { getCollection } from 'astro:content' import EchoThread from '../../components/EchoThread.astro' import BlogLayout from '../../layouts/BlogLayout.astro' export async function getStaticPaths() { const posts = await getCollection('blog') return posts.map(post => ({ params: { slug: post.slug }, props: { post }, })) } const { post } = Astro.props const { Content } = await post.render() --- <BlogLayout> <h1>{post.data.title}</h1> <Content /> <EchoThread pageId={post.slug} pageTitle={post.data.title} pageUrl={Astro.url.href} /> </BlogLayout>
Why use the slug? Content collection slugs are derived from the filename and stay stable even if you change the page's URL structure. This means comments survive URL migrations.

MDX integration

If you write content in MDX, you can import and use the EchoThread component directly in your .mdx files:

src/content/blog/my-post.mdx --- title: "My Post" slug: "my-post" --- import EchoThread from '../../components/EchoThread.astro' Your post content here... <EchoThread pageId="my-post" pageTitle="My Post" pageUrl="https://example.com/blog/my-post" />
Heads up: Using the component in a layout (Step 2) is usually better than importing it in every MDX file. The layout approach keeps your content files clean and ensures comments appear consistently.

Theming

Add data-theme and data-accent-color props to the component:

src/components/EchoThread.astro (with theming) --- interface Props { pageId: string pageTitle: string pageUrl: string theme?: string accentColor?: string } const { pageId, pageTitle, pageUrl, theme, accentColor } = Astro.props --- <div id="echothread" data-api-key="YOUR_API_KEY" data-page-url={pageUrl} data-identifier={pageId} data-page-title={pageTitle} data-theme={theme} data-accent-color={accentColor} ></div> <script src="https://cdn.echothread.io/widget.js"></script>

Disable per page

Add a comments field to your content schema and conditionally render the component:

{frontmatter.comments !== false && ( <EchoThread pageId={frontmatter.slug} pageTitle={frontmatter.title} pageUrl={Astro.url.href} /> )}

Troubleshooting

Comments don't appear

  • Check your API key in the dashboard.
  • Make sure the domain matches your site (including localhost for dev).
  • Check the browser console for errors.

Multiple widgets on one page

The EchoThread widget targets id="echothread". Only include the component once per page. If you need comments in multiple spots, you'd need separate container IDs (not currently supported).

Script loads twice

If you include the component in both a layout and an MDX file, the script may load twice. Stick to one approach — layout-level is recommended.

Ready to add comments to your Astro site?

Free during beta. Set up in under 5 min.

Create free account