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.
When you click Copy embed code in your Supascribe dashboard, 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:
<!-- 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:
// 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:
// App.tsx
import SupascribeEmbed from "./components/SupascribeEmbed";
export default function App() {
return (
<main>
<section>
<h2>Get the newsletter</h2>
<SupascribeEmbed embedId="abc123" type="subscribe" />
</section>
<section>
<h2>Latest posts</h2>
<SupascribeEmbed embedId="abc123" type="feed" />
</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:
// 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:
// App.tsx
import SupascribeEmbed from "./components/SupascribeEmbed";
export default function App() {
return (
<main>
<SupascribeEmbed embedId="abc123" type="subscribe" />
<SupascribeEmbed embedId="abc123" type="feed" />
</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:
// 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:
// 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.
App Router setup with layout.tsx.
Supascribe
Ready to grow your Substack?
Add a subscribe embed or landing page to any website in minutes. Free to start.
Start for free →