Echo
Getting Started

React

Integrate Echo into your React application

Getting Started with Echo in React

Create a React app using Vite

Run the following commands to create a new React app using Vite.

npm create vite@latest echo-react -- --template react-ts
cd echo-react
npm install
npm run dev
yarn create vite echo-react --template react-ts
cd echo-react
yarn install
yarn dev
pnpm create vite echo-react --template react-ts
cd echo-react
pnpm install
pnpm dev
bun create vite echo-react --template react-ts
cd echo-react
bun install
bun dev

Install @merit-systems/echo-react-sdk and ai

The Echo React SDK gives you access to prebuilt components, hooks and helpers to make LLM billing and calling easier.

The Vercel AI SDK is the standard SDK for interacting with AI in Typescript.

Run the following commands to install the dependencies.

npm i @merit-systems/echo-react-sdk ai
yarn add @merit-systems/echo-react-sdk ai
pnpm add @merit-systems/echo-react-sdk ai
bun add @merit-systems/echo-react-sdk ai

Setup your Echo App

  1. In the Echo dashboard navigate to Create App.
  2. Copy your app_id and paste it into your .env file.

The final result should resemble the following:

.env
VITE_ECHO_APP_ID=b30f0f78-4000-8000-000000000000

Import your Echo App ID

In your main.tsx file, import your app id. Include your App ID from the prior step.

main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'

const APP_ID = import.meta.env.VITE_ECHO_APP_ID;

if (!APP_ID) {
    throw new Error('Add your Echo App ID to .env');
}

createRoot(document.getElementById('root')!).render(
    <StrictMode>
        <App />
    </StrictMode>,
)

<EchoProvider> component

The <EchoProvider> component provides session and user context to Echo's hooks and components. It's recommended to wrap your entire app at the entry point with <EchoProvider> to make Echo globally available.

Pass your Echo App ID as a prop to <EchoProvider>.

main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
import { EchoProvider } from '@merit-systems/echo-react-sdk';

const APP_ID = import.meta.env.VITE_ECHO_APP_ID;

if (!APP_ID) {
    throw new Error('Add your Echo App ID to .env');
}

createRoot(document.getElementById('root')!).render(
    <StrictMode>
        <EchoProvider config={{ appId: APP_ID }}>
            <App />
        </EchoProvider>
    </StrictMode>,
)

<EchoSignIn> component

<EchoSignIn> is a React component that can be placed anywhere in your app. When a user clicks it will redirect to authenticate with echo.merit.systems. After authentication, Echo can manage all LLM calls.

src/App.tsx
import { EchoSignIn } from '@merit-systems/echo-react-sdk';

function App() {

    return (
        <>
            <header>
                <EchoSignIn />
            </header>
            <main>
                <h1>AI Coming Soon</h1>
            </main>
        </>
    );
}

export default App;

useEcho() hook

The useEcho() hook surfaces everything you need to show Echo state to your users.

src/App.tsx
import { EchoSignIn, useEcho } from '@merit-systems/echo-react-sdk';

function App() {

const { isAuthenticated, user, balance, signOut } = useEcho();

return (
    <>
        <header>
            <EchoSignIn />

        {!isAuthenticated && "Sign in to continue"}
        {isAuthenticated && (
            <div>
                <p>Welcome, {user?.name}!</p>
                <p>Email: {user?.email}</p>
                <p>Balance: {balance?.balance}</p>
                <button onClick={signOut}>Sign Out</button>
            </div>
        )}
        </header>
        <main>
            <h1>AI Coming Soon</h1>
        </main>
    </>
);
}

export default App;

generateText() from OpenAI

Create a new component and use the Vercel AI SDK with Echo models.

src/App.tsx
import { EchoSignIn, useEcho } from '@merit-systems/echo-react-sdk';
import AIComponent from './AIComponent';

function App() {

const { isAuthenticated, user, balance, signOut } = useEcho();

return (
    <>
        <header>
            <EchoSignIn />

            {!isAuthenticated && "Sign in to continue"}
            {isAuthenticated && (
                <div>
                    <p>Welcome, {user?.name}!</p>
                    <p>Email: {user?.email}</p>
                    <p>Balance: {balance?.balance}</p>
                    <button onClick={signOut}>Sign Out</button>
                </div>
            )}
        </header>
        <main>
            <h1>AI Coming Soon</h1>
            {isAuthenticated && <AIComponent />}
        </main>
    </>
);
}

export default App;

AI SDK's generateText() is used to generate a single response from the model. useEchoModelProviders() routes the requests through Echo.

src/AIComponent.tsx
import { useState } from 'react';
import { generateText } from 'ai';
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';

export default function AIComponent() {
    const [result, setResult] = useState("");
    const { openai } = useEchoModelProviders();

    const handleGen = async () => {
        const { text } = await generateText({
            model: openai('gpt-5-nano'),
            messages: [
                { role: 'user', content: 'Two sentences. What is the cleanest way to make $1M?' }
            ]
        });
        setResult(text);
    };


    return (
        <div>
            <button onClick={handleGen}>Generate Wisdom</button>
            <p>{result}</p>
        </div>

    );
}

Switch to streamText()

The AI SDK streamText() function is used to incrementally show the response from the model.

src/AIComponent.tsx
import { useState } from 'react';
import { generateText } from 'ai';
import { streamText } from 'ai';
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';

export default function AIComponent() {
    const [result, setResult] = useState("");
    const { openai } = useEchoModelProviders();

    const handleGen = async () => {
        setResult("Thinking...");
        const { text } = await streamText({
        const { text } = await generateText({
            model: openai('gpt-5-nano'),
            messages: [
                { role: 'user', content: 'Two sentences. What is the cleanest way to make $1M?' }
            ]
        });

        for await (const chunk of textStream) {
            setResult(prev => prev + chunk);
        }
    };


    return (
        <div>
            <button onClick={handleGen}>Generate Wisdom</button>
            <p>{result}</p>
        </div>

    );
}

Enjoy the fruits of your labor.

Run your project with the following command.

npm run dev
yarn dev
pnpm dev
bun dev

Visit your app's homepage at http://localhost:5173. Sign in and click "Generate Wisdom".

Next Steps

For detailed documentation and advanced features, see the React SDK overview.