Framework Guides

Install Callout in React, Next.js, Vue, or plain HTML.

Callout works with any web framework. The installation is always the same script tag — frameworks only matter for identity calls and milestone completion.

HTML / Static Sites

<script>
  window.CalloutConfig = { projectId: "YOUR_PROJECT_ID" };
</script>
<script src="https://cdn.withcallout.com/widget.js" defer></script>

That's it. Works with any static site, WordPress, or plain HTML.

React

Add the script tag to public/index.html. Use useEffect for identity:

import { useEffect } from "react";
import { useAuth } from "./auth";

function App() {
  const { user } = useAuth();

  useEffect(() => {
    if (user && window.Callout) {
      Callout.identify({
        id: user.id,
        email: user.email,
        name: user.name
      });
    }
  }, [user]);

  return <div>{/* your app */}</div>;
}

Next.js

Use next/script in your root layout:

import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Script id="callout-config" strategy="afterInteractive">
          {`window.CalloutConfig = { projectId: "YOUR_PROJECT_ID" };`}
        </Script>
        <Script
          src="https://cdn.withcallout.com/widget.js"
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}

Vue

Add the script tag to index.html. Use onMounted for identity:

<script setup>
import { onMounted } from "vue";
import { useAuth } from "./composables/auth";

const { user } = useAuth();

onMounted(() => {
  if (user.value && window.Callout) {
    Callout.identify({
      id: user.value.id,
      email: user.value.email,
      name: user.value.name
    });
  }
});
</script>

Single-Page Apps

Callout automatically detects route changes in single-page apps. URL-targeted experiences (tours, tooltips, banners) re-evaluate on every navigation. You don't need to do anything special.

For conditional mounting (e.g., hide on admin pages):

router.on("routeChange", (route) => {
  if (route.startsWith("/admin")) {
    Callout.destroy();
  } else {
    Callout.init({ projectId: "YOUR_PROJECT_ID" });
  }
});

On this page