Upstream: jwplayer/ott-web-app, branched from the
releasebranch at v6.11.0 for a reproducible foundation. Everything below this section is the original project README.
This fork instruments the JW Player OTT Web App with Bitmovin Observability
using the player-agnostic HTMLVideoElementAdapter (element-level collector).
(Bitmovin's product is named Observability; the collector package and its APIs
retain the legacy analytics naming, which is preserved wherever code is
referenced.) It demonstrates that Bitmovin's observability pipeline can observe
playback on a third-party player with no dedicated adapter — sessions, QoE
metrics, persistent viewer identity, and failure detection — and documents
precisely where the element-level approach hits its fidelity ceiling versus the
Bitmovin Player's integrated analytics. See FINDINGS.md for
the technical write-up.
- Observability integration (
packages/ui-react/src/components/Player/Player.tsx): attaches the Bitmovin collector to the<video>element JW Player renders, on the player'sreadyevent. SPA title navigation is handled via the adapter'ssourceChange()API so each title reports as its own session under its ownvideoId. - Persistent viewer identity: a localStorage-backed
customUserId(viewer-XXXXX) so one browser accumulates a session history like a real logged-in subscriber. Different browser profiles act as different viewers. - Env plumbing:
APP_BITMOVIN_ANALYTICS_KEYwired through the app's three-step env pipeline (.env→index.tsxconfigureEnv→env.ts). - Failure injection: append
&chaos=manifestto any watch URL to force a fatal playback failure on demand (the source list is reduced to a single broken progressive URL — see FINDINGS.md for why manifest-only corruption is silently rescued by JW's source failover). - Traffic generator (
bots/): a Playwright script that runs staggered headless viewing sessions against the local app, each with a distinct viewer identity, producing realistic audience and completion distributions in the dashboard. Uses the brandedchromechannel (H.264 support) with autoplay enabled.
yarn # release branch uses yarn classic, NOT pnpm
# add your key to platforms/web/.env:
# APP_BITMOVIN_ANALYTICS_KEY=<your Observability license key>
# (dashboard: Observability -> Licenses -> select license -> "Observability Key")
yarn web start # http://localhost:8080localhost is allowed by default on web licenses. If you deploy elsewhere,
add the domain under Observability → Licenses → select the license → "Domains /
Package Names / Bundle Identifiers". The same license page holds the Time Zone
setting (see FINDINGS.md §4 before trusting it) and the impressions quota.
Play any title and the session appears in the Bitmovin dashboard (Observability → Sessions) within a couple of minutes.
Bots: node bots/smoke.mjs to verify the environment, then
node bots/viewers.mjs with the dev server running. Start with ~15 sessions;
each bot is a full Chrome instance. Note that trial licenses meter
impressions (e.g., 5,000 on the default license — visible on the license
page), and every bot session consumes them, so size bot runs with the quota
in mind.
Failure demo: copy a working watch URL and append &chaos=manifest
(note &, not a second ?). The same title plays cleanly without the param —
useful for a healthy/broken side-by-side.
- Errors originating in JW's player layer (e.g., manifest fetch failures over MSE) are invisible to the element-level collector; forced failures are detected but may ship without an error code due to element teardown races.
- The adapter has no public destroy; on SPA navigation its listeners persist until the video element is torn down.
- Bot traffic originates from one machine, so geo views will cluster on a single location.
These limitations are the demonstration: they map exactly to what the
Bitmovin Player's integrated analytics adds.

The JW OTT Webapp is an open-source, dynamically generated video website built around JW Player and JW Platform services. It enables you to easily publish your JW Player-hosted video content with no coding and minimal configuration.
Examples of JW OTT Webapp in action:
- Free Content + Live + EPG
- Ad-based Monetization
- Subscription-based Monetization
- Authentication-based Access
- Right Rail Page Layout (Inline Player)
Examples built using the JW OTT Webapp
|
Symphony
|
FansChoice.tv
|
Trinity Broadcasting Network
|
- Configure JW OTT Webapp
- Configure Translations
- Contributing Guidelines
- Frameworks, SDKs and Libraries
- Backend Services
- Developer Guidelines
- Workspaces
- Works with any JW Player edition, from Free to Enterprise (note that usage will count against your monthly JW streaming limits). Only cloud-hosted JW Players are supported.
- It looks great on any device. The responsive UI automatically optimizes itself for desktop, tablet, and mobile screens.
- Populates your site's media content using JSON feeds. If you are using JW Platform, this happens auto-magically based on playlists that you specify. Using feeds from other sources will require you to hack the source code.
- Video titles, descriptions and hero images are populated from JW Platform JSON feed metadata.
- Playback of HLS video content from the JW Platform CDN. You can add external URLs (for example, URLS from your own
server or CDN) to your playlists in the Content section of your JW Player account dashboard, but they must be HLS
streams (
.m3u8files). - Support for live video streams (must be registered as external .m3u8 URLs in your JW Dashboard).
- Customize the user interface with your own branding. The default app is configured for JW Player branding and content,
but you can easily change this to use your own assets by modifying the
config.jsonfile. Advanced customization is possible (for example, editing the CSS files), but you will need to modify the source code and build from source. - Site-wide video search and related video recommendations powered by JW Recommendations.
- Basic playback analytics is reported to your JW Dashboard.
- Ad integrations (VAST, VPAID, GoogleIMA, etc.). These features require a JW Player Ads Edition license. For more information, see the JW Player pricing page.
- A "Favorites" feature for users to save videos for watching later. A separate list for "Continue Watching" is also
kept so users can resume watching videos from where they left off. The lists are per-browser at this time (i.e., lists
do not sync across user's browsers or devices). The "Continue Watching" list can be disabled in your JW OTT
Webapp's
config.jsonfile. - A grid view for a particular playlist of videos, with the ability to deep-link to the playlist through a static URL.
- Social sharing options using the device native sharing dialog.
- 24x7 live channel(s) screen with Electronic Programming Guide (EPG) view.
- Self-hosted JW Players
The easiest way to get the OTT Web App running on your machine, use the following commands:
$ yarn
$ yarn web startThese commands will install all dependencies and start a dev server serving the web app. Read the full documentation for more information about the web app.
To report bugs and feature requests, or request help using JW OTT Webapp, use this repository's Issues page.
This project is licensed under the Apache License, Version 2.0. See LICENSE.txt for more details.


