EchoThread Comment Widget Documentation
Use these EchoThread docs to install a privacy-first comment widget on any website in under a minute. Start with the copy-paste embed snippet, then configure thread identifiers, theming, import/export, moderation, and platform setup for Shopify, Wix, Framer, Squarespace, WordPress, Next.js, Hugo, Astro, Ghost, Jekyll, Eleventy, and Gatsby.
Last updated · See the changelog for recent widget updates, or the EchoThread blog for in-depth guides.
Popular setup paths
Quick start
Get EchoThread running on your site in under a minute. No build tools required.
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.
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" async></script>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.
| Attribute | Default | Description |
|---|---|---|
| data-api-key | (required) | Your site API key from the dashboard. |
| data-page-url | window.location.href | Canonical URL of the page. Used to group comments into threads. |
| data-identifier | page URL | Stable unique ID for the comment thread. Use a slug or database ID so threads survive URL changes. |
| data-page-title | document.title | Title stored with the thread. Shown in the dashboard. |
| data-lang | auto (browser) | Widget UI language: "en", "ko", or "it". Omit to follow each visitor's browser language (falling back to English). Set it to pin one language for every visitor. |
| data-theme | auto (OS) | "light", "dark", or any hex color (e.g. "#FAF7F2") for a custom background. Omit to follow visitor's OS preference. |
| data-accent-color | #4f46e5 | Custom accent color for the send button and footer link. |
| data-font | system | Typography preset: "system", "sans", "serif", "mono", or "rounded". data-font-family overrides this. |
| data-font-family | system stack | Override the widget font. Any CSS font-family value, e.g. "'Inter', sans-serif". Use "inherit" to pick up your site's font. |
| data-font-size | 14px | Override the base font size. Any CSS length, e.g. "15px" or "0.95rem". |
| data-radius | 8px | Border radius for the widget container and cards. Any CSS length, e.g. "0" for sharp corners or "16px" for softer cards. |
| data-mobile-gap | 6px | Row gap between avatar and composer on mobile (≤480px). Tighten with "0" or "4px" for narrow sidebars, or widen for more breathing room. |
| data-mobile-avatar-size | 28px | Avatar size on mobile (≤480px). Defaults to 28px so the composer card uses more horizontal space; "24px" gives the editor even more room in very narrow columns. |
| data-mobile-min-width | auto | Minimum widget width on mobile (≤480px). Set to "100%" to fill the host column edge-to-edge. |
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" async></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-color-accent: #6366f1;
--et-radius: 12px;
--et-font: 'Inter', system-ui, sans-serif;
}Match your site's typography
By default EchoThread uses a clean system font stack so it looks consistent across browsers. Pass data-font-family to use a specific font, or data-font-family="inherit" to pick up the font your site already uses. You can also tune the base size with data-font-size and the corner radius with data-radius.
<!-- Inherit your site's font, bump the base size, soften the corners -->
<div id="echothread"
data-api-key="YOUR_API_KEY"
data-font-family="inherit"
data-font-size="15px"
data-radius="12px"></div>
<!-- Or pin a specific font -->
<div id="echothread"
data-api-key="YOUR_API_KEY"
data-font-family="'Inter', system-ui, sans-serif"></div>The widget defends its own typography against host-page CSS resets, so these attributes are the supported way to change fonts — host-side !important overrides on .et-widget descendants won't take effect.
CSS custom properties
| Variable | Default | Description |
|---|---|---|
| --et-color-accent | #4f46e5 | Primary accent color (send button, links, active states). |
| --et-color-accent-hover | #4338ca | Accent color used on hover. |
| --et-color-bg | #ffffff | Widget background. Derived automatically from data-theme when set. |
| --et-color-surface | #f8fafc | Surface color for comment bubbles, inputs, and chips. |
| --et-color-border | #e2e8f0 | Border color for the container, inputs, and cards. |
| --et-color-text | #1e293b | Primary text color. |
| --et-color-muted | #64748b | Muted text color (timestamps, secondary actions). |
| --et-radius | 8px | Border radius for the container and cards. |
| --et-font | system stack | Font family for all widget text. |
| --et-font-size | 14px | Base font size for the widget. |
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 by default (Sad and Fire are also available per site). 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.
Link previews
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 & spoiler tags
Comments support four formatting primitives via toolbar buttons, keyboard shortcuts, or inline markdown:
**text**Ctrl + B_text_Ctrl + I~~text~~Ctrl + Shift + S||text||Ctrl + Shift + Xaria-label announces the current state. WCAG 2.1 AA aligned — useful for movie, TV, gaming, and book threads.Sorting
Readers can sort comments by newest, oldest, most liked, or most replied. The sort preference persists for the session.
Languages & localization
The widget interface — buttons, labels, prompts, relative timestamps, and dates — is fully localized in English, Korean (한국어), and Italian (italiano). By default each visitor sees the widget in their own browser language when it's supported, falling back to English otherwise, so a Korean reader and an English reader on the same page each get their own language with zero configuration.
To pin the widget to a single language for every visitor, set data-lang="ko" (or "en" / "it") on the container. Dates and "5 minutes ago"–style timestamps are formatted with the browser's native Intl APIs, so they read naturally in each language. Comment content is never translated — only the widget's own interface.
Accessibility
The widget is built with WCAG 2.1 Level AA success criteria in mind: visible focus rings on buttons, inputs, and the compose editor; aria-labels on the compose toolbar, image-remove, and lightbox-close controls; a focus-trapped image lightbox with Escape-to-close; and broad prefers-reduced-motion coverage across animated affordances. No configuration required.
Authentication
How readers post is configurable per site. You can require an account or open commenting to guests — either way, the Siftfy ML spam filter screens new comments and gives moderators a clean queue.
Guest commenting
Turn on Allow guest comments in a site's moderation settings and readers can post with just a display name — no account required. Every guest comment is always scored by Siftfy before it can appear, even when auto-approve is on, so you get frictionless commenting without the spam. Guest commenting is off by default; enabling it is a one-click, per-site choice.
Commenter sign-in
Visitors can also sign in with Google or GitHub 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 scores every incoming comment with a machine-learning spam classifier. High-confidence spam is kept out of the public thread automatically; borderline comments land in your spam queue, tagged with the signals that flagged them — link density, ALL-CAPS, repeated characters, promo keywords, and drive-by links — so you can review at a glance. Behind the scenes, each comment's spam probability is scored by the Siftfy classification API: very high scores auto-block, borderline scores go to your review queue, and the rest pass through.
Notifications
Get dashboard notifications when new comments arrive or spam is detected. The notification bell polls for unread counts 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.
| Setting | Description |
|---|---|
| Site name | Display name for your site (shown in the dashboard only). |
| Domain | The domain where the widget is embedded. Used for CORS validation. |
| Description | Optional description for your own reference. |
| Auto-approve | When on, new comments are immediately visible. When off, they require manual approval. |
| Spam filter | When on, likely spam is automatically flagged and sent to the spam queue. |
| Allow voting | Show or hide emoji reactions (Like, Love, Haha, Angry) 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 — from static site generators to hosted no-code builders like Shopify, Wix, Framer, and Squarespace. Static site generators are especially popular with EchoThread since they have no built-in backend for comments, and no-code builders pair well with it because their native comment tools are limited. For a deeper comparison, see our guide to the best commenting system for static sites. 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 ML spam filtering. The easiest way is our official plugin — no code required. If you want more control, you can also add EchoThread by hand in three ways.
Recommended — Official WordPress plugin (no code)
Install ThreadBridge Comments for EchoThread from the WordPress.org plugin directory — or search EchoThread under Plugins → Add New in your dashboard. Activate it, open Settings → ThreadBridge Comments for EchoThread, paste your site shortname and API key, and pick where comments appear: replace your theme's comments, append below the content, or drop them anywhere with the [echothread] shortcode. No theme edits, no database tables.
Prefer to wire it up by hand? Three more ways:
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' );
}
});For React frameworks and static site generators, follow the dedicated guide for your platform. Each guide walks through the reusable component or template include, identifier choices, conditional rendering, and any framework-specific gotchas.
Next.js / React
Reusable React component with App Router and Pages Router setup.
Read the full Next.js / React guideHugo
Partial template with per-post identifiers and multilingual support.
Read the full Hugo guideJekyll
Liquid include for Jekyll blogs and GitHub Pages.
Read the full Jekyll guideAstro
Astro component with content collections support.
Read the full Astro guideEleventy (11ty)
Nunjucks, Liquid, or Handlebars include with per-collection toggles.
Read the full Eleventy (11ty) guideGatsby
React component that loads after Gatsby hydrates.
Read the full Gatsby guide
Hosted website builders don't expose theme files the way a static site generator does, but each one has a place for custom HTML — so the same embed snippet works with no build step. The guides below cover the platform-specific placement; for the full walkthrough, follow the linked companion guide for each platform.
Framer
Framer's Embed element accepts raw HTML, so EchoThread drops in without code. To add comments to every blog post at once, edit the CMS Collection page rather than an individual page.
- Open the CMS Collection page (or a static page) and drag an Embed element below your content.
- Set the embed type to HTML and paste the Quick start snippet.
- For blog posts, use the code editor's + menu to bind the post slug to
data-identifierso each post gets its own thread. - Set the element width to Fill and height to Auto so the thread can grow, then publish.
Wix
Wix lets you embed custom HTML on a blog post layout with its Embed HTML element. Because Wix renders embeds inside an isolated frame, set an explicit data-identifier per post so threads stay separate.
- Register your Wix domain in your EchoThread dashboard so the API key is authorized for it.
- In the Wix Editor, open the Blog Post layout and choose Add Elements → Embed Code → Embed HTML.
- Place the element below the post body, click Enter Code, and paste the Quick start snippet with a unique
data-identifier. - Give the element a generous height so the thread isn't clipped, then publish.
Shopify
Shopify blog posts are rendered by your theme's article template. Add EchoThread by editing that template in the theme code editor — no app required.
- From the Shopify admin, go to Online Store → Themes, then … → Edit code. Duplicate the theme first so you can test safely.
- Open
sections/main-article.liquid(ortemplates/article.liquidon older themes). - Paste the Quick start snippet just after
{{ article.content }}, usingdata-identifier="{{ article.id }}"so each post keeps its own thread. - Optionally remove the native
{% if blog.comments_enabled? %}block, then save and preview.
Squarespace
Squarespace supports EchoThread through a Code Block — a no-code installation that takes a few minutes.
- Edit a blog post (or the blog post template) and add a Code Block below the content.
- Paste the Quick start snippet and confirm the block is set to render HTML, not display it as text.
- On Business and Commerce plans you can instead add the widget
<script>once under Settings → Developer Tools → Code Injection → Footer, and keep only the<div id="echothread">container in each post's Code Block.
Ghost
Most Ghost themes ship without comments. EchoThread adds them with no theme edits using Ghost's Code Injection for the script and an HTML card for the container — or, if you maintain your own theme, a one-line template include.
- Register your Ghost site's domain in your EchoThread dashboard so the API key is authorized for it.
- In Ghost Admin, open Settings → Code injection and paste just the widget
<script>from the Quick start snippet into Site Footer so it loads once on every page. - In each post, add an HTML card (type
/html) at the bottom containing only the<div id="echothread" …>container with a uniquedata-identifierso threads stay separate. - Prefer all posts at once? If you edit your theme, add the container to
post.hbsafter{{content}}usingdata-identifier="{{slug}}", then re-upload the theme.
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
- Log in to your Disqus Admin Panel and select the site you want to migrate.
- In the left sidebar, navigate to Community → Export.
- 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.
- 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.
- Download the
.xml.gzfile and extract it to get the raw.xmlfile. On macOS, double-click the file. On Linux, rungunzip 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
- Open your EchoThread dashboard and go to My Sites.
- Click on the site you want to import comments into.
- Click the Import button.
- Select Disqus as the source format.
- Upload the extracted
.xmlfile (max 10 MB — see below if your file is larger). - 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 data | EchoThread mapping | Notes |
|---|---|---|
| Threads (with URL + title) | Thread per page URL | URL 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 + email | Guest comment with display name | Imported as guest comments; email stored if available |
| Timestamps | Original created_at | Chronological order preserved exactly |
| Approved / pending status | Approved / pending status | Unapproved comments go to your moderation queue |
| Spam-flagged comments | Spam queue | Available in moderation dashboard for review |
| Deleted comments | Skipped | Deleted comments are not imported |
| Votes / likes | Not imported | Disqus does not include vote data in the XML export |
| User avatars | Not imported | Guest 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-urlattribute 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}/importwith 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-urlmatches 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.gzfile. Uploading the compressed.gzfile 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: Threads are deduplicated — if a thread with the same URL already exists, comments are added to it instead of creating a duplicate thread. Individual comments are not deduplicated, so re-running the same file will add a second copy of every comment. Import each file only once.
Import from WordPress
If your comments live in WordPress, export them with WordPress's built-in tool and upload the file — no plugin required.
- In your WordPress admin, go to Tools → Export.
- Choose All content (or just Posts) and click Download Export File. WordPress produces a
.xml(WXR) file containing your posts and their comments. - On the EchoThread import page, select WordPress as the source format and upload the
.xmlfile (up to 10 MB). - Comments attach to each page by its post URL, so make sure your embed's
data-page-urlmatches the original post URLs. Approved WordPress comments import as approved; pending and spam comments keep their status.
EchoThread accepts every WordPress export namespace (WXR 1.0, 1.1, and 1.2), so both classic and modern WordPress exports work.
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"
}
]
}
]
}| Field | Required | Description |
|---|---|---|
| url | Yes | Page URL for the thread. |
| title | No | Thread title (shown in dashboard). |
| identifier | No | Stable thread ID. Defaults to url. |
| comments[].id | No | Original comment ID (used for parent_id references). |
| comments[].author | No | Display name. Defaults to "Anonymous". |
| comments[].body | Yes | Comment text (HTML allowed). |
| comments[].created_at | No | ISO 8601 timestamp. Defaults to now. |
| comments[].parent_id | No | ID of parent comment for replies. null for top-level. |
| comments[].status | No | "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: Deduplication applies to threads only. If a thread with the same identifier already exists, comments are added to it rather than creating a duplicate thread — but re-importing a file re-adds its comments, so import each file only once.
- 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.
Still weighing your options before you migrate? See how EchoThread stacks up in the Disqus alternatives roundup, or read a head-to-head comparison: vs Disqus, vs Commento, or vs Hyvor Talk.
Exporting comments
Download all comments from a site for backups, analysis, or migration to another platform.
How to export
- Go to My Sites in your dashboard and click on the site you want to export.
- Click the Export button in the top-right corner.
- Choose your format: JSON or CSV.
- 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.
| Column | Description |
|---|---|
| thread_url | Page URL of the thread. |
| thread_title | Thread title. |
| comment_id | Unique comment ID. |
| parent_id | Parent comment ID for replies (empty for top-level). |
| author | Author display name. |
| body | Comment text. |
| status | Comment status (approved, pending, rejected, spam). |
| reactions_like | Number of "like" reactions. |
| reactions_love | Number of "love" reactions. |
| reactions_haha | Number of "haha" reactions. |
| reactions_angry | Number of "angry" reactions. |
| created_at | ISO 8601 timestamp when the comment was posted. |
Troubleshooting
Widget doesn't appear
- Check that the
data-api-keymatches 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, nothttp://example.com. - If testing locally, register
localhostas your domain.
Wrong thread / duplicate threads
- Use
data-identifierto 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-urlto set the canonical URL if your pages are accessible via multiple URLs.
FAQ
Is EchoThread free?
Yes. The Hobby tier is free for your first site, with no credit card required. It is a permanent free plan; paid plans start at $5/month if you outgrow it.
Does EchoThread use cookies?
No. EchoThread does not set any cookies. When a commenter signs in, their session tokens are kept in your browser's local storage — not in cookies, and never shared with third parties.
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?
Around 37 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.
Will the free tier ever go away?
No. The Hobby tier is a permanent free plan. Paid plans exist for high-volume sites, but a generous free tier will always be available.
Is there a WordPress plugin?
Yes. Install "ThreadBridge Comments for EchoThread" from the WordPress.org plugin directory (or search EchoThread under Plugins → Add New), then paste your site shortname and API key — no code or theme edits. You can replace your theme's comments, append them below the content, or place them with the [echothread] shortcode. Prefer to do it by hand? The WordPress section above covers the embed snippet and theme-template methods too.
Can guests comment without signing in?
Yes, if the site owner enables it. Turn on "Allow guest comments" in a site's moderation settings and readers can post with just a display name — no account required. Every guest comment is screened by the Siftfy ML spam filter first. Owners can also require Google or GitHub sign-in instead. Guest commenting is off by default.
Does the widget support other languages?
Yes. The widget interface is localized in English, Korean, and Italian. By default each visitor sees it in their own browser language, falling back to English — no setup required. You can pin a single language for all visitors with data-lang="ko" (or "en" / "it") on the container. Timestamps and dates are formatted natively per language. Comment content itself is never translated, only the widget's own interface.
Support
Need help? Sign in to your dashboard and use the Feedback form to reach us directly.