TikTok for Developers

Docs

TikTok Minis Player

Your app must use the official TikTok Minis player (VePlayer) to play reviewed mini drama episodes. This helps protect copyright safety and ensures a consistent playback experience. After your content passes review, your server prepares the required playback data, such as album_id, episode_id, vid, and a play credential, and your app uses VePlayer through the TikTok Minis SDK to render and control playback.

Note: Third-party players and native HTML video are not allowed. If they are used, TikTok will replace them with a default blocked UI. If you need support for gradual migration, submit a support ticket or contact your operations representative.

Integrate VePlayer

Follow these steps to integrate VePlayer into your mini app.

Step 1: Get the player

  1. Initialize the TikTok Minis SDK when the page loads.
  2. Obtain and cache the VePlayer constructor.

Parameters

TTMinis.getPlayer(channel) // channel: 'byteplus' | 'volcengine'. Returns Promise<typeof VePlayer>. Call init() first.

Example:

let VePlayerCtor = null;
TTMinis.getPlayer().then((VePlayerClass) => {
  VePlayerCtor = VePlayerClass;
});

Step 2: Prepare playback data

Get approved video information from your server. This includes:

Field

Meaning

Description

album_id

Drama ID

Identifies the drama or album being played

episode_id

Episode ID

Identifies the episode within the drama

vid

BytePlus video ID

Identifies the actual video stored in BytePlus. Learn more about managing media assets on BytePlus.

play_auth_token

Temporary play credential used for video playback on older versions of the app (TikTok versions below 44.5.0)

If a video has successfully passed content review, you can request this token via the relevant API endpoint. Note that this token is valid only for a limited duration; therefore, you should retrieve it only when you are certain that playback is required.

Step 3: Play video

Create player

Reserve a player container element on the playback page, and use the constructor of the player VePlayer obtained in the previous step to create the player as follows:

<div id="player-container-xx" style="width: 100%; height: 100%" />
const playerSdkIns = new VePlayer({
   id: 'player-container-xx', // The id of the player container element
   vid: 'sdsd3**33', // video id from BytePlus
   lang: 'en', // UI language
   albumId: videoInfo.album_id, // album id
   episodeId: videoInfo.episode_id, // episode id
   defaultDefinition: '720p', // default definition, If there is no need to transcode the video into multiple resolutions, it can be left unset.
   getVideoByToken: {
     playAuthToken: videoInfo.play_auth_token, // play temporary credential
   }
});

Each player instance must use a unique container. Make sure the container has the correct size through CSS.

If you use a framework such as React, you can also pass the corresponding root field through the HTMLElement object.

import { useEffect, useRef } from "react";
import * as React from "react";

export const PlayerComponent = (props) => {
  const rootRef = useRef(null);
  const playerSdkRef = useRef(null);

  useEffect(() => {
    const root = rootRef.current;
    if (!root) return;
    if (playerSdkRef.current) return;

    playerSdkRef.current = new VePlayer({
      root,
      vid: props.videoInfo.vid,
      albumId: props.videoInfo.album_id,
      episodeId: props.videoInfo.episode_id,
      getVideoByToken: {
        playAuthToken: props.videoInfo.play_auth_token,
      },
    });

    return () => {
      playerSdkRef.current?.destroy();
      playerSdkRef.current = null;
    };
  }, []);

  return React.createElement('div', { ref: rootRef, className: 'player-container' });
};

The player provides a rich set of UI plugins. Because mini dramas are immersive, choose a simpler configuration, for example:

const playerSdkIns = new VePlayer({
  id: 'player-container-xx', // player container id
  vid: 'sdsd3**33', // videovid
  lang: 'en', // UI language, support en、zh-cn、jp
  vid: videoData.vid, // video id
  albumId: videoData.albumId, // album id
  episodeId: videoData.episodeId, // episode id
  closeVideoClick: false, // Whether to toggle play/pause via video click/touchend behavior
  closeVideoDblclick: true, // Whether to toggle play/pause via video double click/touchend behavior
  videoFillMode: "fillWidth", // video fill mode
  getVideoByToken: {
    playAuthToken: videoData.playAuthToken, // play auth token
    needPoster: true, // whether to need poster
  },
  ignores: [
    "moreButtonPlugin", // more button plugin at the top right corner
    "enter", // enter plugin
    "fullscreen", // fullscreen plugin
    "volume", // volume plugin
    "play", // play plugin
    "pip", // picture in picture plugin
    "replay", // replay plugin
    "playbackrate", // playback rate plugin
    "sdkDefinitionPlugin", // definition plugin
  ],
  commonStyle: {
    playedColor: "#ffffff", // played color of the progress bar after playback is completed
  },
  mobile: {
    gradient: "none", // gradient of the container background in mobile
  },
  sdkErrorPlugin: {
    isNeedRefreshButton: false, // whether to need refresh button
  },
  start: {
    disableAnimate: true, // whether to disable animate
    isShowPause: true, // whether to show pause button
  },
});

Playback interface calls

  1. Playback control is provided by the player kernel.
playerSdkIns.on(VePlayer.Events.READY, () => {
  const player = playerSdk.player; // Obtain player kernel
  console.log('player core', player);
})

