edutap.ai developers
SDK Integration

API Reference

Complete TapKit API Reference

API Reference

TapKitElement

The <tap-kit> Web Component element.

API Summary

Lifecycle

APIDescription
readyPromise that resolves when initialization is complete
isInitializedWhether initialization is complete (boolean)

UI Control

APIDescription
show()Show chat container
hide()Hide chat container
isOpenChat open state (boolean)

Course Information

APIDescription
setCourse({ courseId, clipId, userId?, clipPlayHead? })Update course information

Events (kit.events)

APIDescription
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)

APIDescription
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 use

userId: string

kit.userId = 'user-123';
// or <tap-kit user-id="user-123">

courseId: string

kit.courseId = 'course-456';

clipId: string

kit.clipId = 'clip-789';

clipPlayHead: number

Playback position in seconds.

kit.clipPlayHead = 100;

language: "ko" | "en"

Language setting. Default is "ko".

kit.language = 'en';
// or <tap-kit language="en">

mode: "inline" | "floating" | "sidebar"

Display mode. Default is "inline".

ValueDescription
inlineEmbed in page content (default)
floatingCompact floating widget
sidebarFull-height sidebar on the right
kit.mode = 'floating';
// or <tap-kit mode="sidebar">

allowLayoutToggle: boolean

Whether to show the toggle button between floatingsidebar modes. Default is true.

kit.allowLayoutToggle = false;  // Hide layout toggle button

videoTarget: 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
  clipPlayHead?: number;
}
kit.setCourse({
  courseId: 'course-999',
  clipId: 'clip-001',
  clipPlayHead: 50
});

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.

ParameterTypeRequiredDescription
configHTMLVideoElement | VideoPlayerAdapterYesVideo element or custom adapter
clipIdstringAuto-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 window

Parameters

PropertyTypeRequiredDescription
apiKeystringYesTapKit API key
userIdstringUser ID
courseIdstringCourse ID
clipIdstringClip ID
clipPlayHeadnumberInitial playback position (seconds)
language'ko' | 'en'Language setting
mode'inline' | 'floating' | 'sidebar'Display mode (default: 'floating')
allowLayoutTogglebooleanAllow floating↔sidebar toggle (default: true)
videoTargetHTMLVideoElement | VideoPlayerAdapterVideo player binding
buttonIdstringCustom button element ID
debugbooleanEnable debug logging

Advanced Options (for testing/development):

PropertyTypeDescription
apiUrlstringBackend API URL (e.g., 'https://tapapistaging.coxwave.link')
tapUrlstringiframe URL (internal testing only)
environment'dev' | 'prod' | 'staging' | 'demo'Environment setting

Event Handlers:

PropertyTypeDescription
onReady() => voidCalled when SDK initialization is complete
onError(error: Error) => voidCalled when an error occurs
onTimelineSeek(time: number, clipId: string) => voidTimeline seek event
onAlarmFadeIn(info: unknown) => voidAlarm display event

Return Value: TapKitFactoryControl

Property/MethodTypeDescription
readyPromise<void>Initialization complete promise
isReadybooleanWhether initialization is complete
isOpenbooleanChat open state
isMountedbooleanWhether mounted to DOM
mount(container?)voidAdd to DOM (required)
unmount()voidRemove from DOM
show()voidShow chat window
hide()voidHide chat window
setCourse(course)voidUpdate course info
eventsEventManagerEvents API
videoVideoControllerVideo API
elementTapKitElement | nullAccess internal element
destroy()voidClean 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;
  clipPlayHead?: number;

  // Display Options
  language?: 'ko' | 'en';
  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;
  clipPlayHead?: number;
  language?: 'ko' | 'en';
  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;

  // 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;
  };
}

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"></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".

ValueDescription
bottom-rightBottom-right of screen (default)
bottom-leftBottom-left of screen
top-rightTop-right of screen
top-leftTop-left of screen
customCustom 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".

ValueSize
small48px
medium56px
large64px (default)
<tap-button size="small"></tap-button>

floating: string

Sets positioning mode. Default is floating (fixed) mode.

ValueDescription
(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);
});

Next Steps