# MediaMelon JS Custom Multi-Player SDK Integration Document

**Step 1:** [Add MediaMelon Player SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Instantiate and Register SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Initialize Playback Session](#step-3-initialize-playback-session)

**Step 4:** [Custom Metadata](#step-4-custom-metadata)

**Step 5:** [Stream and Network Information](#step-5-stream-and-network-information)

**Step 6:** [Chunk/Segment Information](#step-6-chunk-segment-information)

**Step 7:** [Player Events](#step-7-player-events)

**Step 8:** [Fallback & Request Status](#step-8-fallback-and-request-status)

**Step 9:** [Ad Data & Ad Events](#step-9-a-d-data-and-ad-events)

**Step 10:** [Custom Events](#step-10-custom-events)

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

* **NPM (2.1.0):**

```bash
npm i mediamelon-js-custom-sdk
```

```javascript
import { mmJSCustomAdapter, MMPlayerState, RenditionInfo, RequestStatus} from 'mediamelon-js-custom-sdk'
```

### **Step 2:** Instantiate and Register SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Instantiate and Report Registration Information:

```javascript
var mmJSPlugin = new mmJSCustomAdapter();
mmJSPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean Value
);
```

{% hint style="info" %}
`hashSubscriberId`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmJSPlugin.reportPlayerId("PLAYER_ID");
mmJSPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmJSPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmJSPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmJSPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Device Information:

```javascript
var deviceInfo = {
    "deviceName": "DEVICE_NAME",
    "deviceBrand": "DEVICE_BRAND",      // Device Brand or Manufacturer
    "deviceModel": "DEVICE_MODEL",
    "deviceId": "DEVICE_ID",
    "deviceOS": "DEVICE_OS",
    "deviceOSVersion": "DEVICE_OS_VERSION",            
    "screenWidth": screen_width,        //Integer Value
    "screenHeight": screen_height       //Integer Value
};
mmJSPlugin.reportDeviceInfo(deviceInfo);
```

#### Step 2.5: Report Sub Property ID:

```javascript
mmJSPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

### Step 3: Initialize Playback Session

#### Step 3.1: Initialize Session with Content Metadata:

```javascript
var contentMetaData = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "drmLevel": "DRM_LEVEL",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE",
    "videoType": "VIDEO_TYPE"
};

mmJSPlugin.initializeSession(contentMetaData, "STREAM_URL");
```

{% hint style="warning" %}
All metadata fields set from **Step 3** will be reset when `initializeSession` is called. Therefore, ensure that all session-specific metadata, such as `view session ID`, `preload`, and similar fields, are reported after `initializeSession` is called for every playback session.
{% endhint %}

#### Step 3.2: Report View Session ID:

```javascript
mmJSPlugin.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 3.3: Report Experiment Name:

```javascript
mmJSPlugin.reportExperimentName("EXPERIMENT_NAME");
```

#### Step 3.4: Report Preload:

```javascript
mmJSPlugin.reportPreload(<boolean>);
```

#### Step 3.5: Report Player Resolution:

```javascript
mmJSPlugin.reportPlayerResolution(width, height);
```

#### Step 3.6: Report User-Initiated Playback:

{% hint style="info" %}
This function indicates the intent for playback and must be invoked after `initializeSession`. Any metadata fields reported before this API call will be included in the first payload sent to the dashboard. To avoid `Null` values in metadata fields, it is recommended to report all available metadata before calling this API.
{% endhint %}

```javascript
mmJSPlugin.reportUserInitiatedPlayback();
```

### Step 4: Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```javascript
mmJSPlugin.reportCustomMetadata("custom_1", "value1");
mmJSPlugin.reportCustomMetadata("custom_2", "value2");
```

### Step 5: Stream and Network Information

#### Step 5.1: Report Stream Information:

```javascript
mmJSPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 5.2: Update Stream URL:

```javascript
mmJSPlugin.updateStreamURL("STREAM_URL");
```

#### Step 5.3: Report Presentation Info:

```javascript
mmJSPlugin.reportPresentationInfo(<is_live>, <video_duration>);
```

{% hint style="info" %}

* `is_live`: Set to `true` for live video stream and to `false` for the VOD stream.
* `video_duration`: Integer value in milliseconds.
  {% endhint %}

#### Step 5.4: Report Track Information

Call this API with initial values, and every time there is a change in the track info. Call this API when the user enables/disables subtitles or when the user changes the audio track.

```javascript
mmJSPlugin.reportTrackinfo(<is_subtitle_active>, "SUBTITLE_TRACK", "AUDIO_TRACK", <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 5.5: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```javascript
var renditionInfo = new RenditionInfo();
rendition.bitrate = <birate>;            //Integr Value in bps
rendition.width = <width>;               //Integr Value
rendition.height = <height>;             //Integer Value
rendition.frameRate = <frame_rate>;      //Integr Value in fps
rendition.aCodec = "AUDIO_CODEC";
rendition.vCodec = "VIDEO_CODEC";

mmJSPlugin.reportRendition(renditionInfo);
```

#### Step 5.6: Update DRM Type:

{% hint style="danger" %}
`updateDrmType(drmType:)` is **deprecated**. A new API called `updateDRM(drmProtection:, drmLevel:)` is introduced.
{% endhint %}

```javascript
mmJSPlugin.updateDRM("DRM_PROTECTION", "DRM_LEVEL");
```

#### Step 5.7: Report Network Information:

```javascript
var networkInfo = {
    "cdn": "CDN",
    "asn": asn,                     //Integer Value
    "hostName": "SOURCE_HOST_NAME",
    "networkType": "NETWORK_TYPE",  // Network Connection Type
    "networkOperator": "NETWORK_OPERATOR"
}
mmJSPlugin.reportNetworkInfo(networkInfo);
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 5.8: Report CDN Information:

```javascript
mmJSPlugin.reportCDN("CDN");
```

#### Step 5.9: Report Encoding Service:

```javascript
mmJSPlugin.reportEncodingService("ENCODING_SERVICE");
```

### Step 6: Chunk/Segment Information

#### Step 6.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```javascript
mmJSPlugin.reportDownloadRate(downloadRate);    //Integer Value in bps (bits per second
```

### Step 7: Player Events

#### Step 7.1: Report Player State:

```javascript
mmJSPlugin.reportPlayerState(MMPlayerState.PLAYING);

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 7.2: Report Buffering:

```javascript
mmJSPlugin.reportBufferingStarted();
mmJSPlugin.reportBufferingCompleted();
```

#### Step 7.3: Report Seek:

```javascript
mmJSPlugin.reportPlayerSeekStarted(); 
mmJSPlugin.reportPlayerSeekCompleted(seekEndPositionInMS); //Integer Value in Milli Seconds
```

#### Step 7.4: Report Error:

```javascript
mmJSPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 7.5: Report Warning:

```javascript
mmJSPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

#### Step 7.6: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```javascript
mmJSPlugin.reportPlaybackPosition(playback_position); //Integer Value in Milli Seconds
```

#### Step 7.7: Report Player Resolution:

```javascript
```

### Step 8: Fallback & Request Status

#### Step 8.1: Report Fallback Event:

```javascript
mmJSPlugin.reportFallbackEvent("FALLBACK_MANIFEST_URL", "DESCRIPTION");
```

#### Step 8.2: Report Request Status:

```javascript
var requestInfo = {
    id: "ID",
    error: "ERROR",
    text: "TEXT",
    hostname: "HOSTNAME",
    url: "URL",
    ...
}

mmJSPlugin.reportRequestStatus(RequestStatus.FAILED, "REQUEST_TYPE", requestInfo);

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 9: Ad Data & Ad Events

#### Step 9.1: Report Ad Break Start & End:

```javascript
mmJSPlugin.reportAdBreakStart();
mmJSPlugin.reportAdBreakEnd();
```

#### Step 9.2: Report Ad Data, Ad Start & End:

```javascript
var adInfo = {
    "adTitle": "AD_TITLE",
    "adId": "AD_ID",
    "adUniversalId": "AD_UNIVERSAL_ID",
    "adCreativeId": "AD_CREATIVE_ID",
    "adCreativeType": "AD_CREATIVE_TYPE",
    "adClient": "AD_CLIENT",
    "adPosition": "AD_POSITION",               //pre, mid, post
    "adServer": "AD_SERVER",
    "adResolution": "AD_RESOLUTION",
    "adUrl": "AD_URL",
    "adDuration": ad_duration,              //Double Value
    "adPodIndex": pod_index,                //Integer Value
    "adPositionInPod": ad_position_in_pod,  //Integer Value
    "isBumper": is_bumper                   //Boolean Value
}

mmJSPlugin.reportAdStart(adInfo);
mmJSPlugin.reportAdEnd();
```

<details>

<summary>AdInfo Object description</summary>

<table data-header-hidden><thead><tr><th width="198.04296875">Field</th><th width="116.59375">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 9.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```javascript
mmJSPlugin.reportAdBufferingStrated();
mmJSPlugin.reportAdBufferingCompleted();
```

### Step 10: Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```javascript
mmJSPlugin.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 35 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v2.1.0[^1]

* Added support for multiple player instances within a single application.
* Added the following new metadata fields:
  * **Player ID** - report it using `reportPlayerId`.
  * **DRM Level** - report it as part of Content Metadata.
  * **Ad Universal ID** - report it as part of Ad Info.
* `updateDRMType(drmType)` → **Deprecated**
  * Use `updateDRM(drmProtection, drmLevel)` (refer to [Step 5.6](#step-5.6-update-drm-type))
* Buffering events exceeding the stats interval are now included in the stats payload.
* Updated **metadata lifecycle handling**:
  * [Step 2](#step-2-register-and-initialize-mediamelon-sdk) metadata fields persist across the SDK instance lifecycle.
  * All Metadata fields from [Step 3](#step-3-initialize-playback-session) are reset for every playback session.

</details>

***

<details>

<summary>Previous Releases</summary>

#### [Non-Multiplayer Releases](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/web/mediamelon-js-custom-sdk-integration-document#release-notes)

</details>

[^1]: **Release Date:** April 30, 2026

    **Performance Report:** [here](https://docs.mediamelon.com/mediamelon-sdk-performance-metrics/apple/apple-custom-multi-player-sdk-performance-metrics)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/web/mediamelon-js-custom-multi-player-sdk-integration-document.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