Note: The creation of the player kernel is an asynchronous process. Directly obtaining the kernel after the player is instantiated will not yield the kernel because the creation of the kernel has not yet completed. You can obtain the player kernel through the player property of the SDK instance after the SDK triggers an event (such as the ready event).

For more information, refer to the player kernel reference from BytePlus.

  1. Get the properties of the player kernel. For example, to get the current playback time:
const currentTime = playerSdkIns.player?.currentTime; // get current play time
const paused = playerSdkIns.player?.paused; // is paused
const ended = playerSdkIns.player?.ended; // is playing ended
  1. Call the methods of the player kernel. Taking the call of the play and pause methods as an example, the sample code is as follows:
const playBtn = document.getElementById('play_btn'); // call player.play() based on user action
playBtn.addEventListener('click', (e) => {
  playerSdkIns.player?.play();
});

const pauseBtn = document.getElementById('pause_btn'); // call player.pause() based on user action
pauseBtn.addEventListener('click', (e) => {
  playerSdkIns.player?.pause();
});
  1. Switch video: If you need to switch videos without destroying the player instance, you can call the playNext method and pass in the new video information.
playerSdkIns.playNext({
  albumId: nextVideoData.albumId,
  episodeId: nextVideoData.episodeId,
  vid: nextVideoData.vid,
  getVideoByToken: {
    playAuthToken: nextVideoData.playAuthToken, // play auth token
  },
}).then(() => {
  console.log('play next video completed');
});

Monitor playback status

The player provides a full event monitoring mechanism so you can implement playback-related features as needed.

  • Listen for playback errors:
playerSdkIns.on(VePlayer.Events.ERROR, (error) => {
  // error TODO
})
  • Listen and play
playerSdkIns.on(VePlayer.Events.PLAY, () => {
  // TODO after play
})
  • Listen for playback time updates:
playerSdkIns.on(VePlayer.Events.TIME_UPDATE, (data) => {
  const { currentTime } = data;
  console.log('currentTime: ', currentTime);
})

For more information, refer to the events reference from BytePlus.

Destroy player

Destroy the player instance after playback is complete and the player is no longer needed.

playerSdkIns.destroy();

VePlayer reference documents

Other relevant documents for the VePlayer are listed. License configuration is not required for TikTok Minis.

Acquire video playback token (for older client versions)

Invoke this API to retrieve a play credential used for video playback on older versions of the app (TikTok versions below 44.5.0).

Base info

HTTP URL

https://open.tiktokapis.com/v2/sg/shortdrama/play_token/

HTTP Method

GET

HTTP Header

Authorization : Bearer access_token

Request parameters

Field

Type

Description

Example

Required

client_key

string

Client unique identifier

mnxxxxxxx

Yes


episode_id


string

Episode ID

7234234123423421

Yes

Example

curl --location --request GET 'https://open.tiktokapis.com/v2/sg/shortdrama/play_token?client_key=mnxxxxxxxxxxxxx&episode_id=3453425324534' \
--header 'Authorization: Bearer xxxxx'

Response

Field

Type

Description

Example

play_auth_token

string

Video playback token

wasfasdfasdfasdfaasdfafasfastokenxasdfafasfa

Migrate from a third-party player

If you use a third-party player or native HTML video, TikTok will replace it with a default blocked UI. You can apply for an exemption to support gradual migration by submitting a support ticket or reaching out to your operations representative.

Before the exemption is available, if you need to customize the replaced UI elements, use the setValidateVideoReplaceElement API from the TikTok Minis SDK.

TTMinis.setValidateVideoReplaceElement(customReplaceElement: (
  videoEl: HTMLVideoElement,
  replaceReason: string,
) => HTMLElement | null)

External subtitles

After developers upload subtitles via the media library API, VePlayer supports automatically parsing the subtitle list from short drama media info and injecting it into the subtitle plugin for display, without the need to manually configure the subtitle list Subtitle.list.

Subtitle configuration is only used to control plugin behavior (such as isDefaultOpen, style, etc.), and the list field within it will be overridden by the automatically parsed results.

Through the formatAutoSubtitleItem callback, each subtitle item can be filtered, renamed, and sorted. Subtitle language tags (language / language_id) are automatically converted to native language names (for example, Simplified Chinese, English, 日本語).

Note:

  1. autoSubtitle depends on the Subtitle plugin. If Subtitle is not configured, the subtitle plugin will not be registered when new VePlayer is called, and subtitles will not be displayed.
  2. If subtitles in multiple languages are required, developers need to use the media asset library interface multiple times to upload subtitle files for each language.
new VePlayer({
  // ...
  autoSubtitle: true,
  Subtitle: {},       // Required: ensures the plugin is registered
});

Note: Subtitle.list does not need to be manually passed in. After enabling autoSubtitle, the player will automatically parse the subtitle list when retrieving media information, and write it to Subtitle.list after filtering, customizing, or sorting through formatAutoSubtitleItem.

The player provides a UI plugin for subtitle selection and corresponding APIs for controlling subtitle display.

Subtitle format support

WebVTT, SRT, ASS, and SSA (complex subtitle styles are not supported; only text content is displayed)

Initialization configuration

autoSubtitle

Property

Type

Default

autoSubtitle

boolean

false

