> Public copy of the ViewStream developer guide (also for AI agents). All guides: https://www.viewstream.co.il/developers/guide/index.md · API reference: https://api.viewstream.co.il/docs/

# Player integration

How to put the ViewStream player (**Player v2** — Video.js 8 with ViewStream's skins and plugins) on your pages, pick a
player configuration, and listen to its events.

Sources: the loader player/site/embed.js, the player
player/site/lab/b/vs-vjs.js, the hosted pages
player/site/_hosted/, configuration documents
player-configs.md, and player/README.md.

## Three ways to embed

Studio builds all three for you: open a channel, clip or video and use **Embed & share (הטמעה ושיתוף)** — **Share
link (קישור לשיתוף)**, **Embed (iframe) (הטמעה (iframe))** and **Embed (player tag) (הטמעה (תגית נגן))**.

### 1. Share link — a hosted watch page

```
https://player.viewstream.co.il/w/<tenant>/<kind>/<id>[?start=<s>&lang=<xx>&config=<name>]
```

`kind` is `live` (id = channel slug), `vod` (id = asset id) or `clip` (id = clip id). The page carries social preview
tags, so the link unfurls in WhatsApp, Facebook and others.

### 2. iframe — the simplest embed

```html
<iframe src="https://player.viewstream.co.il/e/acme/live/main"
        allow="autoplay; fullscreen; picture-in-picture" allowfullscreen
        style="aspect-ratio:16/9;width:100%;border:0"></iframe>
```

Query options: `autoplay=1` (starts muted), `start=<seconds>` (not for live), `lang=he|en|ru|ar`, `config=<name>`.

### 3. Player tag — the player inside your page

```html
<script async src="https://player.viewstream.co.il/embed.js"
        data-src="https://cdn.acme.vustream.net/live/acme/main/master.m3u8"
        data-tenant="acme"
        data-config="news"
        data-lang="he"></script>
```

The player appears where the tag sits (or inside `data-target="<css selector>"`). The loader fetches everything else
(Video.js, skin, language, Chromecast, DRM support) from `player.viewstream.co.il`, once per page, even with several
players on the page.

Common attributes (all optional except a source):

| Attribute | Meaning |
|---|---|
| `data-src` | an HLS (`.m3u8`), DASH (`.mpd`) or MP4 URL |
| `data-tenant` | your tenant slug; otherwise taken from the URL (`/live/<tenant>/…`, `/vod/<tenant>/…`, or `?c=<tenant>`) |
| `data-config` | a named player configuration (see below); default = the configuration resolved for the content |
| `data-skin` | `classic`, `cinema`, `neon`, `glass`, `minimal`, `emoji`, `retro`, or any of the 100 library skin ids at `/skins/` |
| `data-lang` | `he`, `en`, `ru`, `ar` |
| `data-autoplay="1"` + `data-muted="1"` | autoplay (browsers allow it only muted) |
| `data-start`, `data-end` | seconds |
| `data-aspect` | e.g. `16:9` |
| `data-width` | maximum width in pixels |
| `data-resume` | `ask` (default), `auto`, `off` — continue where the viewer stopped (stored only in the viewer's browser) |
| `data-max-seek-back` | live: seconds the viewer may go behind live (`0` = live only) |
| `data-back-to-live="0"` | hide the back-to-live button |
| `data-restart="1"`, `data-restart-back` | a restart button on live channels without a guide |
| `data-cinema="1"` | cinema-mode button (desktop) |
| `data-mode="tile"` | a muted preview tile instead of a full player |
| `data-options` | JSON for lists and objects (`sources`, `tracks`, `chapters`, `thumbnails`, `ads`, `drm`, `configDoc`) |

The full list is the comment at the top of embed.js (loader version 1.3.0).

### Protected streams

When a playback policy requires tokens, the player asks the public issuer (`POST /v1/playback/session`) for a signed
URL by itself and re-issues when a token expires. If you sign in your own backend instead, pass the signed `src` from
`POST /v1/playback/tokens` as `data-src` ([recipes.md](recipes.md#get-a-playback-url-or-a-signed-token)).
`embed.allowed_domains` in the configuration limits which sites may embed.

## Player configurations

A configuration is a JSON document edited in Studio → **Players (נגנים)**: skin, theme, language, branding and logo,
controls, playback defaults, the live EPG overlay, ads, beacons, tile settings, allowed domains.

| URL (public, no key, CORS `*`, cached 60 s, `ETag`) | What |
|---|---|
| `https://player.viewstream.co.il/player/config/<tenant>.json` | the tenant default |
| `https://player.viewstream.co.il/player/config/<tenant>/<name>.json` | a named configuration |
| `https://player.viewstream.co.il/player/config/<tenant>/resolve.json?kind=live\|vod\|clip&id=<…>` | the configuration that applies to that content (by assignment: channel → live default → tenant; asset → section → library default → tenant), plus `resolved_from` and the content's title metadata |

The same paths answer on `api.viewstream.co.il`. A change in Studio reaches viewers within about a minute. CDN-only
tenants and unknown names answer `404` (the player then uses its built-in defaults).

Precedence inside the player: attributes on the page > the configuration document > built-in defaults.

Manage configurations over the API: `GET/POST /v1/player-configs`, `GET/PATCH/DELETE /v1/player-configs/{id}`
(read `assets:read`, write `delivery:write`), and where they apply: `/v1/player-config-assignments`. All keys and
defaults: player-configs.md.

## Events

Listen on the player box (the element the player was placed in, or any ancestor — the events bubble):

| DOM event | `detail` | When |
|---|---|---|
| `vs:ready` | `{player, engine}` (`engine` is `b` = Player v2, or `tile`) | the player is created |
| `vs:error` | `{error}` | the loader failed (bad JSON in `data-options`, missing target, a file did not load) |
| `vs:config` | `{theme, config}` | the resolved configuration is applied — theme your page from it |
| `vs:cinema` | `{on}` | cinema mode toggled (your page lays itself out; or style `html.vs-cinema-on`) |

```html
<script>
document.addEventListener('vs:ready', function (e) {
  var player = e.detail.player;          // a Video.js player
  player.on('vsqualitychange', function () { /* … */ });
  player.on('vsdeny', function (ev) { console.log('denied', ev); });
});
</script>
```

`e.detail.player` is a Video.js player: all standard Video.js events (`play`, `pause`, `ended`, `timeupdate`, …) work.
ViewStream adds, among others: `vsqualitychange`, `vscaptionchange`, `vsskinchange`, `vsthemechange`, `vscast`,
`vsstatschange`, `vsmenuopen`, `vsdeny` (the CDN refused playback — token, geo, blackout…), `vstokenrefresh`,
`vsreconnect`, `vsstallskip`, `vspathway` (multi-CDN switch `{from, to, reason}`), `vsdrmunavailable`, and the ad
events `adstart`, `adend`, `adskip`, `adclick`, `quartile`. These names come from the code
(vs-vjs.js); their payloads are not a frozen contract yet.

`window.VSEmbed` holds `{version, players}` for every player the loader created on the page.

## Viewing statistics (beacons)

The player reports viewing to `https://<your cdn_hostname>/b/v1` (fetch keep-alive, `sendBeacon` on unload) when the
configuration's `beacon.enabled` is on (default); heartbeat every `beacon.heartbeat_s` seconds (5–120, default 15)
(vs-beacon.js). These beacons feed Studio → Analytics and the `/v1/stats`
API. Only a hashed anonymous viewer id is used, and none without consent.

## Sites SDK and web components

For tiles, rails and a `<vs-player>` element in your own site: `@viewstream/sites-wc` at
`https://player.viewstream.co.il/sdk/sites-wc@0.2.4.js` (demo `/sdk/demo.html`, docs
studio/packages/sites-wc/README.md). It reads the
[Sites Delivery API](sites-delivery-api.md).

## Status of player features

| Feature | Status |
|---|---|
| HLS / LL-HLS live, DVR, start-over, catch-up, EPG overlay | live |
| Client-side ads (VAST/VMAP, in-house engine or IMA), house pre-roll | live |
| Server-side ad insertion (SSAI) | built, **off by default** (platform switch) |
| AES-128 encrypted VOD | live |
| FairPlay / Widevine DRM | **pending** — needs the DRM vendor account (work report §54) |
| Chromecast | live (Chromium browsers, not iOS) |
