Ask0 logoAsk0
Integrations

React Integration

Integrate Ask0 into your React app using our official React component. Easy setup with full TypeScript support and customizable UI.

Integrate Ask0 AI assistant into your React application to provide instant support and guidance to users.

Installation

Using Script Tag

The simplest way to add Ask0 to React:

// In your index.html or public/index.html
<script
  src="https://assets.ask0.ai/scripts/ask.js"
  data-project-id="YOUR_PROJECT_ID"
></script>

Using React Component

For better control, create a React component:

npm install @ask0/react
yarn add @ask0/react

Basic Integration

Functional Component

import { useEffect } from 'react';

function App() {
  useEffect(() => {
    // Load Ask0 script
    const script = document.createElement('script');
    script.src = 'https://assets.ask0.ai/scripts/ask.js';
    script.async = true;
    script.dataset.projectId = process.env.REACT_APP_ASK0_PROJECT_ID;

    document.body.appendChild(script);

    return () => {
      // Cleanup on unmount
      if (document.body.contains(script)) {
        document.body.removeChild(script);
      }
      if (window.ask0) {
        window.ask0.destroy?.();
      }
    };
  }, []);

  return (
    <div className="App">
      {/* Your app content */}
    </div>
  );
}

export default App;

Custom Hook

Create a reusable hook:

// hooks/useAsk0.js
import { useEffect, useCallback } from 'react';

export function useAsk0(config = {}) {
  const {
    projectId = process.env.REACT_APP_ASK0_PROJECT_ID,
    position = 'bottom-right',
    theme = 'auto',
  } = config;

  useEffect(() => {
    if (!projectId) {
      console.warn('Ask0: Project ID not provided');
      return;
    }

    const script = document.createElement('script');
    script.src = 'https://assets.ask0.ai/scripts/ask.js';
    script.async = true;
    script.dataset.projectId = projectId;
    script.dataset.position = position;
    script.dataset.theme = theme;

    document.body.appendChild(script);

    return () => {
      if (document.body.contains(script)) {
        document.body.removeChild(script);
      }
    };
  }, [projectId, position, theme]);

  const open = useCallback(() => {
    window.ask0?.open();
  }, []);

  const close = useCallback(() => {
    window.ask0?.close();
  }, []);

  const toggle = useCallback(() => {
    window.ask0?.toggle();
  }, []);

  return { open, close, toggle };
}

// Usage in component
function MyComponent() {
  const { open, close, toggle } = useAsk0();

  return (
    <button onClick={open}>
      Open Support Chat
    </button>
  );
}

Advanced Integration

Context Provider

Create a context for Ask0:

// context/Ask0Context.js
import React, { createContext, useContext, useEffect, useState } from 'react';

const Ask0Context = createContext(null);

export function Ask0Provider({ children, config }) {
  const [isReady, setIsReady] = useState(false);
  const [ask0, setAsk0] = useState(null);

  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://assets.ask0.ai/scripts/ask.js';
    script.async = true;
    Object.entries(config).forEach(([key, value]) => {
      script.dataset[key] = value;
    });

    script.onload = () => {
      setAsk0(window.ask0);
      setIsReady(true);
    };

    document.body.appendChild(script);

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

  return (
    <Ask0Context.Provider value={{ ask0, isReady }}>
      {children}
    </Ask0Context.Provider>
  );
}

export function useAsk0Context() {
  const context = useContext(Ask0Context);
  if (!context) {
    throw new Error('useAsk0Context must be used within Ask0Provider');
  }
  return context;
}

// Usage
function App() {
  return (
    <Ask0Provider config={{ projectId: 'YOUR_PROJECT_ID' }}>
      <YourApp />
    </Ask0Provider>
  );
}

function SupportButton() {
  const { ask0, isReady } = useAsk0Context();

  return (
    <button
      onClick={() => ask0?.open()}
      disabled={!isReady}
    >
      Get Help
    </button>
  );
}

User Identification

Identify logged-in users:

import { useEffect } from 'react';
import { useAuth } from './hooks/useAuth'; // Your auth hook

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

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

  return <div>Your App</div>;
}

React Router Integration

Integrate with React Router:

import { useLocation } from 'react-router-dom';
import { useEffect } from 'react';

function Ask0RouterIntegration() {
  const location = useLocation();

  useEffect(() => {
    if (window.ask0) {
      // Track page views
      window.ask0.trackPage(location.pathname);

      // Page-specific configuration
      if (location.pathname === '/pricing') {
        window.ask0.setContext({
          page: 'pricing',
          showPricingHelp: true,
        });
      }
    }
  }, [location]);

  return null;
}

// In your App component
function App() {
  return (
    <Router>
      <Ask0RouterIntegration />
      <Routes>
        {/* Your routes */}
      </Routes>
    </Router>
  );
}

State Management

With Redux

// redux/ask0Slice.js
import { createSlice } from '@reduxjs/toolkit';