When set to true, the player will automatically convert subtitle_info_list / SubtitleInfoList into a subtitle list and apply it to the subtitle plugin when media info is obtained.

formatAutoSubtitleItem

Property

Type

Default

formatAutoSubtitleItem

(item, index) => result

undefined

A formatting callback triggered before each subtitle item is generated, used for filtering, renaming, or adjusting order.

Callback Parameters:

Parameter

Type

Description

item

Record<string, any> | string

Raw subtitle item returned by the server

index

number

Index of the current item in the original list (starting from 0)

item Object Fields:

item comes from the server-side subtitle list data.

Field

Type

Description

subtitle_id

string

Subtitle ID

language

string

Subtitle language tag, e.g., cmn-Hans-CN, eng-US

language_id

number

Subtitle language ID, e.g., 1 (Simplified Chinese); used together with language for automatic language name conversion

format

string

Subtitle format, e.g., webvtt

subtitle_url

string

External subtitle file URL

source

string

Subtitle source, e.g., MT (Machine Translation)

status

string

Subtitle status, e.g., enable

title

string

Subtitle title; used as a name fallback when language mapping does not match

tag

string

Subtitle tag

file_id

string

File ID

store_uri

string

Storage URI

vid

string

Video ID

Example subtitle item:

{
  "file_id": "",
  "format": "webvtt",
  "language": "cmn-Hans-CN",
  "language_id": 1,
  "source": "MT",
  "status": "enable",
  "store_uri": "",
  "subtitle_id": "1857853977",
  "subtitle_url": "https://veplayer-vod-cdn.bytepluscdn.com/.../?X-Amz-...",
  "tag": "",
  "title": "",
  "vid": ""
}

Return Value Behavior:

Return Value

Behavior

string | number

Use this value as the subtitle display name

true | undefined

Pass through, keep the default parsed result

false | null

Filter out this subtitle, not shown in the list

{ label }

Use label as the subtitle display name

{ show: false } or { visible: false }

Filter out this subtitle

{ order: number }

Set sort weight; smaller values come first; can be used with label

{ isDefault: true } or { default: true }

Set this subtitle as the default selection; can be used with label and order

Subtitle

Top-level Configuration:

style Sub-configuration:

Property

Type

Default

Description

follow

boolean

true

Whether to adjust subtitle position along with the control bar

mode

'stroke' | 'bg'

'stroke'

Font display mode: stroke for outline, bg for solid background

followBottom

number

50

Height offset (px) when following the bottom control bar

fitVideo

boolean

true

Whether to auto-adjust font size based on the video frame

offsetBottom

number

4

Percentage of subtitle distance from the bottom of the video frame

baseSizeX

number

49

Base font size for landscape video

baseSizeY

number

28

Base font size for portrait video

minSize

number

16

Minimum font size on PC

minMobileSize

number

13

Minimum font size on mobile

line

'single' | 'double' | 'three'

'double'

Maximum number of display lines

fontColor

string

'#fff'

Font color, supports 16-bit color values or RGB values

list Item Structure (ISubTitleItem):

Property

Type

Description

id

string | number

Subtitle ID

language

string | number

Subtitle language tag

text / label

string | number

Subtitle display name

url

string

External subtitle URL

stringContent

string

Inline subtitle content (WebVTT / SRT text)

list

IListItem[]

Structured subtitle content list (used when not in URL form)

isDefault / default

boolean

Whether this is the default selected subtitle

Configuration example:

new VePlayer({
  autoSubtitle: true,
  Subtitle: {
    isDefaultOpen: true,
    isShowIcon: true,
    mode: 'external',
    style: {
      follow: true,
      mode: 'stroke',
      offsetBottom: 4,
      line: 'double',
      fontColor: '#fff',
    },
  },
});

Subtitle language name auto-conversion

When autoSubtitle parses subtitle items, it first looks up the built-in language mapping table via language_id (numeric) or language (language tag, e.g., cmn-Hans-CN), and converts it to the native name of that language for display.

language

language_id

Display Name

cmn-Hans-CN

1

简体中文

eng-US

2

English

jpn-JP

3

日本語

kor-KR

4

한국어

cmn-Hans-CN|eng-US

5

中英双语

rus-RU

6

Русский

fra-FR

7

Français

por-PT

8

Português

spa-ES

9

Español

vie-VN

10

Tiếng Việt

deu-DE

20

Deutsch

ita-IT

26

Italiano

cmn-Hant-CN

36

繁體中文

ara-SA

34

العربية

hin-IN

42

हिन्दी

For the complete language list, see BytePlus VOD Subtitle Language Documentation.

If the language tag or ID is not in the mapping table, it falls back to titlelabeltextlanguagetaglanguage_id raw value in order.

Usage Examples

Basic Usage

new VePlayer({
  vid: 'your_vid',
  getVideoByToken: { playAuthToken: 'your_token' },
  autoSubtitle: true,
  Subtitle: { isDefaultOpen: true },
});

Specify default language subtitle

When the player initializes, the subtitle plugin reads the item with isDefault: true (or default: true) as the default selected subtitle. If multiple subtitles are marked as default, only the first one takes effect; other marks are ignored.

