> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beyondwords.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Magic Embed

Magic Embed is the quickest way to integrate BeyondWords with any web platform. Add a script to your article template and BeyondWords will automatically ingest content from live pages, generate [audio](/docs-and-guides/content/audio) and/or [video](/docs-and-guides/content/video), and install the [player](/docs-and-guides/distribution/player/player-introduction)—no backend integration required.

Magic Embed is also known as the **client-side integration**. If you're using the [JavaScript SDK](/docs-and-guides/distribution/player/installation/javascript-sdk) directly, the equivalent setting is [`clientSideEnabled`](/docs-and-guides/distribution/player/developer-guides/player-properties#param-client-side-enabled).

<Tip>
  Using WordPress with Elementor or another page builder? The [WordPress plugin](/docs-and-guides/integrations/publishing-platforms/wordpress) can use Magic Embed as an alternative to its default REST API integration. You can also set up other distributions for your audio and video content, or configure Magic Embed via the [Magic Embed API](/api-reference/magic-embed/show).
</Tip>

## How it works

Magic Embed is a **client-side** integration. The script runs in the visitor's browser each time an article page loads, but content ingestion works differently on the first visit versus later ones.

* **First visit**: When an article hasn't been ingested before, the script triggers [content extraction](/docs-and-guides/integrations/content-extraction) from the live page and starts audio/video generation. The player appears once generation is complete.
* **Later visits**: The player loads existing audio/video straight away. BeyondWords periodically re-checks the live page for updates, but not on every visit. If you've edited the article on your website, changes are picked up automatically over time.

If you don't pass an identifier, the page URL (`window.location.href`) is used by default. This works out of the box, but we **recommend passing a `sourceId`**—your CMS article ID—in the embed code wherever you can. Magic Embed will use it as the content's `source_id`, which lets you search for content by source ID in the dashboard, embed the player on other surfaces using the same ID, and take advantage of platform features such as [webhooks](/docs-and-guides/integrations/webhooks) and [syndicated content](/api-reference/content/syndicated) that key off `source_id`.

<Tip>
  URLs can change if an article moves. A `sourceId` tied to your CMS article ID is more stable and consistent across your site, apps, and integrations.
</Tip>

<Info>
  On the first visit, the player won't appear until audio/video generation is complete. If a domain isn't in your allowed domains list, content won't be ingested and the player won't load.
</Info>

