A web component and React component library that provides an embedded interface for Corti AI assistant.
- Web Component & React: Available as both a native web component and React component
- Show/Hide: Control the visibility of the chat interface
- Authentication Support: Built-in authentication message handling
- TypeScript Support: Full TypeScript definitions included
npm install @corti/embedded-webThe package provides a web component by default. For React usage, also install React as a peer dependency:
npm install react @types/react<corti-embedded
id="corti-component"
base-url="https://assistant.eu.corti.app" <!-- REQUIRED -->
></corti-embedded>const myComponent = document.getElementById('corti-component');
const userResponse = await myComponent.auth({...});
const interaction = await myComponent.createInteraction({
"assignedUserId": null,
"encounter": {
"identifier": `encounter-${Date.now()}`,
"status": "planned",
"type": "first_consultation",
"period": {
"startedAt": "2025-11-11T16:14:59.923Z"
}
}
});
await myComponent.configureSession({"defaultTemplateKey": "soap_note"});
await myComponent.addFacts([{"text": "Chest pain", "group": "other"}]);
await myComponent.navigate('/interactions/123');
await myComponent.show()import React, { useRef } from 'react';
import {
CortiEmbeddedReact,
type CortiEmbeddedReactRef,
useCortiEmbeddedApi,
useCortiEmbeddedStatus,
} from '@corti/embedded-web/react';
function App() {
const cortiRef = useRef<CortiEmbeddedReactRef>(null);
const api = useCortiEmbeddedApi(cortiRef);
const { status } = useCortiEmbeddedStatus(cortiRef);
const handleReady = () => {
console.log('Corti component is ready!');
};
const handleEvent = (
event: CustomEvent<{ name: string; payload: unknown }>,
) => {
console.log('Event name:', event.detail.name);
console.log('Event payload:', event.detail.payload);
};
const handleAuth = async () => {
try {
const user = await api.auth({
access_token: 'your-token',
token_type: 'Bearer',
// ... rest of the token response
});
console.log('Authenticated:', user);
await api.configureSession({ defaultTemplateKey: 'soap_note' });
await api.createInteraction({
encounter: {
identifier: `encounter-${Date.now()}`,
status: 'planned',
type: 'first_consultation',
period: { startedAt: new Date().toISOString() },
},
});
} catch (error) {
console.error('Auth failed:', error);
}
};
return (
<div style={{ height: '100vh' }}>
<button onClick={handleAuth}>Authenticate</button>
<CortiEmbeddedReact
ref={cortiRef}
baseURL="https://assistant.eu.corti.app" // REQUIRED
visibility="visible"
onReady={handleReady}
onEvent={handleEvent}
onError={event => console.error('Embedded error:', event.detail)}
style={{ width: '100%', height: '500px' }}
/>
<pre>{JSON.stringify(status, null, 2)}</pre>
</div>
);
}const component = document.getElementById('corti-component');
// Show the chat interface
component.show();
// Hide the chat interface
component.hide();- Use these named helpers for common tasks. They provide clearer intent and sensible defaults.
const authResponse = await component.auth({
// Example: Keycloak-style token + mode
access_token: 'YOUR_JWT',
token_type: 'Bearer',
mode: 'stateful',
...
});await component.configureSession({
defaultLanguage: 'en',
defaultOutputLanguage: 'en',
defaultTemplateKey: 'discharge-summary',
defaultMode: 'virtual',
});await component.addFacts([
{ text: 'Patient reports chest pain', group: 'subjective' },
{ text: 'BP 120/80', group: 'vitals' },
],await component.navigate('/interactions/123');const created = await component.createInteraction({
assignedUserId: null,
encounter: {
identifier: 'enc-123',
status: 'in-progress',
type: 'consult',
period: { startedAt: new Date().toISOString() },
title: 'Visit for cough',
},
patient: {
identifier: 'pat-456',
},
});await component.startRecording();
// ... later
await component.stopRecording();console.log(component.getStatus());The component uses a PostMessageHandler utility class that:
- Manages message listeners and cleanup
- Tracks pending requests with unique IDs
- Handles response correlation
- Ensures proper cleanup on component destruction
The React component (CortiEmbeddedReact) is available as an additional export and provides:
- Hook-based API access:
useCortiEmbeddedApi(ref)exposes instance-bound methods (auth,navigate,createInteraction, etc.) - Generic event stream:
onEventreceives all embedded events as{ name, payload } - Status hook:
useCortiEmbeddedStatus(ref)keeps latest status/reactive state - Multi-instance safety: API methods are scoped to the ref you pass
- React Props: Standard React props like
className,style, etc.
import {
CortiEmbeddedReact,
CortiEmbedded, // Web component also available
type CortiEmbeddedReactRef,
useCortiEmbeddedApi,
useCortiEmbeddedStatus,
} from '@corti/embedded-web/react';- Use
onEventfor all embedded events. - Event detail shape is
{ name: string; payload: unknown }. - Full event catalog and payload details are documented at:
<CortiEmbeddedReact
baseURL="https://assistant.eu.corti.app"
onEvent={event => {
console.log(event.detail.name, event.detail.payload);
}}
onReady={() => console.log('Ready')}
onError={event => console.error(event.detail)}
/>Use the API hook with the same component ref:
import React, { useRef } from 'react';
import {
CortiEmbeddedReact,
type CortiEmbeddedReactRef,
useCortiEmbeddedApi,
} from '@corti/embedded-web/react';
function Example() {
const ref = useRef<CortiEmbeddedReactRef>(null);
const api = useCortiEmbeddedApi(ref);
const run = async () => {
await api.auth({ access_token: '...', token_type: 'Bearer', mode: 'stateful' });
const created = await api.createInteraction({ encounter: { ... } });
await api.navigate(`/session/${created.id}`);
};
return (
<>
<button onClick={() => void run()}>Run</button>
<CortiEmbeddedReact ref={ref} baseURL="https://assistant.eu.corti.app" />
</>
);
}For detailed React usage examples, see docs/react-usage.md.
- Default export: Web component only (
dist/web-bundle.js) - React export: Web component + React component (
@corti/embedded-web/react) - No dependencies: Web component bundle has zero external dependencies
- Peer dependencies: React components require React as peer dependency only