API Reference
Complete TapKit API Reference
API Reference
TapKitElement
The <tap-kit> Web Component element.
API Summary
Lifecycle
| API | Description |
|---|---|
ready | Promise that resolves when initialization is complete |
isInitialized | Whether initialization is complete (boolean) |
UI Control
| API | Description |
|---|---|
show() | Show chat container |
hide() | Hide chat container |
isOpen | Chat open state (boolean) |
Course Information
| API | Description |
|---|---|
setCourse({ courseId, clipId, sectionId?, userId?, clipPlayHead? }) | Update course information |
setExternalReferenceId(id?) | Update external reference ID at runtime (pass undefined to clear) |
setExternalReferenceData(data?) | Update external reference data at runtime (pass undefined to clear) |
Host Context
| API | Description |
|---|---|
sendContext(contextType, payload) | Send context from host app to AI tutor |
Events (kit.events)
| API | Description |
|---|---|
seekTimeline({ clipPlayHead, clipId }) | Request timeline seek |
onTimelineSeek(callback) | Subscribe to timeline seek events, returns unsubscribe function |
onAlarmFadeIn(handler) | Subscribe to alarm display events, returns unsubscribe function |
Video (kit.video) (deprecated - use videoTarget instead)
| API | Description |
|---|---|
bind(config, clipId?) | Bind video player (timeline sync) |
unbind() | Unbind video player |
Properties
apiKey: string (write-only)
Security
Must be set via property only. Do not use as HTML attribute.
kit.apiKey = 'your-api-key'; // O
// <tap-kit api-key="..."> Don't useuserId: string
kit.userId = 'user-123';
// or <tap-kit user-id="user-123">courseId: string
kit.courseId = 'course-456';clipId: string
kit.clipId = 'clip-789';sectionId?: string
Section ID (identifier for a section within a course). Optional.
kit.sectionId = 'section-456';
// or <tap-kit section-id="section-456">clipPlayHead: number
Playback position in seconds.
kit.clipPlayHead = 100;externalReferenceId?: string
External reference ID assigned by an upstream system (e.g., LMS). Forwarded in the chat stream request body.
kit.externalReferenceId = 'ext-abc-123';
// or <tap-kit external-reference-id="ext-abc-123">userInputCode?: string
External reference data assigned by an upstream system (e.g., LMS). Forwarded in the chat stream request body.
kit.userInputCode = 'ext-data-123';
// or <tap-kit user-input-code="ext-data-123">rowDataForCodeEditor?: CodingRowData
Raw coding exercise metadata from a host LMS/platform. The SDK auto-extracts 5 required fields and attaches them to the chat stream request body. Additional fields on the object are ignored.
Property-only (set via JS property, not HTML attribute).
| Source field | → Chat stream body field |
|---|---|
language_id_nm | coding_language |
d_test_case | coding_testcase |
content | coding_content |
io_example | coding_example |
restriction | coding_restriction |
If rowDataForCodeEditor is provided, all 5 required fields must be non-empty strings — otherwise the SDK throws on init.
Automatic HTML entity decoding: during the chat stream build step, entity decoding is applied to all 5 fields (<p> → <p>). It is idempotent against raw-HTML input as well, so hosts can pass the value as-is regardless of input form.
kit.rowDataForCodeEditor = {
language_id_nm: 'C++ (GCC 9.2.0)',
d_test_case: '<p>...</p>',
content: 'Problem description...',
io_example: 'input: 1234 / output: 4S 0B',
restriction: '1s / 256MB',
// additional fields (grcode, sol_code, etc.) are ignored
};For host-side data flow and fetch patterns see Code Editor Integration - Fetching JSON from a Host API.
language: "ko" | "en" | "ja"
Language setting. Default is "ko".
kit.language = 'en';
// or <tap-kit language="en">mode: "inline" | "floating" | "sidebar"
Display mode. Default is "inline".
| Value | Description |
|---|---|
inline | Embed in page content (default) |
floating | Compact floating widget |
sidebar | Full-height sidebar on the right |
kit.mode = 'floating';
// or <tap-kit mode="sidebar">allowLayoutToggle: boolean
Whether to show the toggle button between floating ↔ sidebar modes. Default is true.
kit.allowLayoutToggle = false; // Hide layout toggle buttonvideoTarget: HTMLVideoElement | VideoPlayerAdapter
Declarative binding for video player synchronization. Recommended over video.bind().
// HTMLVideoElement
kit.videoTarget = document.querySelector('video');
// VideoPlayerAdapter (YouTube, Vimeo, etc.)
kit.videoTarget = {
getCurrentTime: () => player.getCurrentTime(),
setCurrentTime: (time, clipId) => player.seekTo(time), // clipId for cross-clip seeking (optional)
};videoTarget persists through lifecycle changes (mode changes, reconnections).
buttonId: string
Custom button element ID.
debug: boolean
Enable debug logging.
Static Properties
TapKit.version: string (read-only)
Returns the current SDK version.
console.log(TapKit.version); // "2.1.0"TapKit.buildEnv: string (read-only)
Returns the current build environment. ("prod", "staging", "dev", "demo")
console.log(TapKit.buildEnv); // "prod"Advanced Properties
The properties below are for testing/development environments. Not typically used in production.
apiUrl: string
Backend API URL. Used for staging/demo environment testing.
kit.apiUrl = 'https://tapapistaging.coxwave.link';tapUrl: string
iframe URL. For internal testing only, do not modify.
environment: "dev" | "prod" | "staging" | "demo"
Environment setting. Affects logging level and default URLs.
kit.environment = 'staging';root: HTMLElement (deprecated)
Deprecated
This property no longer affects positioning. In floating/sidebar modes, the container always renders to document.body.
// ❌ Don't use
kit.root = document.getElementById('chat-container');Read-only Properties
isOpen: boolean (read-only)
Check if chat is currently open.
isInitialized: boolean (read-only)
Check if SDK initialization is complete.
ready: Promise<void> (read-only)
Promise that resolves when SDK is ready.
await kit.ready;
kit.show();Methods
show(): void
Show the chat window.
hide(): void
Hide the chat window.
setCourse(course): void
Update course information.
interface SetCourseParams {
userId?: string;
courseId: string; // Required
clipId: string; // Required
sectionId?: string; // Optional
clipPlayHead?: number;
}kit.setCourse({
courseId: 'course-999',
clipId: 'clip-001',
clipPlayHead: 50
});setExternalReferenceId(id?): void
Update the external reference ID at runtime. Pass undefined to clear.
kit.setExternalReferenceId('ext-abc-123');
kit.setExternalReferenceId(undefined); // clearsetExternalReferenceData(data?): void
Update the external reference data at runtime. Pass undefined to clear.
kit.setExternalReferenceData('ext-data-123');
kit.setExternalReferenceData(undefined); // clearsendContext(contextType, payload): void
Send context information from the host application to the AI tutor. This is a generic API for passing any type of contextual data (quiz answers, reading progress, etc.).
| Parameter | Type | Description |
|---|---|---|
contextType | string | Context type identifier (e.g., 'passage:answer:submit') |
payload | Record<string, unknown> | Context data object |
kit.sendContext('passage:answer:submit', {
question: 'What is the main idea of the passage?',
selectedOptionId: 'A',
correctAnswer: 'B',
isCorrect: false,
});Events
tap-kit:ready
Fired when SDK initialization is complete.
kit.addEventListener('tap-kit:ready', () => {
console.log('TapKit is ready!');
});tap-kit:error
Fired when an error occurs during initialization.
kit.addEventListener('tap-kit:error', (e) => {
console.error('TapKit error:', e.detail.error);
});tap-kit:iframe-retry
Fired when retrying after iframe load failure.
interface IframeRetryEvent {
attempt: number; // Current retry count
error: Error; // The error that occurred
nextDelay: number; // Wait time until next retry (ms)
}kit.addEventListener('tap-kit:iframe-retry', (e) => {
console.log(`Retrying iframe... (attempt ${e.detail.attempt}, retry in ${e.detail.nextDelay}ms)`);
console.error('Error:', e.detail.error.message);
});kit.events
Event-related APIs.
kit.events.seekTimeline(params): void
Seek timeline to a specific position.
interface SeekTimelineParams {
clipPlayHead: number; // Position to seek (seconds)
clipId: string;
}kit.events.seekTimeline({ clipPlayHead: 100, clipId: 'clip-789' });kit.events.onTimelineSeek(handler): () => void
Listen for timeline seek events. Returns an unsubscribe function.
const unsubscribe = kit.events.onTimelineSeek((playHead, clipId) => {
console.log(`Seeking to ${playHead}s: ${clipId}`);
videoElement.currentTime = playHead;
});
// Unsubscribe
unsubscribe();kit.events.onAlarmFadeIn(handler): () => void
Listen for alarm arrival events.
const unsubscribe = kit.events.onAlarmFadeIn((alarm) => {
console.log('New alarm:', alarm.message);
});kit.video
Deprecated
The kit.video.bind() API is deprecated. Use the videoTarget property instead.
videoTarget is more stable as it automatically persists through lifecycle changes.
Video player synchronization API.
Why is video.bind important?
Using video.bind():
- AI tutor recognizes current playback position for accurate answers
- Auto-seek when clicking specific segments in chat
- Automatic new clipId tracking when calling
setCourse()
kit.video.bind(config, clipId?): void
Synchronize video player with TapKit.
| Parameter | Type | Required | Description |
|---|---|---|---|
config | HTMLVideoElement | VideoPlayerAdapter | Yes | Video element or custom adapter |
clipId | string | Auto-tracked from SDK settings if omitted |
interface VideoPlayerAdapter {
getCurrentTime: () => number;
setCurrentTime: (time: number, clipId?: string) => void; // clipId for cross-clip seeking
}Auto-tracking (recommended):
kit.video.bind(videoElement);
// When changing courses later, new clipId is automatically used
kit.setCourse({ courseId: 'new-course', clipId: 'new-clip' });Custom adapter (YouTube, etc.):
kit.video.bind({
getCurrentTime: () => player.getCurrentTime(),
// clipId is optional - used for cross-clip seeking
setCurrentTime: (time, clipId) => player.seekTo(time, true),
});kit.video.unbind(): void
Disconnect video player synchronization.
kit.video.unbind();createTapKit()
Factory API for programmatically creating and controlling <tap-kit> Web Component elements.
Available in both npm package and CDN.
- npm:
import { createTapKit } from '@coxwave/tap-kit' - CDN:
window.createTapKit(...)
For React projects, we recommend the useTapKit Hook.
Syntax
// npm package
import { createTapKit } from '@coxwave/tap-kit';
const tapkit = createTapKit(options);
tapkit.mount(); // Add to DOM (required)
await tapkit.ready; // Wait for initialization
tapkit.show(); // Show chat windowParameters
| Property | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | TapKit API key |
userId | string | User ID | |
courseId | string | Course ID | |
clipId | string | Clip ID | |
sectionId | string | Section ID (identifier for a section within a course) | |
clipPlayHead | number | Initial playback position (seconds) | |
externalReferenceId | string | External reference ID assigned by upstream system (forwarded in chat stream body) | |
userInputCode | string | External reference data assigned by upstream system (forwarded in chat stream body) | |
rowDataForCodeEditor | CodingRowData | Coding exercise metadata. Auto-extracts 5 required fields (language_id_nm, d_test_case, content, io_example, restriction) to chat stream body as coding_*. Throws on init if any required field is missing. | |
language | 'ko' | 'en' | 'ja' | Language setting | |
mode | 'inline' | 'floating' | 'sidebar' | Display mode (default: 'floating') | |
allowLayoutToggle | boolean | Allow floating↔sidebar toggle (default: true) | |
videoTarget | HTMLVideoElement | VideoPlayerAdapter | Video player binding | |
buttonId | string | Custom button element ID | |
debug | boolean | Enable debug logging |
Advanced Options (for testing/development):
| Property | Type | Description |
|---|---|---|
apiUrl | string | Backend API URL (e.g., 'https://tapapistaging.coxwave.link') |
tapUrl | string | iframe URL (internal testing only) |
environment | 'dev' | 'prod' | 'staging' | 'demo' | Environment setting |
Event Handlers:
| Property | Type | Description |
|---|---|---|
onReady | () => void | Called when SDK initialization is complete |
onError | (error: Error) => void | Called when an error occurs |
onTimelineSeek | (time: number, clipId: string) => void | Timeline seek event |
onAlarmFadeIn | (info: unknown) => void | Alarm display event |
Return Value: TapKitFactoryControl
| Property/Method | Type | Description |
|---|---|---|
ready | Promise<void> | Initialization complete promise |
isReady | boolean | Whether initialization is complete |
isOpen | boolean | Chat open state |
isMounted | boolean | Whether mounted to DOM |
mount(container?) | void | Add to DOM (required) |
unmount() | void | Remove from DOM |
show() | void | Show chat window |
hide() | void | Hide chat window |
setCourse(course) | void | Update course info |
setExternalReferenceId(id?) | void | Update external reference ID at runtime |
setExternalReferenceData(data?) | void | Update external reference data at runtime |
sendContext(contextType, payload) | void | Send host context to AI tutor |
events | EventManager | Events API |
video | VideoController | Video API |
element | TapKitElement | null | Access internal element |
destroy() | void | Clean up instance |
Example (npm package)
import { createTapKit } from '@coxwave/tap-kit';
const tapkit = createTapKit({
apiKey: 'your-api-key',
userId: 'user-123',
courseId: 'course-456',
clipId: 'clip-789',
// Environment settings (for testing)
apiUrl: 'https://tapapistaging.coxwave.link',
environment: 'staging',
// Event handlers
onReady: () => console.log('Ready!'),
onTimelineSeek: (time, clipId) => {
videoElement.currentTime = time;
},
});
// Add to DOM (required)
tapkit.mount();
// Or add to specific container
tapkit.mount(document.getElementById('chat-container'));
// Wait for initialization
await tapkit.ready;
// Show chat window
tapkit.show();
// Clean up
tapkit.destroy();Example (CDN)
<script src="https://files.edutap.ai/tap-sdk/loader.js"></script>
<script>
const kit = window.createTapKit({
apiKey: 'your-api-key',
userId: 'user-123',
courseId: 'course-456',
clipId: 'clip-789'
});
document.body.appendChild(kit);
kit.ready.then(() => kit.show());
</script>CSS Variables
For CSS variables for UI styling, see the Styling Guide.
TypeScript Types
TapKitConfig
Type for Legacy Class API (new TapKit()) constructor.
interface TapKitConfig {
apiKey: string;
}CreateTapKitOptions
Configuration type for createTapKit() and useTapKit() APIs.
interface CreateTapKitOptions {
// Required
apiKey: string;
// Course Information
userId?: string;
courseId?: string;
clipId?: string;
sectionId?: string;
clipPlayHead?: number;
externalReferenceId?: string;
userInputCode?: string;
rowDataForCodeEditor?: CodingRowData;
// Display Options
language?: 'ko' | 'en' | 'ja';
mode?: 'inline' | 'floating' | 'sidebar';
allowLayoutToggle?: boolean;
videoTarget?: HTMLVideoElement | VideoPlayerAdapter;
buttonId?: string;
debug?: boolean;
// Advanced Options (for testing/development)
apiUrl?: string;
tapUrl?: string;
environment?: 'dev' | 'prod' | 'staging' | 'demo';
// Event Handlers
onReady?: () => void;
onError?: (error: Error) => void;
onTimelineSeek?: (clipPlayHead: number, clipId: string) => void;
onAlarmFadeIn?: (messageInfo: AlarmMessageInstanceType) => void;
}TapKitElement
Type for the <tap-kit> Web Component element.
interface TapKitElement extends HTMLElement {
// Properties
apiKey: string;
userId?: string;
courseId?: string;
clipId?: string;
sectionId?: string;
clipPlayHead?: number;
externalReferenceId?: string;
userInputCode?: string;
rowDataForCodeEditor?: CodingRowData;
language?: 'ko' | 'en' | 'ja';
mode?: 'inline' | 'floating' | 'sidebar';
allowLayoutToggle: boolean;
videoTarget?: HTMLVideoElement | VideoPlayerAdapter;
buttonId?: string;
debug: boolean;
// Advanced Properties
apiUrl?: string;
tapUrl?: string;
environment?: 'dev' | 'prod' | 'staging' | 'demo';
/** @deprecated This property no longer affects positioning */
root?: HTMLElement;
// Read-only
readonly isOpen: boolean;
readonly isInitialized: boolean;
readonly ready: Promise<void>;
// Methods
show(): void;
hide(): void;
setCourse(params: SetCourseParams): void;
setExternalReferenceId(id?: string): void;
setExternalReferenceData(data?: string): void;
sendContext(contextType: string, payload: Record<string, unknown>): void;
// Sub-APIs
readonly events: {
seekTimeline(params: { clipPlayHead: number; clipId: string }): void;
onTimelineSeek(handler: (playHead: number, clipId: string) => void): () => void;
onAlarmFadeIn(handler: (messageInfo: AlarmMessageInstanceType) => void): () => void;
};
/** @deprecated Use videoTarget property instead */
readonly video: {
bind(config: HTMLVideoElement | VideoPlayerAdapter, clipId?: string): void;
unbind(): void;
};
}CodingRowData
Type for the rowDataForCodeEditor property. Host applications pass the raw LMS/platform JSON; the SDK extracts only the 5 required fields below and ignores additional fields.
interface CodingRowData {
language_id_nm: string; // → coding_language
d_test_case: string; // → coding_testcase
content: string; // → coding_content
io_example: string; // → coding_example
restriction: string; // → coding_restriction
[key: string]: unknown; // extra fields allowed (ignored by SDK)
}AlarmMessageInstanceType
Type for alarm message information.
interface AlarmMessageInstanceType {
type: 'basic:welcome' | 'basic:default' | 'feat:quiz' | 'feat:guide' | 'feat:progress' | 'custom:cheer';
content: AlarmElement;
}
interface AlarmElement {
tag: string;
props?: Record<string, unknown>;
children?: (AlarmElement | string)[];
payload?: {
type: 'startChat';
message: string;
pingMessageId?: string;
};
}VideoPlayerAdapter
Interface for custom video player (YouTube, Vimeo, Video.js, etc.) integration.
interface VideoPlayerAdapter {
/** Current playback time (seconds) */
getCurrentTime: () => number;
/**
* Set playback time
* @param time - Time to seek (seconds)
* @param clipId - Target clip ID for cross-clip seeking (optional)
*/
setCurrentTime: (time: number, clipId?: string) => void;
}
/** HTMLVideoElement or custom adapter */
type VideoPlayerConfig = HTMLVideoElement | VideoPlayerAdapter;TapButtonElement
The <tap-button> Web Component is a floating button for opening AI tutor chat.
Basic Usage
<!-- Use with TapKit (auto toggle) -->
<tap-kit user-id="user-123" course-id="course-456" clip-id="clip-789" section-id="section-456"></tap-kit>
<tap-button position="bottom-right" size="large"></tap-button>
<script>
const kit = document.querySelector('tap-kit');
kit.apiKey = 'your-api-key';
</script><tap-button> automatically connects with <tap-kit> on the same page, toggling the chat window when clicked.
Attributes
position: string
Specifies the button's screen position. Default is "bottom-right".
| Value | Description |
|---|---|
bottom-right | Bottom-right of screen (default) |
bottom-left | Bottom-left of screen |
top-right | Top-right of screen |
top-left | Top-left of screen |
custom | Custom position (specify with inline style) |
<tap-button position="bottom-left"></tap-button>
<!-- Custom position example -->
<tap-button position="custom" style="top: 100px; right: 50px;"></tap-button>size: string
Specifies button size. Default is "large".
| Value | Size |
|---|---|
small | 48px |
medium | 56px |
large | 64px (default) |
<tap-button size="small"></tap-button>floating: string
Sets positioning mode. Default is floating (fixed) mode.
| Value | Description |
|---|---|
| (omitted) | Floating mode (position: fixed) |
"false" | Static mode (normal document flow) |
<!-- Floating mode (default) -->
<tap-button></tap-button>
<!-- Static mode: placed like normal element -->
<tap-button floating="false"></tap-button>language: string
Sets tooltip language. Default is "ko".
<tap-button language="en"></tap-button>tutor-name: string
Tutor name to display in tooltip. Default text is shown if not set.
<tap-button tutor-name="AI Tutor"></tap-button>Custom Icon
Use slots to customize button content.
<tap-button position="bottom-right">
<img src="/my-tutor-icon.svg" alt="AI Tutor" />
</tap-button>CSS Shadow Parts
Provides CSS Shadow Parts for external styling.
tap-button::part(button) {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
border-radius: 50%;
}
tap-button::part(tooltip) {
background: #1f2937;
color: white;
}Events
tap-button:click
Fired when button is clicked. Chat toggles automatically if <tap-kit> is present.
const button = document.querySelector('tap-button');
button.addEventListener('tap-button:click', (e) => {
console.log('Button clicked', e.detail);
});