<Warning>
  Adding the embed to a site-wide article template means **every** article that gets visited—including older back-catalog articles—will be ingested and generated the first time someone views it. If you only want audio for recent content, [limit which articles get audio](#limit-which-articles-get-audio) so old articles don't trigger generation.
</Warning>

## Install Magic Embed

<Steps>
  <Step title="Enable Magic Embed">
    Go to **Settings** → **Integrations** → **Magic Embed** in your project dashboard and switch the toggle on.
  </Step>

  <Step title="Add allowed domains">
    In the **Allowed domains** field, enter each domain where Magic Embed should work, then click **Add**.

    Include production, staging, preview environments, and any subdomains (e.g., `www.example.com` and `staging.example.com` are separate entries). If a page's domain isn't on this list, BeyondWords won't ingest content from it.
  </Step>

  <Step title="Copy the embed code">
    In the **Embed code** dropdown, select what type of content you want to embed: <Tooltip tip="The audio version of your full article, as opposed to your script." headline="Audio article">audio article</Tooltip>, <Tooltip tip="The audio version of your script, as opposed to your full article." headline="Audio summary">audio summary</Tooltip>, <Tooltip tip="The video version of your full article, as opposed to your script." headline="Video article">video article</Tooltip>, or <Tooltip tip="The video version of your script, as opposed to your full article." headline="Video summary">video summary</Tooltip>.

    Click the copy icon alongside the embed code—you'll need this in step 6.

    Then, click **Save changes**.
  </Step>

  <Step title="Set request headers (optional)">
    For paywalled or protected content, configure authentication headers so BeyondWords can access your pages. These are project-level [extraction settings](/docs-and-guides/integrations/content-extraction), shared with the RSS Feed Importer and URL imports.

    1. Go to **Settings → Extraction** in your project dashboard
    2. Add a **Header name** and **Header value**
    3. Click **+** to add additional headers if needed
    4. Click **Save changes**

    <Info>
      Requests will be made with `User-Agent: BeyondWords Importer`
    </Info>
  </Step>

  <Step title="Enable static IP (optional)">
    If your website requires IP allowlisting, enable static IP in your [extraction settings](/docs-and-guides/integrations/content-extraction).

    1. Go to **Settings → Extraction** in your project dashboard
    2. Switch the **Static IP** toggle on
    3. Allowlist the displayed IP addresses within your firewall, CDN, or server configuration
    4. Click **Save changes**

    <Info>
      Requests will be sent from `20.234.8.180`
    </Info>
  </Step>

  <Step title="Add the embed code to your website">
    Paste the script into your article template where you want the player to appear. The player is inserted immediately after the script tag.

    A typical embed code looks like this. Pass your CMS article ID as `sourceId` if your template has access to it:

    ```html theme={null}
    <script async defer
      src="https://proxy.beyondwords.io/npm/@beyondwords/player@latest/dist/umd.js"
      onload="new BeyondWords.Player({
        target: this,
        projectId: YOUR_PROJECT_ID,
        sourceId: YOUR_ARTICLE_ID,
        clientSideEnabled: true,
      })">
    </script>
    ```

    Copy the base snippet from your dashboard—it will include your project ID and the correct settings for your chosen content type—then add `sourceId` in your article template.
  </Step>
</Steps>

## Limit which articles get audio

Because Magic Embed ingests content on the first visit to a page, placing the embed in your global article template means old articles will start generating audio as soon as they get traffic. If you only want audio for recent articles, gate the embed so it only runs for content published on or after a cutoff date.

<Tabs>
  <Tab title="Template-level (recommended)">
    Use your CMS or templating engine to only output the embed for recent articles, comparing the article's publish date to a cutoff when the page is rendered. Old articles never load the script, so they're never ingested.

    The exact syntax depends on your platform—the example below is pseudo-template code:

    ```html theme={null}
    <!-- Only render the BeyondWords embed for articles published on or after the cutoff -->
    {{ if article.published_at >= "2026-06-01" }}
      <script async defer
        src="https://proxy.beyondwords.io/npm/@beyondwords/player@latest/dist/umd.js"
        onload="new BeyondWords.Player({
          target: this,
          projectId: YOUR_PROJECT_ID,
          sourceId: YOUR_ARTICLE_ID,
          clientSideEnabled: true,
        })">
      </script>
    {{ endif }}
    ```
  </Tab>

  <Tab title="Client-side date check">
    If template-level logic isn't available, gate loading in the browser. Read the article's published-time meta tag and only inject the player script when the article is newer than your cutoff:

    ```html theme={null}
    <meta property="article:published_time" content="2026-06-01T00:00:00Z" />

    <script>
      (function () {
        var cutoff = new Date('2026-06-01');
        var meta = document.querySelector('meta[property="article:published_time"]');
        if (!meta) return;
        if (new Date(meta.getAttribute('content')) < cutoff) return;

        var current = document.currentScript;
        var player = document.createElement('script');
        player.async = true;
        player.defer = true;
        player.src = 'https://proxy.beyondwords.io/npm/@beyondwords/player@latest/dist/umd.js';
        player.onload = function () {
          new BeyondWords.Player({
            target: player,
            projectId: YOUR_PROJECT_ID,
            sourceId: YOUR_ARTICLE_ID,
            clientSideEnabled: true,
          });
        };
        current.parentNode.insertBefore(player, current);
      })();
    </script>
    ```
  </Tab>
</Tabs>

<Note>
  Replace the cutoff date and `YOUR_PROJECT_ID` / `YOUR_ARTICLE_ID` with your own values. The `article:published_time` meta tag is just an example—most CMSes already emit it, but you can target whatever publish-date field your template exposes. This is different from [`data-beyondwords-publish-date`](/docs-and-guides/integrations/data-attributes), which only labels the publish date of content that's already generated; it does not prevent generation.
</Note>

## Content filters

Magic Embed uses [automatic extraction](/docs-and-guides/integrations/content-extraction#automatic-extraction) by default, which identifies editorial content on your page and ignores most non-article elements. In practice, most publishers also set up **content filters** to fine-tune what gets included or excluded—for example:

* **Exclude** newsletter sign-ups, related-article blocks, social embeds, or author bios that shouldn't be read aloud
* **Include** only a specific container when automatic extraction picks up more than you need

Filters are applied alongside automatic extraction, so you don't need to switch extraction modes to use them. Configure them in **Settings → Extraction → Filters** in your project dashboard.

See [content filters](/docs-and-guides/integrations/content-extraction#filters) for how to create include and exclude rules, and the available [filter types](/docs-and-guides/integrations/content-extraction#filter-types) (class, ID, XPath, text, and more).

<Tip>
  If you need precise control over metadata such as title, author, or publish date, use [data attributes](/docs-and-guides/integrations/data-attributes) alongside filters.
</Tip>

## Fine-tuning your integration

Beyond filters, you can further refine how Magic Embed processes your pages:

* [Content extraction](/docs-and-guides/integrations/content-extraction)—extraction modes and advanced filter configuration
* [Data attributes](/docs-and-guides/integrations/data-attributes)—explicitly define title, author, publish date, and other fields in your HTML
* [Player settings](/docs-and-guides/distribution/player/player-settings)—customize player appearance and behavior
* [Segment detection](/docs-and-guides/distribution/player/developer-guides/segment-detection)—Magic Embed automatically retrieves segment markers from your page for text highlighting

You can also distribute generated content beyond the player using [playlists](/docs-and-guides/distribution/playlists), [podcast feeds](/docs-and-guides/distribution/podcast-feeds), and [downloads](/docs-and-guides/distribution/download).

## FAQs

<AccordionGroup>
  <Accordion title="What happens if I update my live article?">
    BeyondWords periodically re-checks your live article for changes and regenerates audio/video when it detects an update—it doesn't re-ingest the page on every visit. This happens automatically unless you've disabled automatic updates in the Editor (see below).
  </Accordion>

  <Accordion title="What happens if I make changes in the Editor?">
    If you make changes to content generated via Magic Embed in the Editor, the content will be regenerated accordingly. However, any future changes to your live article may trigger regeneration, which will overwrite changes you made in the Editor.

    To preserve your edits, go to the **Info** tab in the Editor and disable **API updates**. This stops automatic sync from your website—future changes on your live article will no longer be picked up.

    If you want article updates to continue syncing automatically, use [content filters](/docs-and-guides/integrations/content-extraction#filters) to control what gets included or excluded from audio generation instead of editing articles manually in the Editor.
  </Accordion>

  <Accordion title="Will the player appear before audio/video is generated?">
    No. The player only appears once content has been generated and is ready to play.
  </Accordion>

  <Accordion title="How does Magic Embed extract content?">
    Magic Embed uses [automatic extraction](/docs-and-guides/integrations/content-extraction#automatic-extraction) by default. If the extracted content is incorrect, use [content filters](/docs-and-guides/integrations/content-extraction#filters) or [data attributes](/docs-and-guides/integrations/data-attributes) to control what BeyondWords includes or excludes.
  </Accordion>

  <Accordion title="How do I stop old articles from generating audio?">
    This usually happens when the embed is added to a site-wide article template, so any visit to an older article triggers generation on the first view. To only generate audio for recent content, gate the embed by publish date—either at the template level or with a client-side date check. See [limit which articles get audio](#limit-which-articles-get-audio).
  </Accordion>
</AccordionGroup>

## Getting help

If you encounter issues or have questions, [contact support](/docs-and-guides/support/get-support).