Default Selection Rules (by priority):

  1. Specify the subtitle returned by formatAutoSubtitleItem as { isDefault: true } or { default: true }
  2. If none of the above is specified and Subtitle.isDefaultOpen is true (default value), the first subtitle in the list will be automatically selected.
new VePlayer({
  // ...
  autoSubtitle: true,
  formatAutoSubtitleItem: (item) => {
    // The English track is selected by default.
    if (item.language === 'eng-US') {
      return { isDefault: true };
    }
    return true;
  },
  Subtitle: { isDefaultOpen: true },
});

You can also combine sorting with default subtitle selection:

formatAutoSubtitleItem: (item, index) => {
  if (item.source === 'MT') return false;
  return {
    order: item.language === 'eng-US' ? 0 : index + 1,
    isDefault: item.language === 'eng-US',
  };
},

Default display system language subtitle

Automatically select the subtitle corresponding to the device's system language (navigator.language). The example below matches via language tag mapping (see the "Subtitle Language Name Auto-Conversion" section above for language tags). If multiple matches are found, only the first takes effect; if no match is found, it falls back to the default behavior of isDefaultOpen (auto-select the first subtitle).

// Mobile system language → Subtitle language label
const SYSTEM_LANG_TO_SUBTITLE_LANGUAGE = {
  'zh-hant': 'cmn-Hant-CN', // Traditional Chinese
  zh: 'cmn-Hans-CN',        // Simplified Chinese
  en: 'eng-US',
  ja: 'jpn-JP',
  ko: 'kor-KR',
  ru: 'rus-RU',
  fr: 'fra-FR',
  pt: 'por-PT',
  es: 'spa-ES',
  vi: 'vie-VN',
  de: 'deu-DE',
  it: 'ita-IT',
  ar: 'ara-SA',
  hi: 'hin-IN',
};

function getSystemSubtitleLanguage() {
  const lower = (navigator.language || navigator.languages?.[0] || '').toLowerCase();
  const iso = lower.split('-')[0];
  if (iso === 'zh') {
    const isHant = lower.includes('hant') || /\b(tw|hk|mo)\b/.test(lower);
    return SYSTEM_LANG_TO_SUBTITLE_LANGUAGE[isHant ? 'zh-hant' : 'zh'];
  }
  return SYSTEM_LANG_TO_SUBTITLE_LANGUAGE[iso] ?? null;
}

const systemSubtitleLanguage = getSystemSubtitleLanguage();

new VePlayer({
  // ...
  autoSubtitle: true,
  formatAutoSubtitleItem: (item) => {
    // The subtitle corresponding to the system language is set as the default selection (e.g., if the system is in Chinese, then Chinese is the default).
    if (
      systemSubtitleLanguage != null &&
      typeof item.language === 'string' &&
      item.language.toLowerCase() === systemSubtitleLanguage.toLowerCase()
    ) {
      return { isDefault: true };
    }
    return true;
  },
  Subtitle: { isDefaultOpen: true },
});

You can also use language_id matching instead (e.g., Number(item.language_id) === 1), the principle is the same.

Filter to SRT format only

new VePlayer({
  // ...
  autoSubtitle: true,
  formatAutoSubtitleItem: (item, index) => {
    if (typeof item === 'object' && item.format !== 'srt') return false;
    return { order: index };
  },
  Subtitle: { isDefaultOpen: true },
});

Custom subtitle names

new VePlayer({
  // ...
  autoSubtitle: true,
  formatAutoSubtitleItem: (item) => {
    return item.title || item.language;
  },
  Subtitle: {},
});

Filter specific source and custom sorting

new VePlayer({
  // ...
  autoSubtitle: true,
  formatAutoSubtitleItem: (item, index) => {
    // Filter out Machine Translation (MT) sources
    if (item.source === 'MT') return false;
    // ASR source is ranked at the top.
    return { order: item.source === 'ASR' ? 0 : index + 1 };
  },
  Subtitle: {},
});

Display only specific languages

new VePlayer({
  // ...
  autoSubtitle: true,
  formatAutoSubtitleItem: (item) => {
    const allowedLangs = ['cmn-Hans-CN', 'eng-US'];
    if (!allowedLangs.includes(item.language)) return null;
    return { label: item.title || item.language };
  },
  Subtitle: {},
});

Subtitle Control API

The following APIs can be called directly through the player instance without using the subtitle UI icon. Ensure the Subtitle plugin is registered (configured with Subtitle: {}) before calling.

getSubtitleList()

Get the current subtitle list.

const list = playerSdk.getSubtitleList();
// return examples:
// [
//   { id: 'sub-zh', language: 'cmn-Hans-CN', text: '简体中文', url: 'https://...' },
//   { id: 'sub-en', language: 'eng-US', text: 'English', url: 'https://...' },
// ]

Return Value

Type

Description

Subtitle list

ISubTitleItem[]

Returns [] when the plugin is not registered or the list is empty

switchSubtitle(subtitle)

Switch to a specified subtitle.

// Switch by ID
playerSdk.switchSubtitle({ id: 'sub-en' });

// Switch via language
playerSdk.switchSubtitle({ language: 'eng-US' });

Parameter

Type

Description

subtitle.id

string | number

Subtitle ID; either this or language is required

subtitle.language

string | number

Subtitle language tag

Returns Promise<void>; resolves on successful switch, rejects if the target subtitle is not found.

