JavaScript Embed

PostTTS for Any Website

Add natural-sounding audio to your site with a single script tag. Works with any CMS, framework, or static site — no build step, no dependencies.

< 10KB gzipped · Zero dependencies · Works with any CMS

Quick Start

1

Sign up and get your site ID

Create a free account and grab your site ID from the Integration page. The free plan includes 10 articles/month.

2

Mark your article content

Add the data-posttts attribute to any element wrapping your article text — usually the <article> tag.

3

Add the script tag to your <head>

Drop one <script> tag with your site ID. It loads asynchronously and won't block rendering.

Live Demo

This is exactly what your visitors will see after embedding.

P

Your Blog

April 5, 2026

How to Add Audio to Your Website

Listen to the reading
0:00

Audio is the fastest-growing content format on the web. Adding a play button to your articles gives readers the choice to listen while they commute, exercise, or multitask — and it takes less than five minutes to set up.

How It Works

Loads asynchronously

Script uses defer, so it never blocks page rendering or interaction.

Scans the DOM

Finds elements with data-posttts markers (or your custom selector).

Fetches audio URL

Looks up the pre-generated audio for that page from the PostTTS API.

Injects the player

Renders a CSS-isolated, mobile-friendly player next to your content.

Integration Patterns

Drop-in examples for the most common stacks.

<!-- 1. Add the script to your <head> -->
<script
  src="https://posttts.com/player.js"
  data-site="YOUR_SITE_ID"
  defer
></script>

<!-- 2. Mark your article content -->
<article data-posttts>
  <h1>Your article title</h1>
  <p>Your article content...</p>
</article>
<!-- In header.php, before </head> -->
<script
  src="https://posttts.com/player.js"
  data-site="<?php echo esc_attr( get_option('posttts_site_id') ); ?>"
  defer
></script>

<!-- In single.php, wrap the post content -->
<article data-posttts <?php post_class(); ?>>
  <?php the_title('<h1>', '</h1>'); ?>
  <?php the_content(); ?>
</article>
// pages/_document.tsx (or app/layout.tsx)
import Script from 'next/script';

export default function Document() {
  return (
    <html>
      <head>
        <Script
          src="https://posttts.com/player.js"
          data-site="YOUR_SITE_ID"
          strategy="afterInteractive"
        />
      </head>
      <body>{/* ... */}</body>
    </html>
  );
}

// In your post component
export function Post({ title, body }) {
  return (
    <article data-posttts>
      <h1>{title}</h1>
      <div dangerouslySetInnerHTML={{ __html: body }} />
    </article>
  );
}
<!-- Hugo: layouts/partials/head.html -->
<script src="https://posttts.com/player.js" data-site="YOUR_SITE_ID" defer></script>

<!-- Hugo: layouts/_default/single.html -->
<article data-posttts>
  <h1>{{ .Title }}</h1>
  {{ .Content }}
</article>

<!-- Jekyll: _layouts/post.html -->
<article data-posttts>
  <h1>{{ page.title }}</h1>
  {{ content }}
</article>

<!-- Ghost: default.hbs (in <head>) -->
<script src="https://posttts.com/player.js" data-site="YOUR_SITE_ID" defer></script>
<!-- Ghost: post.hbs -->
<article data-posttts>{{content}}</article>

Configuration Reference

Attribute Type Default Description
data-site string Required. Your PostTTS site identifier. Get it from your dashboard.
data-selector string [data-posttts] CSS selector for content elements to convert to audio.
data-position enum before Where to inject the player: before, after, start, or end of content.
data-voice enum woman Default voice. Readers can change it via the player dropdown.
data-theme enum light Player visual theme: light, dark, or minimal.
data-speed number 1 Default playback rate. Supports 0.75, 1, 1.25, 1.5, 2.
data-auto boolean false Enable semantic auto-detection fallback when no markers are present.

Content Detection

Four ways to tell the script where your article content lives.

Opt-in markers (recommended)

Add data-posttts to any element wrapping your article. Most robust and explicit.

<article data-posttts>...</article>

Manual player slot

Control exactly where the player appears by adding a data-posttts-player element inside or next to your content.

<article data-posttts>
  <div data-posttts-player></div>
  <p>Article text...</p>
</article>

CSS selector override

If you can't modify templates, point the script at an existing class or element on your site.

<script src="https://posttts.com/player.js"
  data-site="YOUR_SITE_ID"
  data-selector=".entry-content"></script>

Auto-detect fallback

When opt-in markers are missing, fall back to semantic HTML (<article>[itemprop="articleBody"]<main>). Off by default.

<script src="https://posttts.com/player.js"
  data-site="YOUR_SITE_ID"
  data-auto="true"></script>

Skip unwanted children

Add data-posttts-skip to any child you want excluded from the audio — sidebars, image captions, share buttons, etc.

<article data-posttts>
  <p>This is read aloud.</p>
  <aside data-posttts-skip>This is skipped.</aside>
</article>

Frequently Asked Questions

No. The script is under 10KB gzipped, loads with defer (non-blocking), and the audio file uses preload="metadata" — so the actual m4a is only downloaded when a reader hits play. Audio is served from a global CDN.

Use data-theme="light|dark|minimal" on the script tag for the built-in themes. All player classes are prefixed .posttts-* so you can override any style in your own CSS without conflicts.

Yes. For frameworks that don't do a full page reload on route change, call window.PostTTS.scan() after each route transition to re-mount players on the new content. In Next.js, use next/script with strategy="afterInteractive".

The script fails gracefully. It logs a warning to the console and does nothing — your page renders normally with no broken UI. Once the API is available again, players mount on the next page load.

Yes. Every element matching your selector gets its own player. This is great for magazine-style layouts or pages that feature multiple articles.

Minimal. All player classes use a .posttts-* prefix and the player reads its fonts/colors from CSS custom properties scoped to its root. No global resets are applied.

Ready to add audio to your site?

Create a free account and get your site ID in under a minute.

Create Free Account

Free plan includes 10 articles/month · No credit card required