Skip to content

Documentation

Everything you need to add EchoThread comments to your website.

Quick start

Get EchoThread running on your site in under a minute. No build tools required.

1

Create an account & register your site

Sign up for free, then add your website domain in the dashboard. You'll receive an API key for your site.

2

Add the embed snippet

Paste this before your closing </body> tag, replacing YOUR_API_KEY with the key from your dashboard:

<div id="echothread"
     data-api-key="YOUR_API_KEY"></div>
<script src="https://cdn.echothread.io/widget.js"></script>
3

You're live

Comments will appear on your page immediately. Manage them from the moderation dashboard.

Configuration

Customize the widget using data-* attributes on the container element.

AttributeDefaultDescription
data-api-key(required)Your site API key from the dashboard.
data-page-urlwindow.location.hrefCanonical URL of the page. Used to group comments into threads.
data-identifierpage URLStable unique ID for the comment thread. Use a slug or database ID so threads survive URL changes.
data-page-titledocument.titleTitle stored with the thread. Shown in the dashboard.
data-themeauto (OS)"light", "dark", or any hex color (e.g. "#FAF7F2") for a custom background. Omit to follow visitor's OS preference.
data-accent-color#ff5a5fCustom accent color for the send button and footer link.

Full example

<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="https://example.com/blog/my-post"
     data-identifier="blog-my-post"
     data-page-title="My Blog Post"
     data-theme="dark"
     data-accent-color="#e8353a"></div>
<script src="https://cdn.echothread.io/widget.js"></script>

Theming

EchoThread supports light and dark themes out of the box. By default, it follows the visitor's operating system preference.

Force a theme

Set data-theme="light" or data-theme="dark" on the container to override OS detection.

Custom background color

Pass any hex color to data-theme to use it as the widget background. Text and surface colors adapt automatically based on the color's luminance.

<div id="echothread"
     data-theme="#FAF7F2"
     ...></div>

Custom accent color

Use data-accent-color to match EchoThread to your brand. This applies to the submit button, active states, and footer link. Accepts any valid CSS color value.

/* Example: override via CSS custom properties */
#echothread {
  --et-accent: #6366f1;
  --et-radius: 12px;
}

CSS custom properties

VariableDefaultDescription
--et-accent#ff5a5fPrimary accent color (buttons, links, active states).
--et-radius8pxBorder radius for cards and inputs.
--et-fontsystem-uiFont family for all widget text.

Features

Threaded replies

Conversations nest up to 5 levels deep. Each reply includes a "Replying to" indicator so readers can follow the conversation flow, even in busy threads.

Reactions

Readers can react to comments with Like, Love, Haha, and Angry. Reactions are shown inline and don't require typing a reply, keeping threads focused.

Image attachments

Commenters can upload JPEG, PNG, GIF, or WebP images directly into their comments. Images are automatically resized, optimized, and served from a CDN.

When a commenter pastes a URL, EchoThread automatically fetches Open Graph metadata and renders a rich preview card with title, description, and thumbnail.

Text formatting

Comments support bold and italic formatting via a simple toolbar or keyboard shortcuts (Ctrl+B / Ctrl+I).

Sorting

Readers can sort comments by newest, oldest, most liked, or most replied. The sort preference persists for the session.

Authentication

Only authenticated users can post comments, which keeps spam to a minimum and gives moderators accountability per commenter.

Commenter sign-in

Visitors sign in with their Google account via OAuth. No passwords to manage, no separate accounts to create. The sign-in flow happens inside the widget without navigating away from your page.

Site owner sign-in

Site owners use magic link authentication. Enter your email, click the link we send, and you're in. No password to remember or reset.

Moderation

EchoThread gives you full control over what appears on your site.

Moderation dashboard

The dashboard lets you approve, reject, or delete comments with a single click. Filter by status (pending, approved, rejected, spam) to work through your queue efficiently.

Auto-approve mode

Toggle auto-approve per site. When enabled, new comments go live immediately without manual review. When disabled, all comments start as "pending" until you approve them.

