Self-hosted service
benkaiser/stretto avatar
benkaiser/stretto

Stretto: a web music player that turns YouTube and SoundCloud into a personal library

Beautiful web-based music player

634 stars96 forksJavaScriptMIT

At a glance

What is it?
Stretto is an MIT licensed web-based music player that backs your tracks with YouTube or SoundCloud sources and uses a companion Chrome extension to pull them into the browser, then layers on Spotify playlist import, library sync between machines, automatic lyrics and iTunes chart discovery. It is a Node and MongoDB application with a React front end, and the extension is the part that actually does the downloading.
Who is it for?
Adopt Stretto if you want a self-hosted music player with real library management, Spotify playlist import, sync across machines and lyrics, and you are comfortable with the arrangement that the audio itself comes from YouTube and SoundCloud.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 106 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The player is the easy part; the extension is the mechanism

The description of how Stretto works is the sentence to read first, because it explains both the appeal and the constraint. Stretto works by backing every single one of your tracks with a video or song from YouTube or SoundCloud, and it then uses the companion Chrome extension to download the tracks to your browser directly.

That is a two-part system. Stretto itself is a web application that holds your library, its metadata, your playlists and your listening history, and it presents the player. The Chrome extension, which lives in a separate repository called Stretto-Helper-Extension, is the part that actually retrieves the media into the browser.

The reason the split exists is worth understanding. A plain web page cannot fetch media from YouTube or SoundCloud on its own, so the retrieval has to happen from inside a browser context that already has the right origin and any session the source requires. The extension provides that. This is a design consequence rather than an arbitrary split, and it is also the main thing to weigh before adopting the project, because the extension is a separate piece of software with its own update cycle and its own failure modes.

Everything else in the project is the application around that mechanism, and it is a fairly complete one. The homepage is next.kaiserapps.com, and the project describes itself as an open source web-based music player, MIT licensed, and completely free.

The feature set is library management, not just playback

The README lists the features, and the interesting ones are the ones that make it a player rather than a URL player.

Import your playlists from Spotify is first, and it is the one that changes how you would use the thing. Syncing libraries between machines is second, which matters because your library is server-side state and a player that only works on one browser is a browser tab. Automatic lyric fetching for the currently playing song is third, and the dependency list confirms the implementation with a package called js-azlyrics.

Music discovery through iTunes and Spotify top charts is fourth, with a dedicated page for it, and searching iTunes to add tracks to your library in one step is the other half of the same idea: the source of new tracks is the catalogue, and Stretto treats that as part of the player rather than something you do in a separate tab.

There are multiple themes available, Android support via Kiwi Browser, and the free price. The Android route deserves a note because it is a specific technical claim: since Stretto works as a progressive web app, you can use Kiwi browser on Android to use it on mobile, and there is a blog post with more information.

The dependency list tells you how much of this is standard parts. React and React DOM at 16.5, react-router for navigation, socket.io and socket.io-client for the live connection between server and client, bootstrap and react-bootstrap for the interface, hls.js for streaming, and the spotify-web-api-js and soundcloud packages for the integrations. The custom forks are narrow: bootstrap-slider and react-native-ytdl are both pointed at personal GitHub forks rather than the upstream package.

Running it: two routes, and Docker is the shorter one

The developer instructions are short, and they start with the environment variables, which go in a .env file:

bash
GOOGLE_CLIENT_ID=<...>
SPOTIFY_CLIENT_ID=<...>
SOUNDCLOUD_CLIENT_ID=<...>

The .env.example file in the repository shows the fuller set, and it is a useful checklist because it names every integration the application expects: GOOGLE_CLIENT_ID, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, SOUNDCLOUD_CLIENT_ID, SMTP_PASSWORD, YOUTUBE_REDIRECT_ENDPOINT and SOUNDCLOUD_REDIRECT_ENDPOINT. The two redirect endpoints are for the OAuth callbacks, and the SMTP password is for nodemailer, which the dependency list includes, so the application sends its own email.

The Docker route is a single command:

bash
bin/go

And that is it, after which you go to http://localhost:3000. The compose file in the repository shows what that command starts: a mongo service on the stock mongo image and a web service built from Dockerfile.local, with the web service running the dev script, listening on port 3000, talking to the database at mongodb://mongo:27017/stretto, and mounting the working directory into the container.

yaml
services:
  mongo:
    image: mongo
  web:
    build:
      context: .
      dockerfile: Dockerfile.local
    command: npm run dev
    environment:
      PORT: 3000
      ENV: development
      APP_URL: 'http://localhost:3000'
      MONGO_URL: 'mongodb://mongo:27017/stretto'

The volume setup is the part to understand. The working directory is bind-mounted into the container and node_modules is mounted as an anonymous volume over it, which is the standard trick to keep host and container from fighting over the dependency directory. The consequence is that your source is live-mounted, so a change on the host is a change in the container, and the dev script restarts on it.

The non-Docker route is older and simpler to reason about. You need Node.js 12 and Mongodb running, you add your MONGO_URL setting to your environment variables, and then you execute yarn followed by npm run dev. The dev script in package.json runs nodemon against index.js in the background while webpack runs in watch mode, so the server restarts on server-side changes and the client bundle rebuilds on client-side ones.

