Complete working example available: This guide references the basic React
example
in our examples repository. Clone it to see a fully functional implementation,
then follow this guide to understand how it works and adapt it to your needs.
This guide uses ROPC (Resource Owner Password Credentials) authentication for
simplicity and practicality in embedded scenarios where users are already
authenticated in the host application. For production deployments, consider
your organization’s authentication requirements.
What You’ll Learn
By following this guide, you’ll understand:- How to architect a secure client-server integration
- Why ROPC authentication works well for embedded EHR scenarios
- How to use the Web Component API with React
- How to manage the interaction lifecycle programmatically
- Key customization points and production considerations
Prerequisites
Before starting, ensure you have:- Node.js 18+ installed
- Corti API access with valid credentials
- OAuth client configured for ROPC (Resource Owner Password Credentials) flow
- User account created in Corti Console for authentication
- Basic familiarity with React and Express
Architecture Overview
The integration follows a client-server architecture: Backend (Express Server):- Handles OAuth authentication using ROPC flow via
@corti/sdk - Provides configuration endpoint for environment-specific settings
- Keeps sensitive credentials server-side
- Runs on port 3000
- Fetches auth tokens and configuration from backend
- Embeds Corti Assistant using
@corti/embedded-webWeb Component - Manages interaction lifecycle (create, navigate, handle events)
- Uses React 19’s Suspense for async data loading
- Runs on port 5173 (Vite default)
- Security: Credentials stay on the server, never exposed to the browser
- Separation of concerns: Auth logic separate from UI logic
- Flexibility: Easy to swap ROPC for other auth methods later
- Development speed: Simple to run and test locally
Key Concepts
Authentication Flow
- Backend authenticates with Corti using stored credentials (ROPC)
- Frontend requests tokens from backend
/api/authendpoint - Web Component receives tokens and authenticates the embedded session
- No user interaction required - seamless experience
Web Component Integration
The integration uses<CortiEmbeddedReact>, a React wrapper around the standard Web Component:
- Type-safe: Full TypeScript support with IDE autocomplete
- React-friendly: Hooks-based API (
useCortiEmbeddedApi) - Event handling: Native React event props instead of addEventListener
- Lifecycle management: Automatic cleanup and ref management
Interaction Lifecycle
Every clinical encounter in Corti Assistant is called an “interaction”:- Create interaction - Define encounter metadata (type, identifier, timestamps)
- Navigate to session - Load the session view with recording interface
- User records - Clinician documents the encounter
- Handle events - React to document generation, errors, state changes
- Link Corti sessions to your EHR’s encounter IDs
- Pre-fill encounter metadata from your system
- Control when and how sessions start
- Track interactions in your database
Implementation Guide
Project Structure
Step 1: Backend Setup
Purpose: Securely authenticate with Corti and provide tokens to the frontend. Key file:server.ts
What it does:
/api/auth- Uses@corti/sdkto perform ROPC authentication/api/config- Returns base URL based on environment (EU/US)- CORS configured for local Vite dev server
Step 2: Frontend Data Fetching
Purpose: Fetch auth tokens and config before rendering the Assistant. Key file:src/lib/auth.ts
What it does:
- Promise-based API calls to backend
- Simple in-memory caching to prevent duplicate requests
- Separates data fetching logic from UI components
Step 3: App Root with Suspense
Purpose: Coordinate parallel data fetching and handle loading states. Key file:src/App.tsx
Key pattern: React 19’s use() hook with Suspense for async data
- Parallel fetching: Config and auth load simultaneously
- Declarative loading: Suspense fallback handles loading UI automatically
- Error boundaries: Easy to add error handling at the boundary level
useEffect + useState for data fetching instead. The rest of the pattern stays the same.
See the implementation: App.tsx in example repo
Step 4: Embedded Assistant Component
Purpose: Render the Web Component and manage the interaction lifecycle. Key file:src/components/EmbeddedAssistant.tsx
Core responsibilities:
- Render
<CortiEmbeddedReact>with configuration - Use
useCortiEmbeddedApihook to access API methods - Handle
onReadyevent to authenticate and create interaction - Manage status display and error states
onReady- Authenticate, create interaction, navigate to sessiononEvent- Log events (or handle specific ones like document.generated)onError- Display errors to user
Running the Example
Clone and run the complete example:Customization Points
Change Authentication Method
To use PKCE instead of ROPC, modifyserver.ts to use:
Customize Interaction Creation
Modify thecreateInteraction call in EmbeddedAssistant.tsx:
Configure Assistant Appearance
Callapi.configure() after authentication to customize:
Handle Specific Events
Listen for specific Assistant events:Production Considerations
Environment Variables
Never commit credentials to version control:Error Handling
Add proper error boundaries and retry logic:Token Refresh
Implement token refresh logic in your backend:CORS Configuration
Update CORS for production domains:Next Steps
This is a foundational integration. Extend it with:- Document export - Capture
document.generatedevents and save to your EHR - Session management - Load existing interactions using
api.navigate("/session/<id>") - Advanced configuration - Customize features, appearance, and locale
- Monitoring - Add logging and analytics around Assistant usage
- Multi-user support - Handle authentication for multiple clinicians
Advanced integration patterns including document synchronization, session
persistence, and multi-tenant setups will be available in Q2 2026. Check the
examples repository for updates.
Troubleshooting
CORS Errors
If you see CORS errors, verify Vite’s dev server port matches thecors.origin in server.ts. Vite defaults to 5173 but may use 5174+ if that port is taken.
Fix: Update the origin array in server.ts to match your Vite output:
Authentication Fails
- Verify credentials in
.envmatch your Corti Console setup - Ensure OAuth client has “Direct Access Grants” enabled for ROPC
- Check user account exists and is active in your Corti tenant
- Verify
CORTI_ENVIRONMENTmatches your tenant region (eu/us)
Web Component Not Loading
- Check browser console for import errors
- Verify
@corti/embedded-webpackage is installed correctly - Ensure
baseURLmatches your region (https://assistant.eu.corti.app) - Confirm microphone permissions are granted (required for recording)
Double Initialization in Dev Mode
This is expected with React 19 StrictMode. ThehasInitialized ref guard prevents issues. In production builds, StrictMode is disabled and this won’t occur.