Spam filter

EchoThread's built-in spam scoring catches common patterns: keyword stuffing, repeated characters, suspicious URLs, excessive caps, and known spam phrases. Flagged comments are sent to your spam queue for review. No third-party services are involved.

Notifications

Get real-time notifications in the dashboard when new comments arrive or spam is detected. The notification bell shows an unread count so you never miss activity.

Site settings

Each site you register has its own configuration. Navigate to My Sites → [your site] in the dashboard to manage these.

SettingDescription
Site nameDisplay name for your site (shown in the dashboard only).
DomainThe domain where the widget is embedded. Used for CORS validation.
DescriptionOptional description for your own reference.
Auto-approveWhen on, new comments are immediately visible. When off, they require manual approval.
Spam filterWhen on, likely spam is automatically flagged and sent to the spam queue.
Allow votingShow or hide upvote/downvote buttons on comments.

API key

Each site has a unique API key that authenticates the embed widget. You can find it on your site's settings page in the dashboard.

Keep your API key private. While the key is included in your page's HTML (and therefore visible to visitors), it is scoped to your registered domain. Requests from other domains will be rejected.

Regenerating your key

If your API key is compromised, click Regenerate on your site settings page. The old key stops working immediately. Update the embed snippet on your site with the new key.

Platform guides

EchoThread works on any website that supports custom HTML. Static site generators are especially popular with EchoThread since they have no built-in backend for comments. Below are detailed setup guides for the most popular platforms.

Static HTML

Static HTML is the simplest integration. No build tools, frameworks, or dependencies — just copy and paste.

Step 1 — Add the embed snippet

Paste the following code in your HTML file where you want the comment section to appear. A good location is after your article content, before the closing </body> tag:

<!-- Add this where you want comments to appear -->
<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="https://example.com/blog/my-post.html"
     data-identifier="my-post"
     data-page-title="My Blog Post"></div>
<script src="https://cdn.echothread.io/widget.js" async></script>

Step 2 — Set your attributes

Replace the placeholder values with your own:

  • data-api-key — your site's API key from the EchoThread dashboard (My Sites → Settings).
  • data-page-url — the full canonical URL of the page. This should be the same URL visitors see in their browser.
  • data-identifier — a unique, stable string for this page (e.g. a slug like "my-post"). This ensures comments stay linked to the page even if you change the URL later.
  • data-page-title — the page title shown in your moderation dashboard and notifications.

Step 3 — Customize (optional)

Add optional attributes to control the look and feel:

<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="https://example.com/blog/my-post.html"
     data-identifier="my-post"
     data-page-title="My Blog Post"
     data-theme="dark"
     data-accent-color="#6366f1"></div>
<script src="https://cdn.echothread.io/widget.js" async></script>

Full page example

Here's a minimal complete HTML page with EchoThread:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Blog Post</title>
</head>
<body>
  <article>
    <h1>My Blog Post</h1>
    <p>Your post content here...</p>
  </article>

  <!-- EchoThread comments -->
  <div id="echothread"
       data-api-key="YOUR_API_KEY"
       data-page-url="https://example.com/blog/my-post.html"
       data-identifier="my-post"
       data-page-title="My Blog Post"></div>
  <script src="https://cdn.echothread.io/widget.js" async></script>
</body>
</html>

Multi-page sites: Each page needs its own unique data-identifier. If all your pages share the same identifier, all comments will appear on every page. Use the page slug, filename, or any unique string.

WordPress

WordPress has a built-in comment system, but many site owners prefer EchoThread for its modern UI, threaded replies, reactions, and spam filtering. There are three ways to add EchoThread depending on how much control you want.

Option A — Custom HTML block (per post)

This is the quickest way to try EchoThread on a single page. Open the post or page in the WordPress block editor, add a Custom HTML block where you want comments, and paste the snippet:

<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="<?php the_permalink(); ?>"
     data-identifier="wp-<?php the_ID(); ?>"
     data-page-title="<?php the_title(); ?>"></div>
<script src="https://cdn.echothread.io/widget.js" async></script>

