Skip to content

Output Services

After a track has been detected and enriched, it needs to reach every output you have configured — one overlay, two overlays, a Twitch chat bot, a local file for OBS, Discord, and anything else. Now Playing uses a router fan-out pattern so that a single enriched track triggers all outputs in parallel without any one of them blocking the others.

Enriched track
Router Service
├──► Overlay Service (SSE stream to browser sources)
├──► Twitch Service (chat messages)
├──► File Output Service (local text file for OBS)
└──► Discord Service (planned)

The Router Service reads each enriched track from a Redis stream and pushes a job into a dedicated queue for every output type. Each output service watches its own queue and handles delivery independently.

This architecture has a few important properties:

  • Outputs are isolated. If Twitch chat is temporarily rate-limited, it does not delay your overlays.
  • Outputs are parallel. All outputs receive the track at roughly the same moment.
  • Outputs are restartable. If the Twitch service crashes, it resumes from where it left off when it comes back online, because the queue preserves jobs.

Overlays are delivered via Server-Sent Events (SSE). When you paste your overlay URL into OBS’s browser source, the overlay page opens a long-lived HTTP connection to Now Playing’s cloud. As new tracks arrive, the server pushes them down the connection.

SSE is used instead of WebSockets because:

  • Browser sources implement SSE natively and reconnect automatically.
  • SSE traffic is plain HTTP and plays well with corporate networks and CDNs.
  • The traffic pattern is one-directional (cloud → overlay), which SSE models exactly.

Each user has a dedicated Redis pub/sub channel. When the Overlay Service receives a job for your account, it publishes the enriched track to your channel. The SSE endpoint subscribes to that channel and streams to every browser source you have open.

You can open the same overlay URL in several browser sources at once, or use several overlay URLs tied to the same account. Every open browser source receives the same update simultaneously — there is no primary or secondary. See Overlay Tokens for how multiple overlay URLs are kept secure.

The Twitch Service posts a chat message each time your on-air track changes. The message template is configurable — you can include the artist, title, album, and any custom text. Rate limiting is handled per-channel so that rapid track changes do not flood the chat.

If Twitch is disconnected (stream ended, outage, bot de-authed), the service buffers the most recent track and posts when connectivity is restored, so the next viewer sees the current track even if a few transitions happened while offline.

The File Output Service writes the current track to a local file on your computer. This is the classic integration with OBS Text (GDI+) sources and older broadcast tools that do not understand browser overlays.

The file path, format, and template are configured in the desktop app. See the File Output destination guide for setup details.

It would be simpler for the desktop app to send its track directly to each output. But that design has serious drawbacks:

  • Outputs are cloud-based, not local. Your Twitch bot runs in the cloud, not on your laptop. Direct delivery would require the desktop to know everyone’s Twitch credentials.
  • Multiple overlays in multiple browsers need a single point of fan-out. The cloud is the natural place.
  • Restarts would lose state. The desktop app closing should not stop your overlay from showing the last-played track.

By routing everything through the cloud, Now Playing is always the source of truth for “what is on air right now,” regardless of whether your desktop is up.

The router fan-out pattern is designed to be extensible. Adding a new output type (for example, a webhook or Discord bot) is a matter of:

  1. Creating a new output service that consumes from its own queue.
  2. Configuring the Router Service to push jobs to that queue.

Because existing outputs are not touched, new output types can be added without risk of breaking live streams.