showSubtitle()

Enable subtitle display. Resumes the last selected subtitle; if none was selected, automatically selects the first one.

playerSdk.showSubtitle();

hideSubtitle()

Disable subtitle display. Subtitle data is retained and can be re-enabled via showSubtitle() or switchSubtitle().

playerSdk.hideSubtitle();

Comprehensive example

const playerSdk = new VePlayer({
  // ...
  autoSubtitle: true,
  Subtitle: { isDefaultOpen: false }, // Not displayed by default, manually controlled
});

// get subtitle list
const list = playerSdk.getSubtitleList();
console.log(list); // [{ id, language, text, ... }, ...]

// switch to english
await playerSdk.switchSubtitle({ language: 'eng-US' });

// hide subtitle
playerSdk.hideSubtitle();

// show subtitle
playerSdk.showSubtitle();

Preload for first frame optimization

Note: VePlayer preloading is used to download part of the target video's data in advance before actual playback, so that during actual playback, the pre-downloaded video data cache can be used for quick start, reducing the time to first frame and the waiting time for episode switching.

The short drama scene can directly pass the episode parameters into setPreloadList / addPreloadList , and the SDK will internally query the short drama video information and convert it into the resource data required for player preloading.

Note: This feature is a newly added one and does not affect applications that have historically integrated with the player.

Overview and working principle

Core idea of the VePlayer preloading module: Before the user actually clicks to play, download a portion of the target video's data to the memory cache in advance; when the user actually plays, the player directly reads data from the cache, skipping the network download phase, thereby significantly reducing the time to first frame and the waiting time for episode switching.

The working principle is shown in the figure below:

Compatibility description

Project

Support Status

Description

Encapsulation Format

MP4

Currently only MP4 resource preloading is supported

Playback Configuration

has enabled MSE capabilities

Player instantiation must pass in enableMp4MSE: true

Browser Environment

Environment supporting MSE

PC, Android H5, and iOS 17.1+ support ManagedMediaSource environment

Short video input parameters

Support

albumId / episodeId / vid will first be parsed into an MP4 URL and then enter the preloading queue

Quickstart

The following is the simplest runnable example to help you complete the basic preloading process within 30 seconds:

// 1. Initialize the preloading module
await VePlayer.prepare({
  strategies: { preload: true },
});

// 2. Set the preload list
await VePlayer.setPreloadList([
  {
    vid: "**********",
    albumId: "***********",
    episodeId: "********",
    defaultDefinition: "720p",
    getVideoByToken: { playAuthToken: "..." },
  },
]);

// 3. Create a player (MSE must be enabled)
const playerSdk = new VePlayer({
  id: video,
  vid: "**********",
  albumId: "***********",
  episodeId: "********",
  defaultDefinition: "720p",
  getVideoByToken: { playAuthToken: "..." },
  enableMp4MSE: true,
});

Initialization and configuration

Initialize the preloading module

Before calling setPreloadList / addPreloadList, you need to initialize the preloading module first:

await VePlayer.prepare({
  strategies: {
    preload: true,
  },
});

strategies.preload can be passed true to use the default configuration, or a configuration object can be passed in, for example, to set the default preloading scene, preloading duration, maximum cache count, etc.

strategies.preload Configuration Parameters

Parameter Name

Type

Default Value

Description

preloadScene

0 | 1

0

Preload scenarios.0 represents a normal scenario (preloading is manually executed);1 represents a Feed stream scenario (preloading is automatically executed by the player)

prevCount

number

1

Number of videos preloaded forward, only takes effect in the Feed stream scenario where preloadScene: 1 is set

nextCount

number

2

Number of videos preloaded backward, only takes effect in the Feed stream scenario where preloadScene: 1 is set

preloadTime

number

5

Preloading duration of a single video, unit: seconds

preloadMaxCacheCount

number

15

Maximum number of video caches; after exceeding, eviction follows the LRU strategy

disabled

boolean

false

Whether to disable preloading; When true the preloaded module will not be initialized

Preloaded resource format

Preloading short dramas only requires passing in the drama parameters:

const episode = {
  vid: "**********",
  albumId: "***********",
  episodeId: "********",
  defaultDefinition: "720p",
  getVideoByToken: {
    playAuthToken: "...",
  },
};

Field

Type

Description

Required

albumId

string

Short Drama ID

Yes

episodeId

string

Short drama episode ID, which is also part of the cache key for short drama video information

Yes

vid

string

Video ID; it is recommended to pass it in for easy querying and matching of video data. Please ensure that each video has a unique video vid

No

defaultDefinition

string

Preload target clarity, which is also part of the short drama video information cache key

No

getVideoByToken

IPlayAuthTokenConfig

Play Token configuration will be reused for short drama video information query

No

Media information cache

Tip: Recommended to enable: Linkage between media information caching and preloading. During preloading, short video information has been requested and cached in advance. When playing, directly reusing the cache can save the time consumed by interface requests, and only by cooperating with preloading can the first frame truly be optimized to the extreme.

Media information caching is turned off by default. After it is enabled, when querying short video information or obtaining media information via playAuthToken, the cache will be read first; if there is no hit, a request will be initiated, and valid results will be written to the cache.

VePlayer.setMediaInfoCacheConfig({
  enable: true
});