Note: PHP tags (<?php ... ?>) only work inside theme template files, not in the block editor. If you're using the block editor, hardcode the page URL and a unique identifier instead, or use Option B for automatic values.

Option B — Theme template (site-wide, recommended)

To add EchoThread to every post automatically, edit your theme's single post template. This is the recommended approach for most WordPress sites.

Open single.php (or singular.php) in your active theme and add the snippet after the post content:

<!-- In your theme's single.php, after the_content() -->

<?php if ( comments_open() || get_comments_number() ) : ?>
  <div id="echothread"
       data-api-key="YOUR_API_KEY"
       data-page-url="<?php echo esc_url( get_permalink() ); ?>"
       data-identifier="wp-<?php the_ID(); ?>"
       data-page-title="<?php echo esc_attr( get_the_title() ); ?>"></div>
  <script src="https://cdn.echothread.io/widget.js" async></script>
<?php endif; ?>

Option C — Replace the default comment system

To completely replace WordPress's default comments with EchoThread, create a custom comment template. Add this to your theme's functions.php:

// functions.php — Load EchoThread instead of default comments
function echothread_comments_template( $template ) {
    return get_stylesheet_directory() . '/echothread-comments.php';
}
add_filter( 'comments_template', 'echothread_comments_template' );

Then create echothread-comments.php in your theme folder:

<!-- echothread-comments.php -->
<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="<?php echo esc_url( get_permalink() ); ?>"
     data-identifier="wp-<?php the_ID(); ?>"
     data-page-title="<?php echo esc_attr( get_the_title() ); ?>"></div>
<script src="https://cdn.echothread.io/widget.js" async></script>

Child themes: If you're using a child theme, place echothread-comments.php and functions.php edits in the child theme folder so your changes survive theme updates. This approach works with all major themes including Astra, GeneratePress, Kadence, and block themes (FSE).

Disable WordPress's default comments (optional)

If you're fully switching to EchoThread, you can disable the built-in comment system to avoid confusion:

// functions.php — Disable default WordPress comments entirely
add_action( 'admin_init', function() {
    // Remove comments from admin menu
    remove_menu_page( 'edit-comments.php' );
    // Disable comments on all post types
    foreach ( get_post_types() as $post_type ) {
        remove_post_type_support( $post_type, 'comments' );
        remove_post_type_support( $post_type, 'trackbacks' );
    }
});

Next.js / React

Next.js renders pages on the server or at build time, so you need to load the EchoThread widget on the client side. Create a reusable React component that dynamically injects the script.

Step 1 — Create the component

Create components/EchoThread.jsx (or .tsx):

'use client' // required for Next.js App Router

import { useEffect, useRef } from 'react'

export default function EchoThread({ pageId, pageTitle, pageUrl }) {
  const loaded = useRef(false)

  useEffect(() => {
    if (loaded.current) return
    loaded.current = true

    const script = document.createElement('script')
    script.src = 'https://cdn.echothread.io/widget.js'
    script.async = true
    document.body.appendChild(script)
    return () => script.remove()
  }, [])

  return (
    <div
      id="echothread"
      data-api-key="YOUR_API_KEY"
      data-identifier={pageId}
      data-page-title={pageTitle}
      data-page-url={pageUrl}
    />
  )
}

Step 2 — Use it in a page

Import the component in any page or layout where you want comments. Here's an example for a blog post page using the App Router:

// app/blog/[slug]/page.jsx
import EchoThread from '@/components/EchoThread'

export default function BlogPost({ params }) {
  return (
    <article>
      {/* your post content */}
      <EchoThread
        pageId={params.slug}
        pageTitle="My Blog Post"
        pageUrl={`https://example.com/blog/${params.slug}`}
      />
    </article>
  )
}

Pages Router: The same component works with the Pages Router (pages/ directory). No changes needed — just remove the 'use client' directive since all Pages Router components are client-rendered by default.

Read the full Next.js guide

Hugo

Hugo generates static HTML, making it an ideal fit for EchoThread. Create a partial template that you can include on any page.

