Embed Codiris Brainboard whiteboard functionality into your applications
npm install codiris-brainboard-sdkEmbed Codiris Brainboard whiteboard functionality into your applications. Build collaborative visual experiences with AI-powered features.
``bash`
npm install codiris-brainboard-sdkor
yarn add codiris-brainboard-sdkor
pnpm add codiris-brainboard-sdk
Before using the SDK, you need to generate an API key:
1. Go to Codiris Settings
2. Navigate to Settings & Members → API Keys
3. Click Create Key in the "Brainboard SDK Keys" section
4. Give your key a name (e.g., "Production", "Development")
5. Optionally, configure allowed domains for security
6. Copy the generated key - it will only be shown once!
SDK keys have the format: brb_live_xxxxxxxxxxxxxxxxxxxx (or brb_test_ for test keys)
For production, you can restrict which domains can use your API key:
- Leave empty for development (allows all domains)
- Add specific domains like app.example.com, localhost:3000*.example.com
- Supports wildcard subdomains:
`typescript
import { BrainboardClient } from 'codiris-brainboard-sdk';
// Initialize the client
const client = new BrainboardClient({
apiKey: 'brb_live_your-api-key-here',
baseUrl: 'https://app.codiris.ai', // optional, defaults to production
});
// List boards
const { data: boards } = await client.listBoards();
// Create a board
const { data: board } = await client.createBoard({
name: 'My Board',
description: 'A collaborative whiteboard',
});
// Add objects to the board
await client.createObject(board.id, {
type: 'sticky',
x: 100,
y: 100,
width: 200,
height: 200,
text: 'Hello World!',
fill: '#ffeb3b',
});
`
`tsx
import { BrainboardProvider, BrainboardEmbed, useBoards } from 'codiris-brainboard-sdk/react';
// Wrap your app with the provider
function App() {
return (
baseUrl={process.env.NEXT_PUBLIC_BRAINBOARD_BASE_URL || "https://talk.codiris.build/api"}
>
);
}
// Use the embed component
function MyComponent() {
const { boards, createBoard } = useBoards();
return (
{boards[0] && (
width="100%"
height="600px"
showToolbar
onBoardChange={(board) => console.log('Board updated:', board)}
/>
)}
Important: The
BrainboardEmbed component automatically includes your API key in the iframe URL for authentication. This is necessary because iframes cannot send custom HTTP headers. To protect your API key:1. Use environment variables - Never hardcode your API key
2. Set domain restrictions - Configure allowed domains in your API key settings
3. Use HTTPS only - Always serve your app over HTTPS in production
Features
$3
`typescript
// List boards with filtering
const { data } = await client.listBoards({
status: 'active',
search: 'project',
page: 1,
pageSize: 20,
});// Get a specific board
const { data: board } = await client.getBoard('board-id');
// Update a board
await client.updateBoard('board-id', {
name: 'Updated Name',
isPublic: true,
});
// Delete a board
await client.deleteBoard('board-id');
// Duplicate a board
const { data: newBoard } = await client.duplicateBoard('board-id', 'Copy of Board');
`$3
`typescript
// Create various object types
await client.createObject(boardId, {
type: 'text',
x: 100, y: 100,
text: 'Hello World',
fontSize: 24,
});await client.createObject(boardId, {
type: 'shape',
x: 200, y: 200,
width: 150, height: 100,
shapeType: 'rectangle',
fill: '#3b82f6',
});
await client.createObject(boardId, {
type: 'sticky',
x: 400, y: 100,
width: 200, height: 200,
text: 'Idea #1',
fill: '#fef08a',
});
// Batch create
await client.createObjects(boardId, [
{ type: 'sticky', x: 100, y: 100, text: 'Task 1' },
{ type: 'sticky', x: 320, y: 100, text: 'Task 2' },
{ type: 'sticky', x: 540, y: 100, text: 'Task 3' },
]);
// Update objects
await client.updateObject(boardId, objectId, {
text: 'Updated text',
fill: '#22c55e',
});
// Delete objects
await client.deleteObject(boardId, objectId);
await client.deleteObjects(boardId, [id1, id2, id3]);
`$3
| Type | Description |
|------|-------------|
|
sticky | Sticky note with text |
| text | Text block |
| shape | Shapes (rectangle, circle, triangle, diamond, star, etc.) |
| line | Connecting line |
| arrow | Arrow connector |
| image | Image element |
| card | Card with title, description, tags |
| table | Data table |
| kanban | Kanban board |
| code | Code block with syntax highlighting |
| chart | Chart (line, bar, pie, etc.) |
| embed | External embed (YouTube, Figma, etc.) |
| frame | Presentation frame |
| draw | Freehand drawing |$3
`typescript
// Get board members
const { data: members } = await client.getMembers(boardId);// Invite a member
await client.inviteMember(boardId, 'user@example.com', 'editor');
// Update member role
await client.updateMemberRole(boardId, memberId, 'viewer');
// Remove a member
await client.removeMember(boardId, memberId);
// Generate share link
const { data } = await client.generateShareLink(boardId, {
canEdit: false,
expiresAt: '2024-12-31T23:59:59Z',
});
console.log(data.shareUrl);
`$3
`typescript
// Get comments
const { data: comments } = await client.getComments(boardId);// Add a comment
await client.addComment(boardId, 'Great idea!', objectId);
// Reply to a comment
await client.addComment(boardId, 'I agree!', objectId, parentCommentId);
// Resolve a comment
await client.resolveComment(boardId, commentId);
`$3
`typescript
// Generate content
const { data } = await client.generateContent({
prompt: 'Create a user journey map for an e-commerce checkout flow',
type: 'diagram',
});// Chat with AI about board content
const { data: response } = await client.chat(boardId, [
{ role: 'user', content: 'What are the main themes on this board?' }
]);
console.log(response.content);
console.log(response.sources); // Cited sources from the board
// Execute natural language commands
await client.executeCommand(boardId, 'make all sticky notes blue');
await client.executeCommand(boardId, 'align selected items to the left', selectedIds);
// Generate audio overview
const { data: audio } = await client.generateAudioOverview(boardId, 'podcast');
console.log(audio.audioUrl, audio.script);
`$3
`typescript
// List templates
const { data: templates } = await client.listTemplates('brainstorming');// Create from template
const { data: board } = await client.createFromTemplate(
'template-id',
'My Brainstorm Session'
);
// Save board as template
await client.saveAsTemplate(boardId, 'My Template', 'Reusable board layout');
`$3
`typescript
// Import from URL
await client.importFromUrl(boardId, 'https://example.com/article', { x: 100, y: 100 });// Extract from PDF
await client.extractPdf(boardId, 'https://example.com/document.pdf');
// Create from interview data
await client.createFromInterview(interviewId, 'Interview Summary Board');
// Export
const { data: json } = await client.exportAsJson(boardId);
const { data: image } = await client.exportAsImage(boardId, 'png', { scale: 2 });
const { data: pdf } = await client.exportAsPdf(boardId, { includeFrames: true });
`React Hooks
$3
`tsx
const { board, loading, error, updateBoard } = useBoard('board-id');
`$3
`tsx
const { boards, total, loading, createBoard, deleteBoard } = useBoards({
status: 'active',
page: 1,
});
`$3
`tsx
const {
objects,
selectedObjects,
createObject,
updateObject,
deleteObject,
selectObject,
clearSelection,
} = useBoardObjects('board-id');
`$3
`tsx
const { members, inviteMember, removeMember } = useBoardMembers('board-id');
`$3
`tsx
const { comments, addComment, deleteComment } = useBoardComments('board-id');
`$3
`tsx
const { messages, loading, sendMessage, clearMessages } = useBrainboardChat('board-id');// Send message with source grounding
await sendMessage('What patterns do you see?', true);
`$3
`tsx
const { loading, generate } = useBrainboardGenerate();const result = await generate({
prompt: 'Create a SWOT analysis template',
type: 'diagram',
});
`$3
`tsx
useBrainboardEvent('object:created', (event) => {
console.log('New object:', event.data);
});
`$3
`tsx
const { templates, createFromTemplate } = useTemplates('planning');
`React Components
$3
Full-featured embedded board editor.
`tsx
boardId="board-id"
width="100%"
height="600px"
readOnly={false}
showToolbar={true}
showSidebar={false}
showComments={true}
showMinimap={true}
theme="light"
onReady={() => console.log('Ready!')}
onBoardChange={(board) => console.log(board)}
onObjectSelect={(objects) => console.log(objects)}
/>
`$3
Read-only board viewer.
`tsx
boardId="board-id"
width="100%"
height="400px"
showNavigation={true}
autoFit={true}
/>
`$3
Board thumbnail preview.
`tsx
board={board}
width={200}
height={150}
onClick={() => navigate(/boards/${board.id})}
/>
`$3
Grid view of boards.
`tsx
boards={boards}
gridColumns={3}
onSelect={(board) => setSelectedBoard(board)}
emptyMessage="No boards yet"
/>
`Events
Listen to real-time events:
`typescript
import { globalEvents } from 'codiris-brainboard-sdk';globalEvents.on('board:updated', (event) => {
console.log('Board updated:', event.data);
});
globalEvents.on('object:created', (event) => {
console.log('Object created:', event.data);
});
globalEvents.on('user:joined', (event) => {
console.log('User joined:', event.data);
});
// Listen to all events
globalEvents.onAll((event) => {
console.log(
${event.type}:, event.data);
});
`$3
| Event | Description |
|-------|-------------|
|
board:loaded | Board finished loading |
| board:updated | Board properties changed |
| object:created | New object added |
| object:updated | Object modified |
| object:deleted | Object removed |
| object:selected | Objects selected |
| object:deselected | Selection cleared |
| camera:moved | Viewport changed |
| user:joined | User joined the board |
| user:left | User left the board |
| cursor:moved | User cursor moved |
| comment:added | New comment added |
| error | Error occurred |Configuration
`typescript
const client = new BrainboardClient({
// Required
apiKey: 'your-api-key', // Optional
baseUrl: 'https://app.codiris.ai/api', // Custom API endpoint
workspaceId: 'workspace-id', // Default workspace
userId: 'user-id', // Current user ID
userEmail: 'user@example.com', // Current user email
userName: 'User Name', // Current user name
externalUserId: 'your-user-123', // External user ID for board isolation
debug: false, // Enable debug logging
});
`User Isolation (Multi-tenancy)
When embedding Brainboard in your application, you can isolate boards per user using the
externalUserId feature. This allows each user in your system to have their own private set of boards without seeing boards from other users.$3
1. Pass your user's unique ID as
externalUserId when initializing the client
2. When creating boards, they are automatically tagged with this external user ID
3. When listing boards, only boards belonging to that user are returned$3
`typescript
// Initialize client with your user's ID
const client = new BrainboardClient({
apiKey: 'brb_live_your-api-key',
externalUserId: currentUser.id, // Your application's user ID
});// This user only sees their own boards
const { data: boards } = await client.listBoards();
// Boards created are tagged with this user's ID
const { data: board } = await client.createBoard({
name: "Alice's Board",
});
// board.externalUserId === currentUser.id
`$3
You can also pass the external user ID via HTTP headers:
`typescript
// When making API requests directly
fetch('/api/brainboard/boards', {
headers: {
'Authorization': Bearer ${apiKey},
'X-External-User-Id': 'your-user-123',
},
});
`$3
To demonstrate different user views (useful for admin/support scenarios):
`tsx
function UserBoardView({ userId }: { userId: string }) {
return (
apiKey={apiKey}
externalUserId={userId} // Each user sees only their boards
>
);
}
`$3
You can also filter boards by external user ID using query parameters:
`
GET /api/brainboard/boards?externalUserId=user_alice_123
`$3
Visit
/test/sdk in your Codiris dashboard to test user isolation. The test bench allows you to:1. Connect with your API key
2. Switch between simulated users (Alice, Bob, Charlie)
3. Create boards for each user
4. See how boards are isolated per user
TypeScript Support
The SDK is fully typed. Import types as needed:
`typescript
import type {
Board,
BoardObject,
BoardMember,
CreateBoardInput,
CreateObjectInput,
BrainboardConfig,
} from 'codiris-brainboard-sdk';
`Error Handling
All API methods return a consistent response format:
`typescript
const response = await client.getBoard('board-id');if (response.success) {
console.log(response.data);
} else {
console.error(response.error);
}
`With React hooks, errors are exposed via the
error property:`tsx
const { board, loading, error } = useBoard('board-id');if (error) {
return
Error: {error.message};
}
`Security Best Practices
$3
- Never commit API keys to version control - Use environment variables instead
- Use domain restrictions in production - Limit which domains can use your key
- Create separate keys for different environments - Use
brb_test_ keys for development
- Rotate keys periodically - Revoke and regenerate keys if compromised
- Monitor usage - Check the API Keys dashboard for unusual activity$3
`bash
.env.local (DO NOT commit this file)
NEXT_PUBLIC_BRAINBOARD_API_KEY=brb_live_xxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_BRAINBOARD_BASE_URL=https://app.codiris.ai
``tsx
// Use environment variables
apiKey={process.env.NEXT_PUBLIC_BRAINBOARD_API_KEY}
baseUrl={process.env.NEXT_PUBLIC_BRAINBOARD_BASE_URL}
>
``You can manage your SDK keys at any time:
- Create new keys: Settings → API Keys → Create Key
- View usage: See request counts and last used date
- Update domains: Modify allowed domains for existing keys
- Revoke keys: Deactivate keys that are no longer needed
Having issues? Check our Troubleshooting Guide for common problems and solutions:
- 401 Authentication Required - API key configuration issues
- Environment Variables Not Loading - .env file setup
- Board Not Loading - Access and permissions issues
- CORS Errors - Domain and security configuration
- Documentation: https://docs.codiris.ai
- Troubleshooting: TROUBLESHOOTING.md
- GitHub Issues: https://github.com/codiris/brainboard-sdk/issues
- Email: support@codiris.ai
MIT