Supported configuration items are as follows:

Configuration Item

Type

Default Value

Description

enable

boolean

false

Whether to enable media information caching

cacheType

memory | localStorage

memory

Cache location;localStorage only outputs logs when writing fails, without affecting the preloading process

expireTime

number

1800000

Cache expiration time, in milliseconds; invalid values will be ignored. The actual expiration time will not be later than the expiration time of the playback URL

maxEntries

number

100

Maximum number of cached items; items will be evicted based on the most recent access time after exceeding this limit

Short video information cache is distinguished by episodeId + defaultDefinition for different episodes and definitions. To clear the cache, you can call:

VePlayer.clearMediaInfoCache();

Note: cacheType: localStorage is suitable for cross-page or persistent reuse of media information; if you only need to reuse within the current page, use the default memory.

Detailed explanation of preloading scenes

Scenario comparison and selection recommendations

Preloading switches the execution mode via setPreloadScene(scene, options), scene corresponds to the PreloadScene enumeration:

  • PreloadScene.NORMAL ( 0 ): Normal scene, manually perform preloading.
  • PreloadScene.FEED ( 1 ): Feed stream / Previous/Next episode switching scene, where the player automatically performs preloading.

The essential difference between the two scenarios lies in "who decides which videos to preload": in the normal scenario, the business explicitly specifies the resources to be loaded through setPreloadList / addPreloadList; in the Feed stream scenario, the player automatically locates based on the vid of the currently playing video in the ordered list, and schedules several episodes before and after according to prevCount / nextCount.

Dimension

Normal Scenario NORMAL (0)

Feed Stream Scenario FEED (1)

Trigger Mode

Manual: Immediately enter the preload queue after the business calls setPreloadList / addPreloadList

Automatic: Automatically detect and schedule when the player creates an instance or switches sets ( vid changes)

List Semantics

Resource collection to be preloaded, loaded upon invocation

Ordered playlist, retrieving previous and next videos in the list based on the current playback position

Scheduling Scope

Load as much as the business provides

Only load the first prevCount and the last nextCount videos of the current video

prevCount / nextCount

does not take effect

Effective (default 1 before, 2 after, prioritize loading subsequent videos)

Currently playing video

will not be preloaded (already playing)

will not be preloaded and only serve subsequent cuts

List maintenance cost

The business needs to decide on its own when to load which episodes

The business only needs to maintain a complete and ordered list, and the preloading of the cut set is managed by the player

Typical Entrance

Homepage / "Preheating" of exposure, hover, and near-click of the landing page card

Play the determined episode playback sequence within the play page

Switching scenes will clear the list of items to be loaded that have not yet entered the preloading queue (tasks already being loaded are not affected), preventing the manual list from being carried over into automatic mode and causing unexpected loading.

Selection Recommendations: For general scenarios, preheating the first episode before the playback page opens is suitable; for Feed stream scenarios, continuous episode chasing within the playback page is appropriate. In practice, the two are often used in combination (see "Linkage between Manual Preheating and Automatic Management" for details).

Manual Mode

Manual mode is suitable for explicitly adding preloading tasks for certain episodes before the playback page is opened, when the card is exposed, or when the user is about to click on a specific episode.

await VePlayer.prepare({
  strategies: { preload: true },
});

await VePlayer.setPreloadScene(0);

await VePlayer.setPreloadList([
  {
    vid,
    albumId,
    episodeId,
    defaultDefinition: "720p",
    getVideoByToken: { playAuthToken },
  },
]);

const playerSdk = new VePlayer({
  id: video,
  vid,
  albumId,
  episodeId,
  defaultDefinition: "720p",
  getVideoByToken: { playAuthToken },
  enableMp4MSE: true,
});

In Manual Mode:

  • setPreloadList(list) will replace the current preload list.
  • addPreloadList(list) will append new resources to be preloaded without clearing the existing list.
  • The player will not preload the video that is currently playing.
  • If you want the first video after instantiation to hit preloading, you need to allow sufficient download time before new VePlayer().

Auto Mode (Feed Stream)

Automatic mode is suitable for scenarios where there is already a defined playback sequence within the playback page. The business only needs to set a complete playlist, and the player will locate the current playing video based on its vid in the list and automatically select several videos before and after it to add to the preloading task.

How Feed Stream Scenarios Work

In the Feed stream scenario, the business only needs to set up a complete and ordered list, and the remaining scheduling is entrusted to the player. The behavior can be summarized as:

  • Select target by playback position: Based on the currently playing video, automatically select the previous prevCount and next nextCount episodes for preloading, and prioritize loading subsequent videos.
  • Does not compete for bandwidth with playback: Preloading will sense the current playback state and only proceed opportunistically when the current video is playing smoothly; when the current playback is laggy or the buffer is insufficient, it will automatically yield to prioritize ensuring the video being played.
  • Execute item by item: Preload tasks are executed serially, advancing with the playback progress to avoid saturating the network all at once.
  • Automatic Deduplication : Videos that are already in the cache, already in the queue, or currently playing will not be preloaded repeatedly; the currently playing video itself will not be preloaded either.

Therefore, the automatic mode eliminates the need for the business to manually maintain the next episode list after each episode switch, making it more suitable for continuous drama watching within the playback page.

