Ask0 logoAsk0
Integrations

Remix Integration

Add Ask0 to your Remix app with React component integration. Full support for Remix's SSR and progressive enhancement.

Add Ask0 to your Remix application.

Installation

Root Layout

Add the script to your root layout:

app/root.tsx
import type { LinksFunction, MetaFunction } from '@remix-run/node';
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from '@remix-run/react';

export const meta: MetaFunction = () => [
  { charset: 'utf-8' },
  { title: 'My Remix App' },
  { viewport: 'width=device-width,initial-scale=1' },
];

export default function App() {
  return (
    <html lang="en">
      <head>
        <Meta />
        <Links />
      </head>
      <body>
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />

        <script
          src="https://assets.ask0.ai/scripts/ask.js"
          data-project-id={process.env.ASK0_PROJECT_ID}
          async
        />
      </body>
    </html>
  );
}

Custom Hook

Create a custom hook for Ask0:

app/hooks/useAsk0.ts
import { useEffect, useState } from 'react';

declare global {
  interface Window {
    ask0?: {
      open: () => void;
      close: () => void;
      toggle: () => void;
      identify: (user: { id: string; email?: string; name?: string }) => void;
    };
  }
}

export function useAsk0() {
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    const checkAsk0 = () => {
      if (window.ask0) {
        setIsReady(true);
      } else {
        setTimeout(checkAsk0, 100);
      }
    };
    checkAsk0();
  }, []);

  return {
    isReady,
    open: () => window.ask0?.open(),
    close: () => window.ask0?.close(),
    toggle: () => window.ask0?.toggle(),
    identify: (user: any) => window.ask0?.identify(user),
  };
}

Component Integration

Use the hook in your components:

app/components/HelpButton.tsx
import { useAsk0 } from '~/hooks/useAsk0';

export default function HelpButton() {
  const { open, isReady } = useAsk0();

  if (!isReady) return null;

  return (
    <button onClick={open} className="help-button">
      Need Help?
    </button>
  );
}

User Identification

Integrate with Remix auth:

app/root.tsx
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { getUser } from '~/session.server';
import { useEffect } from 'react';

export async function loader({ request }: LoaderFunctionArgs) {
  const user = await getUser(request);
  return json({ user });
}

export default function App() {
  const { user } = useLoaderData<typeof loader>();

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

  return (
    <html lang="en">
      {/* ... */}
    </html>
  );
}

Environment Variables

.env
ASK0_PROJECT_ID=your_project_id

Access in loader/action:

app/routes/dashboard.tsx
import type { LoaderFunctionArgs } from '@remix-run/node';

export async function loader({ request }: LoaderFunctionArgs) {
  const projectId = process.env.ASK0_PROJECT_ID;
  // Use projectId...
  return json({ projectId });
}

Route-Specific Loading

Load Ask0 only on specific routes:

app/routes/docs.tsx
import { Outlet } from '@remix-run/react';
import { useEffect } from 'react';

export default function DocsLayout() {
  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://assets.ask0.ai/scripts/ask.js';
    script.dataset.projectId = process.env.ASK0_PROJECT_ID || '';
    script.async = true;
    document.body.appendChild(script);

    return () => {
      document.body.removeChild(script);
    };
  }, []);

  return (
    <div>
      <aside>Docs Sidebar</aside>
      <main>
        <Outlet />
      </main>
    </div>
  );
}

TypeScript Declarations

app/types/ask0.d.ts
declare global {
  interface Window {
    ask0?: {
      open: () => void;
      close: () => void;
      toggle: () => void;
      identify: (user: {
        id: string;
        email?: string;
        name?: string;
        [key: string]: any;
      }) => void;
    };
  }
}

export {};

Remix Tips:

  • Add script in root.tsx for site-wide availability
  • Use loader functions to pass env vars to client
  • Integrate with Remix auth for user identification
  • Compatible with Remix v1 and v2
  • Works with both SSR and SPA modes

Next Steps