Step 1 — Create the partial

Create layouts/partials/echothread.html:

<!-- layouts/partials/echothread.html -->
<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="{{ .Permalink }}"
     data-identifier="{{ .File.UniqueID }}"
     data-page-title="{{ .Title }}"></div>
<script src="https://cdn.echothread.io/widget.js" async></script>

Step 2 — Include in your post layout

Open your single post layout (usually layouts/_default/single.html or layouts/posts/single.html) and add the partial where you want comments to appear:

<!-- layouts/_default/single.html -->
{{ define "main" }}
<article>
  <h1>{{ .Title }}</h1>
  {{ .Content }}

  <!-- Comments -->
  {{ partial "echothread.html" . }}
</article>
{{ end }}

Tip: {{ .File.UniqueID }} gives a stable identifier based on the file path. You can also use {{ .RelPermalink }} or your own front matter field (e.g. {{ .Params.comment_id }}) as the identifier.

Step 3 — Disable on specific pages (optional)

Add a front matter toggle to conditionally show comments:

<!-- In your layout -->
{{ if ne .Params.comments false }}
  {{ partial "echothread.html" . }}
{{ end }}

---
# In a post's front matter, set comments: false to disable
title: "About Me"
comments: false
Read the full Hugo guide

Jekyll

Jekyll builds static HTML from Markdown and Liquid templates. Add EchoThread as an include file that automatically pulls in each post's metadata.

Step 1 — Create the include

Create _includes/echothread.html:

<!-- _includes/echothread.html -->
<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="{{ page.url | absolute_url }}"
     data-identifier="{{ page.id | default: page.url }}"
     data-page-title="{{ page.title | xml_escape }}"></div>
<script src="https://cdn.echothread.io/widget.js" async></script>

Step 2 — Add to your post layout

