# Substack Embed — React

> How to add a Substack subscribe form or feed widget to a React app. Two approaches: global script loading and a self-contained component with useEffect.

Source: https://supascribe.com/examples/react

---
When you click **Copy embed code** in your [Supascribe dashboard](https://supascribe.com), you get a snippet with your embed ID and script URL already filled in.

There are two ways to set it up in React:

## Method A: Global script in index.html (recommended)

Load the script once in `public/index.html` — it only needs to appear once, regardless of how many embeds you use:

```html
<!-- public/index.html -->
<body>
  <div id="root"></div>
  <script src="https://js.supascribe.com/v1/loader/example.js" async></script>
</body>
```

With the script loaded globally, the component is a plain div wrapper — no browser APIs, no side effects:

```tsx
// components/SupascribeEmbed.tsx
interface SupascribeEmbedProps {
  embedId: string;
  type: "subscribe" | "feed";
}

export default function SupascribeEmbed({ embedId, type }: SupascribeEmbedProps) {
  if (type === "feed") {
    return <div data-supascribe-embed-id={embedId} data-supascribe-feed />;
  }
  return <div data-supascribe-embed-id={embedId} data-supascribe-subscribe />;
}
```

Use it anywhere:

```tsx
// App.tsx
import SupascribeEmbed from "./components/SupascribeEmbed";

export default function App() {
  return (
    <main>
      <section>
        <h2>Get the newsletter</h2>
        
      </section>

      <section>
        <h2>Latest posts</h2>
        
      </section>
    </main>
  );
}
```

## Method B: Self-contained component with useEffect

If you can't edit `index.html` (e.g. you're working within a larger app), load the script from the component itself. The component guards against loading the script more than once — safe to use multiple times on the same page:

```tsx
// components/SupascribeEmbed.tsx
import { useEffect } from "react";

interface SupascribeEmbedProps {
  embedId: string;
  type: "subscribe" | "feed";
}

export default function SupascribeEmbed({ embedId, type }: SupascribeEmbedProps) {
  useEffect(() => {
    const scriptSrc = "https://js.supascribe.com/v1/loader/example.js";
    if (document.querySelector(`script[src="${scriptSrc}"]`)) return;

    const script = document.createElement("script");
    script.src = scriptSrc;
    script.async = true;
    document.body.appendChild(script);
  }, []);

  if (type === "feed") {
    return <div data-supascribe-embed-id={embedId} data-supascribe-feed />;
  }
  return <div data-supascribe-embed-id={embedId} data-supascribe-subscribe />;
}
```

Usage is the same:

```tsx
// App.tsx
import SupascribeEmbed from "./components/SupascribeEmbed";

export default function App() {
  return (
    <main>
      
      
    </main>
  );
}
```

## Alternative: Load the script in a Footer component

If you have a shared Footer component that mounts once per page, you can load the script there instead of `index.html`:

```tsx
// components/Footer.tsx
import { useEffect } from "react";

export default function Footer() {
  useEffect(() => {
    const script = document.createElement("script");
    script.src = "https://js.supascribe.com/v1/loader/example.js";
    script.async = true;
    document.body.appendChild(script);
  }, []);

  return (
    <footer>
      {/* footer content */}
    </footer>
  );
}
```

Then use the embed div directly in any component — no component wrapper needed:

```tsx
// components/NewsletterSection.tsx
export default function NewsletterSection() {
  return (
    <section>
      <h2>Get the newsletter</h2>
      <div data-supascribe-embed-id="abc123" data-supascribe-subscribe />
    </section>
  );
}
```

## Using Next.js?

The pattern is the same — load the script in `app/layout.tsx` instead. See the Next.js example.

- [Next.js Example](https://supascribe.com/examples/nextjs): App Router setup with layout.tsx.