The stack is a 2019 application with a long dependency tail

The package.json is a snapshot of a specific moment, and reading it tells you what to expect from a deployment.

The version is 2.0.0 and the release history confirms the shape of the project. The releases are 2.0.0, tagged Stretto Next, from 2019-01-28, and before that v0.0.6 from 2016 and v0.0.5 from 2016. So the significant release is more than seven years old, the last push to the repository was on 2026-07-09, and the project is not archived.

The dependency list is where the age shows. Node.js 12 is the stated requirement for the non-Docker path. Express 4.17 with express-session and connect-mongodb-session, Mongoose 6.2, React 16.5, react-router 4, socket.io 4.4, react-bootstrap 0.32, Pug 3 for templates, and Babel 7 with the proposal plugins for decorators and object rest spread. A build with webpack, sass-loader and mini-css-extract-plugin with nodemon for the dev loop.

None of that is a criticism so much as a deployment reality. A stack pinned to Node 12 will not build on a current Node runtime without friction, and several of those versions have known issues that only get fixes in newer lines. If you want to run this today, the Docker path is the one that isolates you from the host's Node version, and the compose file is set up for exactly that.

The repository layout is a conventional Express application rather than a modern one: index.js at the root, controllers/, models/, services/, views/ for the Pug templates, src/ for the React client, static/ for assets, stubs/, a webpack.config.js, a nodemon.json, a Dockerfile.local and a docker-compose.yml. There is also an AGENTS.md at the root and a.beans.yml, which is a Beanstalk worker configuration file.

What hosting this actually means for your data and your library

This is the part that deserves care, because the application is a self-hosted front end to two services you do not control.

Your library metadata, your playlists and your listening history live in your own MongoDB, which is the friendly part: the data is yours, on your machine, and the compose file puts it in a mongo service you control. The application is MIT licensed and the repository carries a LICENCE file, and there is a privacy_policy.html in the tree, so the intent is clearly a self-hosted service rather than a hosted one.

The audio is a different story. Stretto does not host media. It stores a reference to a YouTube video or a SoundCloud track, and the extension fetches it into the browser. So the actual playability of your library depends on two things you do not own: the behaviour of the extension, and the behaviour of the source services. If YouTube changes how its player serves media, or SoundCloud changes its endpoints, a self-hosted Stretto installation can lose the ability to play back tracks that its own database still lists.

That is a real operational risk and it is inherent to the design rather than a bug. It is also the reason the extension is a separate repository with its own releases, and why the project's own maintenance has been limited: there is not much a maintainer can do to insulate users from upstream changes.

The Spotify import and the iTunes search integration are different in kind, because those are catalogue and metadata APIs that the project is using the way an API is meant to be used, with client credentials supplied by the operator. The audio retrieval is the part that is not an official interface, and that distinction is the one to hold on to when deciding whether to put your own library behind this.

Editorial conclusion

Adopt Stretto if you want a self-hosted music player with real library management, Spotify playlist import, sync across machines and lyrics, and you are comfortable with the arrangement that the audio itself comes from YouTube and SoundCloud. Do not adopt it expecting a self-contained media library, because Stretto stores references and metadata in MongoDB while the companion extension is what fetches the actual tracks, and that dependency is on a browser extension and on the behaviour of two third-party services. Before you commit, read the .env.example file and supply the Google, Spotify and SoundCloud client credentials, decide whether to run it under Docker with bin/go or directly against a local MongoDB, and check the terms of the services you are pulling from before you put your own library behind it.

Frequently asked questions

How does Stretto actually get the music?

Stretto backs every track with a video or song from YouTube or SoundCloud, and it uses the companion Chrome extension, published separately as Stretto-Helper-Extension, to download the tracks to your browser directly. The web application holds the library and metadata; the extension does the retrieval.

What does Stretto need to run without Docker?

Node.js 12 and a running Mongodb. You add your MONGO_URL setting to your environment variables and then run yarn followed by npm run dev, which starts nodemon on index.js alongside a webpack watch build.

Which API credentials does Stretto require?

The .env.example lists GOOGLE_CLIENT_ID, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, SOUNDCLOUD_CLIENT_ID, SMTP_PASSWORD, YOUTUBE_REDIRECT_ENDPOINT and SOUNDCLOUD_REDIRECT_ENDPOINT, while the README's shorter example shows just the Google, Spotify and SoundCloud client IDs.

Can I run Stretto with Docker?

Yes. The README gives a single command, bin/go, and says that is it, after which you go to http://localhost:3000. The compose file starts a mongo service and a web service built from Dockerfile.local with the working directory bind-mounted into the container.

How current is the Stretto codebase?

The package version is 2.0.0, tagged Stretto Next, from 2019-01-28, and the last push to the repository was on 2026-07-09 with the project not archived. The dependencies target Node.js 12, React 16.5, Express 4.17 and Mongoose 6.2, so the Docker path is the practical way to run it on a current system.

Official sources

  1. benkaiser/stretto on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/benkaiser-stretto.svg)](https://hysenlabs.com/projects/benkaiser-stretto)

Was this useful?