ReactionSaaS
Documentation

Next.js installation

ReactifySDK · Next.js

ReactifySDK is client-only. Keep Script and reactify-thread inside a "use client" boundary; server components can import that boundary as a child.

Why WordPress pops up but a bare Next embed opens the hosted record page

The embed only opens the in-page recorder when window.reactifyWprtEmbed.apiKey (or reactifyShopifyEmbed.apiKey) is set—exactly what the WordPress plugin does. Without it, "React To This" / "Stitch this" are target="_blank" links to https://api.reactionsaas.com/reactify/record.

1. Publishable API key

.env.local
# .env.local
NEXT_PUBLIC_REACTIFY_API_KEY=rsk_live_your_publishable_key

2. App Router (recommended)

Bootstrap the embed config in useLayoutEffect (and again on script onLoad) so the key is present when CTAs paint. Use a real thread id for beat/stitch modals.

Client embed component
// app/reactify/ThreadEmbed.tsx
"use client";

import { useLayoutEffect } from "react";
import Script from "next/script";

const SRC = "https://reactify-cdn.s3.us-east-2.amazonaws.com/reactify.js?v=1.1.34";
const APP_BASE = "https://api.reactionsaas.com";

declare global {
  interface Window {
    reactifyWprtEmbed?: { base: string; apiKey: string };
    reactifyShopifyEmbed?: { base: string; apiKey: string };
    REACTIFY_EMBED_BASE?: string;
  }
}

function bootstrapReactifyEmbed(apiKey: string) {
  if (typeof window === "undefined") return;
  const cfg = { base: APP_BASE.replace(/\/+$/, ""), apiKey: apiKey.trim() };
  window.reactifyWprtEmbed = cfg;
  window.reactifyShopifyEmbed = cfg;
  window.REACTIFY_EMBED_BASE = cfg.base;
}

export function ThreadEmbed() {
  const apiKey = process.env.NEXT_PUBLIC_REACTIFY_API_KEY ?? "";

  // Set config before reactify.js upgrades <reactify-thread> (same as WordPress wp_localize_script).
  useLayoutEffect(() => {
    if (apiKey) bootstrapReactifyEmbed(apiKey);
  }, [apiKey]);

  return (
    <>
      <Script
        src={SRC}
        strategy="afterInteractive"
        onLoad={() => {
          if (apiKey) bootstrapReactifyEmbed(apiKey);
        }}
      />
      {/* @ts-expect-error custom element */}
      <reactify-thread
        thread="YOUR_THREAD_ID"
        data-base={APP_BASE}
      />
    </>
  );
}
Server page
// app/page.tsx (Server Component)
import { ThreadEmbed } from "./reactify/ThreadEmbed";

export default function Page() {
  return (
    <main>
      <h1>Drop</h1>
      <ThreadEmbed />
    </main>
  );
}

Pages Router

Set window.reactifyWprtEmbed in pages/_app.tsx (client) before next/script with strategy="afterInteractive", or dynamically import a client-only section that bootstraps then loads the custom element.

Images & video domains

If you wrap media with next/image, keep thread source playback on plain URLs inside the embed—the custom element handles its own media. Add your storage host to images.remotePatterns only if you mirror assets through Next.