# tiktok-video

Video component that plays TikTok videos through the TikTok embed player

The [TikTok embed player](https://developers.tiktok.com/doc/embed-player) expects portrait video and won’t draw its chrome below 325×578, so the element starts at that size rather than the usual 300×150.

## Import

```bash
pnpm add @videojs/tiktok-video
```

```ts
import '@videojs/html/media/tiktok-video';
```

Or load it from the [CDN](https://videojs.org/docs/framework/html/guides/cdn):

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.0-rc.4/media/tiktok-video.js"></script>
```

## Load a source

`src` takes a TikTok video URL or a raw numeric video id. The `@user/video/<id>` URLs the app hands out, `share/video/<id>` links, and `player/v1/<id>` embed URLs all work.

```html
<tiktok-video src="https://www.tiktok.com/@_luwes/video/7527476667770522893"></tiktok-video>
```

## Controls

TikTok always draws part of its own chrome: the center play button, author header, and social rail are always visible. `controls` adds the progress bar and control buttons on top of those. Without `controls`, the element ignores pointer events, so a [player skin](https://videojs.org/docs/framework/html/guides/skins) above it receives every click.

## Deferred startup

TikTok builds its player lazily: until something starts playback, the embed has no video element, reports a duration of 0, and silently drops commands. The element works around this by starting a muted autoplay and pausing it immediately, so the embed answers play, pause, and seek before the first play.

Two settings opt out. `preload="none"` skips the warm-up, leaving the network untouched until the viewer presses play, and the controls inert until then. `controls` hands playback to TikTok’s own chrome instead.

## Behavior

- Mute works, but there’s no volume control: the embed reports a level but takes no command to set one.
- No playback rate and no text tracks; captions are toggled with `engine.tiktok.closed_caption`.
- `poster` and `playsInline` never reach the embed: it always plays inline and draws the video’s own cover image.
- Changing `controls` or `loop` after the embed is up rebuilds it; rewriting the iframe URL is the only reload TikTok allows.

## Examples

### Basic Usage

**index.html**

```html
<tiktok-video class="tiktok-video" src="https://www.tiktok.com/@_luwes/video/7527476667770522893" controls></tiktok-video>
```

**index.css**

```css
/* TikTok videos are portrait: the element floors itself at 325x578. */
.tiktok-video {
  display: block;
  width: 325px;
  height: 578px;
  margin-inline: auto;
}
```

**index.ts**

```ts
import '@videojs/html/media/tiktok-video';
```

## API Reference

### Attributes

These attributes configure the embedded media adapter:

| Attribute | Type | Default |
| --- | --- | --- |
| `autoplay` | `boolean` | `false` |
| `controls` | `boolean` | `false` |
| `loop` | `boolean` | `false` |
| `muted` | `boolean` | `false` |
| `playsinline` | `boolean` | `true` |
| `poster` | `string` | `''` |
| `preload` | `MediaPreloadType` | `'metadata'` |
| `src` | `string` | `''` |

### Properties

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `autoplay` | `boolean` | `false` | |
| `buffered` | `TimeRangeLike` | — | Read-only. |
| `controls` | `boolean` | `false` | |
| `currentSrc` | `string` | — | Read-only. |
| `currentTime` | `number` | — | |
| `defaultMuted` | `boolean` | `false` | |
| `duration` | `number` | — | Read-only. |
| `ended` | `boolean` | — | Read-only. |
| `engine` | `Window \| null` | — | Read-only. The embed's window. TikTok publishes no player object; commands are posted to the frame. Null until rendered. |
| `error` | `MediaError \| null` | — | Read-only. |
| `isFullscreen` | `boolean` | — | Read-only. |
| `loop` | `boolean` | `false` | |
| `muted` | `boolean` | `false` | |
| `paused` | `boolean` | — | Read-only. |
| `played` | `{ length: number; start(index: number): number; end(index: number): number }` | — | Read-only. |
| `playsInline` | `boolean` | `true` | |
| `poster` | `string` | `''` | |
| `preload` | `MediaPreloadType` | `'metadata'` | |
| `readyState` | `number` | — | Read-only. |
| `seekable` | `TimeRangeLike` | — | Read-only. |
| `seeking` | `boolean` | — | Read-only. |
| `source` | `{ src?: string; engine?: TikTokSourceEngineConfig } \| null` | `null` | TikTok URL or id in `src`, player params under `engine.tiktok`. Re-derives `src`; equal sources skip reload. |
| `src` | `string` | `''` | |
| `textTracks` | `TextTrackListLike` | — | Read-only. Always empty: `closed_caption` is the embed's only say over captions. |

### Engine options

#### `source.engine.tiktok`

Pass [TikTok player parameters](https://developers.tiktok.com/doc/embed-player) under `source.engine.tiktok`, spelled exactly as TikTok spells them, each one `0` or `1`, plus anything TikTok adds next. [Media Sources](https://videojs.org/docs/framework/html/guides/media-sources) covers how engine options fit into a structured source.

`autoplay`, `controls`, `loop`, and `muted` come from the props of the same name, so they have no `engine.tiktok` spelling.

```ts
const video = document.querySelector('tiktok-video');
video.source = {
  src: 'https://www.tiktok.com/@_luwes/video/7527476667770522893',
  engine: { tiktok: { closed_caption: 0, rel: 1 } },
};
```

| Option | Type | Description |
| --- | --- | --- |
| `closed_caption` | `0 \| 1 \| undefined` | Show the closed-caption button. Defaults to `1`. |
| `description` | `0 \| 1 \| undefined` | Show the video description. Defaults to `0`. |
| `fullscreen_button` | `0 \| 1 \| undefined` | Show the fullscreen button. Defaults to `1`. |
| `music_info` | `0 \| 1 \| undefined` | Show the track the video uses. Defaults to `0`. |
| `native_context_menu` | `0 \| 1 \| undefined` | Show the browser's native context menu. Defaults to `1`. |
| `play_button` | `0 \| 1 \| undefined` | Show the play button. Defaults to `1`. |
| `progress_bar` | `0 \| 1 \| undefined` | Show the progress bar. Defaults to `1`. |
| `referrerPolicy` | `ReferrerPolicy \| undefined` | `referrerpolicy` for the embed iframe. Not a TikTok player parameter. |
| `rel` | `0 \| 1 \| undefined` | Draw related videos from TikTok's recommendations (`1`) or the author's own videos (`0`). Defaults to `1`. |
| `timestamp` | `0 \| 1 \| undefined` | Show the current playback time and duration. Defaults to `1`. |
| `volume_control` | `0 \| 1 \| undefined` | Show the volume control. Defaults to `1`. |

### Methods

Supports these media methods: `exitFullscreen`, `load`, `pause`, `play`, `requestFullscreen`.

### Events

Implements these standard media events through the embedded player: `durationchange`, `emptied`, `ended`, `error`, `loadedmetadata`, `loadstart`, `pause`, `play`, `playing`, `seeked`, `seeking`, `timeupdate`, `volumechange`, `waiting`.

Also emits these Video.js-specific events:

| Event | Description |
| --- | --- |
| `loadcomplete` | |
| `sourcechange` | Fired when `source` changes, either directly or by resolving a new `src`. Read `source` for the new value. |

---

HTML documentation: https://videojs.org/docs/framework/html/llms.txt
All documentation: https://videojs.org/llms.txt
