Skip to content

Overview

Spooty is a single-activity native Android app written in Kotlin that wraps the Spotify Web Player (https://open.spotify.com) inside a hardened WebView and bends it to your liking, the same way Spicetify does on desktop.

The core idea

Instead of talking Spotify's private APIs, Spooty loads the real web player the browser would, and layers custom behavior on top:

  1. A WebViewClient keeps all navigation in-app; external links leave via the system browser, nothing else ever renders inside the app.
  2. An Injector (running in onPageFinished) loads core-spooty.js, core-spooty.css, the ad engine and the active theme into the page — guarded by a window.__spootyInjected flag so each asset is applied exactly once.
  3. A JSON bridge (JsBridge, every method annotated @JavascriptInterface) is the only JS→native channel: settings, playback state to the lockscreen, ad-mode updates.
  4. A foreground MediaSession service keeps the process alive for background audio while the WebView's own <audio> element does all the real playback.

It is a View-based app (no Compose) with a deliberately small surface area: few screens, thin framework code, and pure, unit-tested logic in inject/, settings/ and the ad-mode plumbing.

What it is not

  • Not a hack of Spotify's backend. No private API calls, no reverse-engineered endpoints, no network-level ad blocking.
  • Not a distributed app. It's built for you, on your machine (or on CI), and sideloaded.
  • Not a re-hosted stream. Native ExoPlayer is never used to play Spotify audio; the <audio> element inside the WebView is the source of truth.

Personal, non-distributed

This project exists to be useful to its maintainer. It bypasses scaffolds and ad flows of the official mobile apps, which means it walks close to the edge of Spotify's Terms of Service. Treat it as a personal experiment: don't publish or distribute it, and keep the accounts you log into as your own.

Where to go next