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:
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:
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:
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:
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
ASK0_PROJECT_ID=your_project_idAccess in loader/action:
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:
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
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