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.
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
- An Astro site (v2+)
- An EchoThread account — create one free
- Your site's API key from the EchoThread dashboard
Step 1 — Create the component
Create 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>
<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:
---
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:
---
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>
MDX integration
If you write content in MDX, you can import and use the EchoThread component directly in your .mdx files:
---
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"
/>
Theming
Add data-theme and data-accent-color props to the component:
---
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
localhostfor 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