← Back to Docs

Embed Script Options

All configuration through data-* attributes. The script loads with async so it does not block page render.

<div id="threadline-comments"></div>
<script src="https://threadline.ink/api/embed"
  data-site-id="YOUR_SITE_ID"
  data-api-url="https://threadline-comments-api.onrender.com"
  async></script>

Attributes Reference

AttributeTypeDescription
data-site-idRequiredstringYour 64-character Site ID (API key) from the dashboard. Required.
data-api-urlRequiredstringComments API base URL (e.g. https://threadline-comments-api.onrender.com). Required when the embed script is loaded from a different origin than the API.
data-page-urlstringStable page URL for the thread. Defaults to the current page URL without query/hash.
data-page-titlestringOverride the page title shown in the dashboard. Defaults to document.title.
data-theme"light" | "dark" | "auto"Force a color scheme. Defaults to "auto" (respects prefers-color-scheme).
data-languagestringISO 639-1 language code. Defaults to browser language. Supports: en, es, fr, de, pt, ja.
data-sort"latest" | "newest" | "oldest"Default comment sort. Latest ranks best comments first. Visitors can change this. Defaults to latest.
data-app-urlstringApp base for config fetches. Use a same-origin path (e.g. /threadline) for CSP-proof first-party installs.
data-auth-urlstringThreadline app origin for login popups. Keep the real Threadline URL even when using first-party rewrites.
data-max-depthnumberMaximum nesting depth for reply threads. Defaults to 6. Set to 1 for flat comments.

Plain HTML

Paste near the bottom of the page. Works on desktop and mobile browsers.

<div id="threadline-comments"></div>
<script src="https://threadline.ink/api/embed"
  data-site-id="YOUR_SITE_ID"
  data-api-url="https://threadline-comments-api.onrender.com"
  async></script>

WordPress

A WordPress plugin is available in the repository at integrations/wordpress. It adds a settings screen, automatic placement, and shortcode support. Follow the plugin README for installation; the manual snippet below is an alternative.

<?php
// Add to your theme's functions.php — loads the async embed on posts/pages.
add_action('wp_footer', function () {
  if (is_single() || is_page()) {
    echo '<script src="https://threadline.ink/api/embed"
      data-site-id="YOUR_SITE_ID"
      data-api-url="https://threadline-comments-api.onrender.com"
      async></script>';
  }
});

// In single.php / page.php (or comments.php), place the mount BEFORE the footer script:
echo '<div id="threadline-comments"></div>';

Ghost

Inject the script via Settings → Code Injection → Site Footer, and put the container in post.hbs.

{{!-- Mount in post template; script can live in Site Footer --}}
<div id="threadline-comments"></div>
<script
  src="https://threadline.ink/api/embed"
  data-site-id="YOUR_SITE_ID"
  data-api-url="https://threadline-comments-api.onrender.com"
  async></script>

Astro

Use a client-side .astro component so the loader runs after HTML is sent.

---
// src/components/ThreadlineComments.astro
---
<div id="threadline-comments"></div>

<script>
  // Runs client-side only — async so it does not block page render
  const script = document.createElement('script');
  script.src = 'https://threadline.ink/api/embed';
  script.async = true;
  script.dataset.siteId = 'YOUR_SITE_ID';
  script.dataset.apiUrl = 'https://threadline-comments-api.onrender.com';
  document.body.appendChild(script);
</script>

<!-- In your layout or post page: -->
<!-- import ThreadlineComments from '../components/ThreadlineComments.astro'; -->
<!-- <ThreadlineComments /> -->

Next.js Example

'use client';
import Script from 'next/script';

export default function ThreadlineComments() {
  return (
    <>
      <div id="threadline-comments" />
      <Script
        src="https://threadline.ink/api/embed"
        data-site-id="YOUR_SITE_ID"
        data-api-url="https://threadline-comments-api.onrender.com"
        strategy="afterInteractive"
      />
    </>
  );
}

React & Next.js integration guide

Prefer a small client component that injects the embed script once. Use env vars for site ID and API URL.

Environment variables

# .env.local
NEXT_PUBLIC_THREADLINE_SITE_ID=your_64_char_site_id
NEXT_PUBLIC_THREADLINE_API_URL=https://threadline-comments-api.onrender.com

React (createElement + cleanup)

Creates the script with data-site-id / data-api-url, and clears window.__threadline__ on unmount so remounts can re-init.

'use client';
import { useEffect, useRef } from 'react';

export default function ThreadlineComments() {
  const mounted = useRef(false);

  useEffect(() => {
    if (mounted.current) return; // prevent double-mount in Strict Mode
    mounted.current = true;

    const script = document.createElement('script');
    script.src = 'https://threadline.ink/api/embed';
    script.async = true;
    script.dataset.siteId = process.env.NEXT_PUBLIC_THREADLINE_SITE_ID!;
    script.dataset.apiUrl = process.env.NEXT_PUBLIC_THREADLINE_API_URL!;
    document.body.appendChild(script);

    return () => {
      document.body.removeChild(script);
      // Allow widget re-init on remount
      delete (window as any).__threadline__;
    };
  }, []);

  return <div id="threadline-comments" />;
}

Next.js (next/script)

Use strategy="afterInteractive" so the widget loads after hydration without blocking first paint.

'use client';
import Script from 'next/script';

export default function ThreadlineComments() {
  return (
    <>
      <Script
        src="https://threadline.ink/api/embed"
        data-site-id={process.env.NEXT_PUBLIC_THREADLINE_SITE_ID}
        data-api-url={process.env.NEXT_PUBLIC_THREADLINE_API_URL}
        strategy="afterInteractive"
      />
      <div id="threadline-comments" />
    </>
  );
}

Tips

Static React snippet (hardcoded IDs)
'use client';
import { useEffect } from 'react';

export default function ThreadlineComments() {
  useEffect(() => {
    // Idempotent: don't inject a second copy if the bundle is already on the page.
    if (document.querySelector('script[data-tl-embed="1"]')) {
      document.dispatchEvent(new Event('threadline:remount'));
      return;
    }
    const script = document.createElement('script');
    script.src = 'https://threadline.ink/api/embed';
    script.async = true;
    script.dataset.tlEmbed = '1';
    script.dataset.siteId = 'YOUR_SITE_ID';
    script.dataset.apiUrl = 'https://threadline-comments-api.onrender.com';
    document.body.appendChild(script);
  }, []);

  return <div id="threadline-comments" />;
}

Comment counts outside the widget

Show a live count beside article links in your homepage, category pages, cards, or navigation without loading the full comment widget. Add the count attribute to each link and load the count script once per page.

<a href="https://your-site.example/article" data-threadline-count>
  <span class="threadline-count-value">0</span> Comments
</a>
<script src="https://threadline.ink/api/count.js" data-site-id="YOUR_SITE_ID" data-api-url="https://threadline-comments-api.onrender.com" async></script>

The link's href identifies the article URL. Use data-threadline-url if the comment thread uses a canonical URL different from the link destination. Wrap the number in threadline-count-value to preserve the surrounding label and icons.

Caching & CORS