await VePlayer.prepare({
  appId: 521173,
  strategies: { preload: true },
});

await VePlayer.setPreloadScene(1, {
  prevCount: 1,
  nextCount: 2,
});

await VePlayer.setPreloadList(episodeList);

const playerSdk = new VePlayer({
  id: video,
  vid: currentVid,
  albumId,
  episodeId: currentEpisodeId,
  defaultDefinition: "720p",
  getVideoByToken: { playAuthToken },
  enableMp4MSE: true,
});

In Automatic Mode:

  • setPreloadList(list) sets an ordered playlist, which should be consistent with the actual playback order of the feed stream videos.
  • If you need to add Tabular Data, use addPreloadList(list) .
  • Under the feed flow, try to keep only one player instance on the entire page, switch videos through playNext, or switch videos by destroying the old player and creating a new one.
  • The player will automatically select videos within the range of prevCount and nextCount for preloading based on the current position of the playing video.
  • When creating a player instance, switching videos, setting or adding to the preload list, a preload task check will be triggered.
  • The first video being played will not be automatically preloaded; the automatic mode mainly serves the subsequent episode-switching experience.

When slicing a set, video information that can match the preloaded list still needs to be passed in:

playerSdk.playNext({
  vid: nextVid,
  albumId,
  episodeId: nextEpisodeId,
  defaultDefinition: "720p",
  getVideoByToken: { playAuthToken },
  enableMp4MSE: true,
});

Connection between manual preheating and automatic hosting

The most common combined usage in practice: Use manual mode to preheat the first episode on the home page, and then switch to automatic mode to manage subsequent episode switching after entering the playback page.

From the home page to the playback page: Preheat the first episode in manual mode

  1. Call setPreloadScene(0) before card exposure, user hover, slide proximity, or click.
  2. Use setPreloadList or addPreloadList to add the first episode preloading task.
  3. When the user enters the playback page, if the first video has already been downloaded to the target duration, it can directly hit the preloaded data.

Switch from the preheating on the home page to the automatic mode on the playback page

VePlayer.preloader?.clearPreloadList();
VePlayer.preloader?.removeAllPreloadTask?.();

await VePlayer.setPreloadScene(1, {
  prevCount: 1,
  nextCount: 2,
});

await VePlayer.setPreloadList(episodeList);

Comparison with multi-instance player preloading

Another common preloading approach on the web ispreloading with multiple instance players: create a hidden player / <video> instance for each video to be loaded (set preload="auto" or directly load()), trigger the browser to download in advance, and then switch instances or replace src during playback. VePlayer's preloading does not rely on additional playback instances, but rather aglobal singleton preloading module downloads data to memory cache based on MSE, and directly reuses it to participate in playback when a hit occurs.

Dimension

Multi-instance Player Preloading

VePlayer Preloading (This Solution)

Resource Occupancy

One < video > /player instance per video to be loaded, occupying DOM, memory, decoder

Global singleton preloading module, no additional playback instances, only in-memory cached data

Concurrency Limit

Subject to the Concurrency Limit of browser media elements (especially on mobile devices / iOS, which typically only allows 1 stream of decoding)

Does not occupy the decoder and is not restricted by the Concurrency Limit of media elements

Download Granularity

The browser decides on its own, usually pulling data as needed, making it difficult to precisely control the download volume

Control the download duration according to preloadTime, download in segments by GOP/Range, and only pull the first segment

Cache Management

Each instance is independent, making it difficult to uniformly retire and reuse

Unified Cache + preloadMaxCacheCount LRU Eviction, Cross-Episode Reuse

Decoupled from Playback

Preloading requires an existing playback instance first

Decoupled from the playback instance, it can be preheated even when there is no player (such as on the home page)

Cut Set Scheduling

The business independently manages the creation/destruction and switching of multiple instances

The Feed stream scenario is automatically scheduled by the player according to prevCount / nextCount

Hit Metric

No unified hit caliber

Providesplayer.preLoadData and PRELOAD_INFO event quantitative hits

Bandwidth Competition

Simultaneous full downloads of multiple instances tend to preempt the bandwidth of the first screen

Only download the first segment required for starting playback, with controllable concurrency, reducing bandwidth competition

Advantages of this solution

  • Lightweight with No Additional Instances: Does not create redundant players / <video>, does not occupy the decoder, avoids the Concurrency Limit of media elements on mobile devices (especially iOS), and has significantly lower memory and performance overhead.
  • Controllable Download, Bandwidth Saving: According to preloadTime, only download the first segment (GOP/Range segment) required for starting playback, rather than the entire video, to avoid competing for bandwidth with the first-screen resources.
  • Unified Caching and Reuse: All preloaded data enters the unified cache, is evicted according to preloadMaxCacheCount LRU, reused across episodes and pages, and directly participates in the start-up after a hit to reduce the time to first frame.
  • Decoupled from Playback : The preloading module is a global singleton, which can preheat the first episode in advance when there are no playback instances (home page/landing page), and also supports automatic scheduling within the playback page according to the playback progress.
  • Scheduling and Hosting : In the Feed stream scenario, the player automatically maintains preloading of previous and next episodes based on the current vid , and the business does not need to manually manage the lifecycle of multiple instances.
  • Measurable: The hit situation can be quantified through player.preLoadData and PRELOAD_INFO events, facilitating the evaluation of benefits and parameter adjustment.