Open _layouts/post.html (create it if it doesn't exist) and include the snippet after the post content:

<!-- _layouts/post.html -->
---
layout: default
---
<article>
  <h1>{{ page.title }}</h1>
  {{ content }}

  <!-- Comments -->
  {% include echothread.html %}
</article>

Step 3 — Enable/disable per post (optional)

Use front matter to control comments on individual posts:

<!-- In _includes/echothread.html, wrap with a conditional -->
{% unless page.comments == false %}
  <div id="echothread" ...></div>
  <script src="https://cdn.echothread.io/widget.js" async></script>
{% endunless %}

---
# In a post's front matter, set comments: false to disable
title: "My Private Post"
comments: false

GitHub Pages: This works out of the box with GitHub Pages. Since EchoThread is loaded from our CDN, no extra plugins or Jekyll gems are required.

Read the full Jekyll guide

Astro

Astro outputs static HTML by default, so the EchoThread widget works without any special configuration. Create a reusable component to keep your layouts clean.

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>

Step 2 — Use in a blog layout

Import the component in your blog post layout or any .astro page:

<!-- 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, pass the collection entry's slug as pageId for a stable, unique identifier per post.

Read the full Astro guide

Eleventy (11ty)

Eleventy is a flexible static site generator that supports multiple template languages. EchoThread integrates via a simple include file — no plugins needed.

Step 1 — Create the include

Create _includes/echothread.njk (Nunjucks) or _includes/echothread.liquid (Liquid):

Nunjucks (_includes/echothread.njk)
<div id="echothread"
     data-api-key="YOUR_API_KEY"
     data-page-url="{{ page.url | url }}"
     data-identifier="{{ page.fileSlug }}"
     data-page-title="{{ title }}"></div>
<script src="https://cdn.echothread.io/widget.js" async></script>

Step 2 — Include in your post layout

Add the include to your blog post layout (e.g. _includes/layouts/post.njk):

<!-- _includes/layouts/post.njk -->
---
layout: layouts/base.njk
---
<article>
  <h1>{{ title }}</h1>
  {{ content | safe }}

  <!-- Comments -->
  {% include "echothread.njk" %}
</article>

Step 3 — Disable per post (optional)

Use front matter to toggle comments off on specific pages:

<!-- Updated _includes/echothread.njk -->
{% if comments != false %}
  <div id="echothread" ...></div>
  <script src="https://cdn.echothread.io/widget.js" async></script>
{% endif %}

---
# In a post's front matter
title: About Me
comments: false

Template languages: This works with any Eleventy template language (Nunjucks, Liquid, Handlebars, etc.). Just match the include syntax to your template engine. The HTML output is the same.

Read the full Eleventy guide

Gatsby

Gatsby is a React-based SSG, so you'll load the EchoThread widget as a client-side script within a React component. This ensures the widget initializes after Gatsby hydrates the page.

Step 1 — Create the component

Create src/components/EchoThread.jsx:

// src/components/EchoThread.jsx
import React, { useEffect, useRef } from 'react'

export default function EchoThread({ pageId, pageTitle, pageUrl }) {
  const loaded = useRef(false)

  useEffect(() => {
    if (loaded.current) return
    loaded.current = true

    const script = document.createElement('script')
    script.src = 'https://cdn.echothread.io/widget.js'
    script.async = true
    document.body.appendChild(script)
    return () => script.remove()
  }, [])

  return (
    <div
      id="echothread"
      data-api-key="YOUR_API_KEY"
      data-identifier={pageId}
      data-page-title={pageTitle}
      data-page-url={pageUrl}
    />
  )
}

Step 2 — Use in a blog post template

Import the component in your blog post template (e.g. src/templates/blog-post.jsx):

// src/templates/blog-post.jsx
import React from 'react'
import { graphql } from 'gatsby'
import EchoThread from '../components/EchoThread'

export default function BlogPost({ data }) {
  const post = data.markdownRemark

  return (
    <article>
      <h1>{post.frontmatter.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />

      <EchoThread
        pageId={post.fields.slug}
        pageTitle={post.frontmatter.title}
        pageUrl={`https://example.com${post.fields.slug}`}
      />
    </article>
  )
}

export const query = graphql`
  query BlogPostBySlug($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      fields { slug }
      frontmatter { title }
    }
  }
`

MDX: If you use gatsby-plugin-mdx, you can import and use the <EchoThread /> component directly inside your MDX files.

Read the full Gatsby guide

Importing comments

Migrating from another platform? EchoThread can import your existing comments so you don't lose any conversations.

Import from Disqus

EchoThread fully supports Disqus's native XML export format as well as the WXR (WordPress eXtended RSS) format that some Disqus accounts use. Here's a complete step-by-step migration guide.

Step 1 — Export your comments from Disqus

  1. Log in to your Disqus Admin Panel and select the site you want to migrate.
  2. In the left sidebar, navigate to Community → Export.
  3. Click the Export Comments button. Disqus will queue the export and email you a download link. This usually takes a few minutes, but larger sites (10k+ comments) may take up to an hour.
  4. Check your email for the download link. The email will come from export@disqus.com — check your spam folder if you don't see it.
  5. Download the .xml.gz file and extract it to get the raw .xml file. On macOS, double-click the file. On Linux, run gunzip your-export.xml.gz.

Can't find the Export option? The export feature is only available to site admins. If you're a moderator, ask the site owner to perform the export. Also note that Disqus may disable exports temporarily for sites under review.

Step 2 — Upload to EchoThread

  1. Open your EchoThread dashboard and go to My Sites.
  2. Click on the site you want to import comments into.
  3. Click the Import button.
  4. Select Disqus as the source format.
  5. Upload the extracted .xml file (max 10 MB — see below if your file is larger).
  6. Click Import comments and wait for the process to finish.

Once complete, you'll see a summary showing how many threads and comments were imported, skipped, or had errors.

What gets imported

Disqus dataEchoThread mappingNotes
Threads (with URL + title)Thread per page URLURL used as identifier; title preserved
Comments (message body)Comment (HTML preserved)Formatting, links, and inline images kept
Reply hierarchy (parent/child)Nested replies (up to 5 levels deep)Full thread structure maintained
Author name + emailGuest comment with display nameImported as guest comments; email stored if available
TimestampsOriginal created_atChronological order preserved exactly
Approved / pending statusApproved / pending statusUnapproved comments go to your moderation queue
Spam-flagged commentsSpam queueAvailable in moderation dashboard for review
Deleted commentsSkippedDeleted comments are not imported
Votes / likesNot importedDisqus does not include vote data in the XML export
User avatarsNot importedGuest comments show default avatars; logged-in users get their own

Step 3 — Update your embed snippet

After importing, you need to ensure the data-identifier or data-page-url in your EchoThread embed matches the URLs from Disqus. This is how EchoThread connects imported threads to the right pages on your site.

  • If your site URLs haven't changed since you used Disqus, no action is needed — threads are matched by URL automatically.
  • If you've migrated to a new domain or changed your URL structure, use the data-page-url attribute to set the original Disqus URL so the imported threads are found.

Step 4 — Remove Disqus from your site

Once you've verified the import looks correct, remove the Disqus embed code from your site and replace it with the EchoThread snippet. Comments will appear immediately.

Handling large exports (over 10 MB)

EchoThread has a 10 MB upload limit per file. If your Disqus export is larger:

  • Split by thread: Use a script or XML editor to split the export into multiple files, each containing a subset of threads and their associated posts.
  • Import sequentially: Upload each file one at a time. EchoThread's duplicate prevention ensures threads aren't created twice if files overlap.
  • Use the API: For very large migrations (100k+ comments), you can use the import API endpoint directly: POST /api/v1/sites/{site_id}/import with the XML file as a multipart upload.

Supported XML formats

EchoThread auto-detects two Disqus XML formats:

  • Native Disqus XML — the default format from Disqus's export page. Uses <disqus> root element with <thread> and <post> elements.
  • WXR format (WordPress eXtended RSS) — used by some Disqus accounts and WordPress migration tools. Uses <rss> root with <item> and <wp:comment> elements.

You don't need to choose — just upload the file and EchoThread will handle it.

Troubleshooting Disqus imports

  • Comments don't appear on my pages: Check that your embed's data-page-url matches the URLs in the Disqus export. Open your browser's network tab and look for the thread API call to see which URL is being queried.
  • "No threads found" error: Ensure you extracted the .xml.gz file. Uploading the compressed .gz file directly will fail.
  • Some comments are missing: Deleted comments in Disqus are intentionally skipped. Comments with empty bodies are also skipped. Check the import summary for the skipped count.
  • Reply threading looks wrong: This can happen if comments were orphaned in Disqus (parent was deleted). Orphaned replies become top-level comments in EchoThread.
  • Duplicate imports: Running the import again with the same file is safe. If a thread with the same URL already exists, new comments are added to it rather than creating a duplicate thread.

Import from JSON

For other platforms, you can prepare a JSON file with your comments. This is useful for custom migrations from platforms like Commento, Hyvor Talk, or your own database.

{
  "threads": [
    {
      "url": "https://example.com/blog/post",
      "title": "My Blog Post",
      "identifier": "blog-my-post",
      "comments": [
        {
          "id": "1",
          "author": "Jane Doe",
          "body": "Great article!",
          "created_at": "2024-01-15T10:30:00Z",
          "parent_id": null
        },
        {
          "id": "2",
          "author": "John Smith",
          "body": "Thanks, Jane!",
          "created_at": "2024-01-15T11:00:00Z",
          "parent_id": "1"
        }
      ]
    }
  ]
}
FieldRequiredDescription
urlYesPage URL for the thread.
titleNoThread title (shown in dashboard).
identifierNoStable thread ID. Defaults to url.
comments[].idNoOriginal comment ID (used for parent_id references).
comments[].authorNoDisplay name. Defaults to "Anonymous".
comments[].bodyYesComment text (HTML allowed).
comments[].created_atNoISO 8601 timestamp. Defaults to now.
comments[].parent_idNoID of parent comment for replies. null for top-level.
comments[].statusNo"approved", "pending", or "spam". Defaults to "approved".

Important notes

  • File size limit: 10 MB per upload. For very large exports, consider splitting by thread.
  • Duplicate prevention: If a thread with the same identifier already exists, new comments are added to it rather than creating a duplicate.
  • Reply threading: Parent-child relationships are preserved. Comments reference each other by their original IDs.
  • Imported comments appear as guest comments with the original author name displayed.
  • Timestamps: Original comment dates are preserved so your conversations maintain their chronological order.

Exporting comments

Download all comments from a site for backups, analysis, or migration to another platform.

How to export

  1. Go to My Sites in your dashboard and click on the site you want to export.
  2. Click the Export button in the top-right corner.
  3. Choose your format: JSON or CSV.
  4. The file will download automatically.

JSON format

The JSON export uses the same format as the JSON import, making round-trip migration easy. It includes all threads and comments with their metadata.

{
  "exported_at": "2026-04-01T12:00:00Z",
  "site_name": "My Blog",
  "threads": [
    {
      "url": "https://example.com/post",
      "title": "My Post",
      "identifier": "my-post",
      "comments": [
        {
          "id": "abc-123",
          "author": "Jane Doe",
          "body": "Great article!",
          "created_at": "2024-01-15T10:30:00Z",
          "parent_id": null,
          "status": "approved"
        }
      ]
    }
  ]
}

The JSON file can be re-imported into another EchoThread site using the JSON import feature.

CSV format

The CSV export provides a flat spreadsheet with one row per comment. Ideal for analysis in Excel, Google Sheets, or data tools.

ColumnDescription
thread_urlPage URL of the thread.
thread_titleThread title.
comment_idUnique comment ID.
parent_idParent comment ID for replies (empty for top-level).
authorAuthor display name.
bodyComment text.
statusComment status (approved, pending, rejected, spam).
reactions_likeNumber of "like" reactions.
reactions_loveNumber of "love" reactions.
reactions_hahaNumber of "haha" reactions.
reactions_angryNumber of "angry" reactions.
created_atISO 8601 timestamp when the comment was posted.

Troubleshooting

Widget doesn't appear

  • Check that the data-api-key matches the key in your dashboard.
  • Make sure the widget script URL is correct: https://cdn.echothread.io/widget.js
  • Verify your domain is registered in your site settings. The API key is scoped to your domain.
  • Open your browser's developer console and look for error messages.

Comments not showing up

  • If auto-approve is off, new comments stay in "pending" until you approve them in the dashboard.
  • Check the moderation queue for pending or spam-flagged comments.

CORS errors

  • The domain in your site settings must match the domain where the widget is embedded.
  • Include the protocol: example.com, not http://example.com.
  • If testing locally, register localhost as your domain.

Wrong thread / duplicate threads

  • Use data-identifier to tie a thread to a stable ID (e.g., a post slug). Without it, threads default to the page URL, which can cause duplicates if URLs change.
  • Use data-page-url to set the canonical URL if your pages are accessible via multiple URLs.

FAQ

Is EchoThread free?

Yes. EchoThread is completely free during the beta period. No credit card required.

Does EchoThread use cookies?

No. EchoThread does not set any cookies. Authentication tokens are stored in memory during the session only.

Does EchoThread track my visitors?

No. There are no analytics, no ads, and no third-party tracking scripts. We collect only the data needed to display and moderate comments.

How big is the widget?

Under 15 KB gzipped. Zero dependencies. It loads asynchronously and won't block your page rendering.

Can I export my data?

Yes. You can export all comments from any site as JSON or CSV from your site settings page. The JSON export uses the same format as the import, so you can easily migrate between sites. See the Exporting comments section above.

What happens after beta?

We plan to introduce paid plans for high-volume sites. A generous free tier will always be available.

Can guests comment without signing in?

Currently, commenters must sign in with Google. This reduces spam and gives moderators accountability. Guest commenting may be added in the future.

Support

Need help? Sign in to your dashboard and use the Feedback form to reach us directly.