const ask0Slice = createSlice({
  name: 'ask0',
  initialState: {
    isOpen: false,
    isReady: false,
  },
  reducers: {
    setReady: (state, action) => {
      state.isReady = action.payload;
    },
    setOpen: (state, action) => {
      state.isOpen = action.payload;
    },
  },
});

export const { setReady, setOpen } = ask0Slice.actions;
export default ask0Slice.reducer;

// Component
import { useDispatch, useSelector } from 'react-redux';
import { setOpen } from './redux/ask0Slice';

function SupportButton() {
  const dispatch = useDispatch();
  const isReady = useSelector(state => state.ask0.isReady);

  const handleClick = () => {
    window.ask0?.open();
    dispatch(setOpen(true));
  };

  return (
    <button onClick={handleClick} disabled={!isReady}>
      Support
    </button>
  );
}

With Context API

// context/AppContext.js
import { createContext, useContext, useState } from 'react';

const AppContext = createContext();

export function AppProvider({ children }) {
  const [supportOpen, setSupportOpen] = useState(false);

  const openSupport = () => {
    window.ask0?.open();
    setSupportOpen(true);
  };

  const closeSupport = () => {
    window.ask0?.close();
    setSupportOpen(false);
  };

  return (
    <AppContext.Provider value={{ supportOpen, openSupport, closeSupport }}>
      {children}
    </AppContext.Provider>
  );
}

TypeScript Support

Add type definitions:

// types/ask0.d.ts
interface Ask0Config {
  projectId: string;
  position?: 'bottom-right' | 'bottom-left' | 'center';
  theme?: 'light' | 'dark' | 'auto';
}

interface Ask0User {
  id: string;
  email?: string;
  name?: string;
  [key: string]: any;
}

interface Ask0Widget {
  open: () => void;
  close: () => void;
  toggle: () => void;
  identify: (user: Ask0User) => void;
  setTheme: (theme: 'light' | 'dark') => void;
  on: (event: string, callback: Function) => void;
  destroy?: () => void;
}

declare global {
  interface Window {
    ask0?: Ask0Widget;
  }
}

export {};

// Usage in component
import { FC } from 'react';

const SupportButton: FC = () => {
  const handleClick = (): void => {
    window.ask0?.open();
  };

  return <button onClick={handleClick}>Support</button>;
};

Styling Integration

With Styled Components

import styled from 'styled-components';

const SupportButton = styled.button`
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  padding: 0.75rem 1.5rem;
  background: ${props => props.theme.primary};
  color: white;
  border-radius: 9999px;
  border: none;
  cursor: pointer;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  transition: all 0.3s;

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
  }
`;

function CustomTrigger() {
  return (
    <SupportButton onClick={() => window.ask0?.open()}>
      Need Help?
    </SupportButton>
  );
}

With Tailwind CSS

function TailwindTrigger() {
  return (
    <button
      onClick={() => window.ask0?.open()}
      className="fixed bottom-8 right-8 px-6 py-3 bg-blue-600 text-white
                 rounded-full shadow-lg hover:shadow-xl hover:-translate-y-0.5
                 transition-all duration-300"
    >
      Get Help
    </button>
  );
}

Environment Configuration

REACT_APP_ASK0_PROJECT_ID=your_project_id
REACT_APP_ASK0_POSITION=bottom-right
REACT_APP_ASK0_THEME=auto
// config/ask0.js
export const ask0Config = {
  projectId: process.env.REACT_APP_ASK0_PROJECT_ID,
  position: process.env.REACT_APP_ASK0_POSITION || 'bottom-right',
  theme: process.env.REACT_APP_ASK0_THEME || 'auto',
};

Testing

Jest Testing

// __tests__/Ask0.test.js
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import App from './App';

describe('Ask0 Integration', () => {
  beforeEach(() => {
    // Mock window.ask0
    window.ask0 = {
      open: jest.fn(),
      close: jest.fn(),
      toggle: jest.fn(),
    };
  });

  it('should open Ask0 when button clicked', async () => {
    render(<App />);

    const button = screen.getByText('Get Help');
    await userEvent.click(button);

    expect(window.ask0.open).toHaveBeenCalled();
  });
});

Performance Optimization

Lazy Loading

import { lazy, Suspense } from 'react';

const Ask0Widget = lazy(() => import('./components/Ask0Widget'));

function App() {
  return (
    <div>
      {/* Your app content */}
      <Suspense fallback={null}>
        <Ask0Widget />
      </Suspense>
    </div>
  );
}

Code Splitting

import { useEffect, useState } from 'react';

function App() {
  const [loadAsk0, setLoadAsk0] = useState(false);

  useEffect(() => {
    // Load Ask0 after initial render
    const timer = setTimeout(() => setLoadAsk0(true), 2000);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div>
      {/* App content */}
      {loadAsk0 && <Ask0Integration />}
    </div>
  );
}

Best Practices

React Integration Tips:

  1. Load Ask0 after initial render for better performance
  2. Use cleanup in useEffect to prevent memory leaks
  3. Identify users when they log in
  4. Handle theme changes reactively
  5. Use TypeScript for better type safety
  6. Test integration with React Testing Library
  7. Consider lazy loading for large applications

Next Steps