Hit monitoring and metrics

player.preLoadData

After starting playback, you can read preLoadData to check if the current player hits preloading:

playerSdk.on(VePlayer.Events.PLAY, (args) => {
  console.log(playerSdk.preLoadData);
  // { hit: 1, duration: 5.2, length: 413696 }
});

Field

Type

Description

hit

0 | 1

1 indicates that preloaded data is involved in the start of playback

duration

number

Preloading duration, unit: second

length

number

Preloaded data volume, unit: ByteDance

PRELOAD_INFO Event

This event is triggered when the player finds an available preloaded cache. It is recommended to combine with byteLength to determine whether there is actually available data.

playerSdk.on(VePlayer.Events.PRELOAD_INFO, data => {
  console.log([PRELOAD_INFO], data);
});

Task and data management

VePlayer.preloader provides interfaces for cleaning up preloaded data, canceling tasks, and resetting the list of items to be preloaded. The scope of action of the three is different, and it is recommended to choose according to the actual scenario.

API

Target Object

Do you want to interrupt the task that is being loaded?

Does it affect subsequent preloading tasks?

Typical Scenario

VePlayer.preloader.removeAll()

Downloaded preloaded data

No

No

Release cached preloaded data while retaining the ability to schedule subsequent tasks

VePlayer.preloader.removeAllPreloadTask()

Current task, list to be preloaded, task being loaded

Yes

Yes, the current task queue will be cleared

Leave the page, switch business scenarios, and switch from the home page preheating to the automatic mode of the playback page

VePlayer.preloader.clearPreloadList()

List of resources to be preloaded

No

Yes, the list to be preloaded will be cleared

Reset the preload list that is about to be executed, but do not remove the downloaded data

Clean up preloaded data

removeAll() will remove the preloaded data that has already been downloaded, without canceling subsequent preloading tasks or preventing new tasks from continuing to execute.

VePlayer.preloader?.removeAll();

Suitable for use when cache pressure is high, preloaded data needs to be released, but the current preloading strategy and subsequent task scheduling still need to be retained.

Cancel preloading task

removeAllPreloadTask() will cancel all preloading tasks, clear the preloading resource list, remove the current task list, and interrupt the currently loading task.

VePlayer.preloader?.removeAllPreloadTask?.();

Suitable for use when the page is destroyed, the business scenario is switched, or the current preloading behavior needs to be stopped immediately.

Empty the list to be preloaded

clearPreloadList() will clear all lists of resources to be preloaded, without removing the preloaded data that has already been downloaded, nor will it actively interrupt the currently ongoing loading tasks.

VePlayer.preloader?.clearPreloadList();

Suitable for cleaning up the old list before resetting setPreloadList , or for use when only wishing to stop subsequent list scheduling.

Notes

  • When instantiating the player, enableMp4MSE: true must be passed in; otherwise, preloaded data cannot be used.
  • defaultDefinition must be consistent with the actual playback resolution; otherwise, both the short video information cache and preload cache may fail to hit.
  • Preload hits require a download window.setPreloadList / addPreloadList When the interval between them and actual playback is too short, it may only create cache entries, but there are not enough bytes to participate in the start of playback.
  • If the video is incompatible due to issues such as non-transcoding, it will cause the player to degrade from MSE playback to native video playback, and in this case, preloaded cached data cannot be used for playback start.
  • It is not recommended to add preloading tasks for all episodes without limitation. In the short drama scenario, the number of tasks should be controlled based on user paths, click probabilities, and network conditions.
  • When switching pages or execution modes, old lists and necessary old tasks should be cleared to avoid network resource competition.

Best Practices

Within the playback page: Automode is preferred

The short drama playback page usually has a fixed playback sequence, such as from Episode 1 to Episode N. After entering the playback page, it is recommended to use the automatic mode:

  1. Initialize the preloading module.
  2. Call setPreloadScene(1, { prevCount, nextCount }) to switch to automatic mode.
  3. Call setPreloadList(episodeList) to set the complete or partial ordered list on the playback page.
  4. Create a player instance and ensure that the instantiation parameters include enableMp4MSE: true.

From the home page to the playback page: the first episode can be preheated using the manual mode

If you want the first video on the playback page to also hit preloading, you can use the manual mode in advance on the home page or landing page with episode cards:

  1. Call setPreloadScene(0) before card exposure, user hover, slide proximity, or click.
  2. Use setPreloadList or addPreloadList to add the first episode preloading task.
  3. When the user enters the playback page, if the first video has already been downloaded to the target duration, it can directly hit the preloaded data.

Recommended Configuration Reference

Scene

Recommended Configuration

Description

Homepage Preheat First Episode

preloadScene: 0preloadTime: 5

Manual mode preheats for 1 episode, and 5 seconds of data is sufficient to start broadcasting

Continuous drama watching on the playback page

preloadScene: 1prevCount: 1nextCount: 2

Automatic mode, 1 front and 2 rear, covering upper and lower sets

Media Information Cache

enable: truecacheType: memory

Recommended to enable, just reuse within the page


Was this document helpful?
TikTok for Developers