Content
# niche-finder
[](https://github.com/pandich93/niche-finder/stargazers)
[](https://github.com/pandich93/niche-finder/forks)
[](https://github.com/pandich93/niche-finder/releases/latest)
[](https://github.com/pandich93/niche-finder/actions/workflows/ci.yml)
[](assets/coverage.json)
[](LICENSE)
[](backend/Dockerfile)
[](backend/interfaces/http/api.py)
[](docker-compose.yml)
[](docker-compose.yml)
[](backend/interfaces/mcp/server.py)
[](https://github.com/pandich93/niche-finder/commits/main)
[](https://github.com/pandich93/niche-finder/issues)
[](https://github.com/pandich93/niche-finder/pulls)
A self-hosted alternative to NexLev / vidIQ / ViewStats: find niches, viral
videos from small channels, trending categories and keywords over arbitrary
periods (24h, 48h, 7/30/90 days), plus full channel tracking and analytics.
Runs on the free YouTube Data API v3 and a local PostgreSQL — no
subscription, no paid LLM key: semantic classification like "faceless / on
topic" is done by the model calling these tools, not the server.

The project has three parts that together make up the "product":
- **`backend/`** — Python: an MCP server (29 tools for Claude), an HTTP API
for the dashboard, and a background worker that logs view/subscriber
history on a schedule (without this, "growth rate over 24 hours" doesn't
exist — the YouTube API only ever returns "right now").
- **`frontend/`** — the same functionality, but visual: a dashboard built on
plain ES modules (no npm, no build step) that calls the backend's HTTP API.
- **`extension/`** — a Chrome extension (Manifest V3) that puts the same
metrics on top of YouTube itself, the way vidIQ and NexLev do: outlier
score, view velocity and tags on a watch page, growth and best publishing
times on a channel page, multiplier badges on thumbnails in any list. It
talks only to `127.0.0.1` — nothing leaves the machine.
Both parts and the Postgres store come up together with one command (see
below) — the dashboard and Claude Desktop end up looking at the same
database.
## Features
- Find viral videos and outlier channels by niche over an arbitrary period
(24h / 48h / 7 / 30 / 90 days)
- Trending categories and keywords, best time to publish, title patterns
- Track specific channels: view/subscriber growth rate, snapshot history
- The exact same calculation in Claude Desktop (via MCP) and on the web
dashboard — one shared codebase, not two implementations
- Only the free YouTube Data API v3 and local PostgreSQL — no paid
subscriptions and no LLM key on the server side
## Table of Contents
- [Screens](#screens)
- [How it works](#how-it-works)
- [Quick start](#quick-start)
- [Repository layout](#repository-layout)
- [Contributing](#contributing)
- [Privacy](#privacy)
- [Changelog](#changelog)
- [Read next](#read-next)
## Screens
<table>
<tr>
<td width="50%"><img src="assets/viral.jpg" alt="Viral videos from small channels"><br><sub>Viral videos — small channels that overperformed expectations</sub></td>
<td width="50%"><img src="assets/outliers.jpg" alt="Outlier channels"><br><sub>Outlier channels — best video's multiplier against the channel's median</sub></td>
</tr>
<tr>
<td width="50%"><img src="assets/categories.jpg" alt="Categories"><br><sub>Categories — share and growth across YouTube niches</sub></td>
<td width="50%"><img src="assets/keywords.jpg" alt="Keywords"><br><sub>Keywords — trendScore, lift, momentum</sub></td>
</tr>
<tr>
<td width="50%"><img src="assets/tracker.jpg" alt="Channel tracker"><br><sub>Channel tracker — collect and follow specific channels</sub></td>
<td width="50%"><img src="assets/niches.jpg" alt="Niches"><br><sub>Niches — everything collected under user-defined labels</sub></td>
</tr>
<tr>
<td width="50%"><img src="assets/data.jpg" alt="Data"><br><sub>Data — database state and manual collection/refresh</sub></td>
<td width="50%"></td>
</tr>
</table>
## How it works
```mermaid
flowchart LR
CD["Claude Desktop"] -->|MCP| MCP["MCP server\nbackend/server.py"]
FE["Browser / frontend"] -->|HTTP| API["HTTP API\nbackend/api.py"]
EXT["Chrome extension\non youtube.com"] -->|"HTTP (localhost)"| API
YT["YouTube Data API v3"] <-->|"on schedule"| W["Background worker\nbackend/worker.py"]
MCP --> PG[("PostgreSQL")]
API --> PG
W --> PG
```
The MCP server, HTTP API, and worker are three different entry points into
the same code: all three call the same use cases from `backend/application/`,
so the result in Claude Desktop and on the dashboard is literally the same
calculation — not two separate implementations. A detailed breakdown of the
backend's layers (as of September 5, 2026 — DDD: domain → infrastructure →
application → interfaces) is in
[backend/README.md](backend/README.md#structure).
## Quick start
With Docker (recommended — brings up Postgres, the worker, and the dashboard
together):
```bash
cp .env.example .env # fill in YOUTUBE_API_KEY (not required to build)
docker compose build
make up # or: docker compose up -d web worker
make doctor # check the key, network, and database
open http://localhost:8080 # dashboard
```
Without Docker (needs your own reachable Postgres):
```bash
make local-install # venv + backend dependencies, once
make dev # HTTP dashboard on http://localhost:8080
make local-run # or: MCP server on the host, for Claude Desktop
```
Запуск на хосте (`make dev` / `make local-run`) ходит в ту же базу, но по
другому адресу: контейнер Postgres опубликован на `127.0.0.1:5433`, а дефолт в
коде -- `localhost:5432`, поэтому без подсказки процесс падает с
`psycopg2.OperationalError: Connection refused`. Добавьте в `.env` строку
```bash
NICHE_DATABASE_URL=postgresql://niches:niches@localhost:5433/niches
```
(`NICHE_DATABASE_URL` важнее `POSTGRES_*` и остаётся хостовым: в контейнеры
compose его не передаёт, а `scripts/mcp-docker.sh` и `scripts/diag.sh`
вырезают его явно). **Не** подменяйте это на `POSTGRES_PORT=5433` -- ту же
переменную compose отдаёт контейнерам как внутрисетевой порт и сломает
`web`/`worker`/`mcp`.
`make dev` слушает тот же `:8080`, что и контейнер `web`. Держать оба сразу
нельзя: хостовый uvicorn перехватывает порт, и проброс у контейнера тихо
отваливается (`docker ps` покажет `8080/tcp` без маппинга). Либо
`docker compose stop web` перед `make dev`, либо правьте код прямо в
контейнере -- `./backend` смонтирован внутрь, и `docker compose restart web`
подхватывает изменения без пересборки.
`make help` prints every available command with a one-line description.
## Repository layout
| Path | What's inside |
|---|---|
| [`backend/`](backend/README.md) | MCP server, HTTP API, worker — all the logic and data storage |
| [`frontend/`](frontend/README.md) | dashboard: index.html, styles.css, ui.js, app.js |
| [`extension/`](extension/README.md) | Chrome extension: panels and badges on top of YouTube |
| `docker-compose.yml` | postgres + worker + web + mcp/mcp-http services |
| `Makefile` | commands to run everything, via Docker or straight on the host |
| `.env.example` | YouTube key and worker settings |
| `scripts/mcp-docker.sh` | MCP server launcher in Docker for Claude Desktop |
`docs/` (decision history and market research) — internal notes, not
included in this repository.
## Contributing
Bug reports, bug fixes, and documentation PRs are welcome — for anything
bigger (a new MCP tool, API endpoint, or dashboard screen), please open an
issue first to agree on the shape. See
[CONTRIBUTING.md](CONTRIBUTING.md) for how to set up a dev environment and
run the test suite.
## Privacy
Self-hosted, no telemetry, no account: everything stays in your own Postgres,
and the app contacts exactly two external hosts — `www.googleapis.com` for the
YouTube Data API and `www.youtube.com` for channel RSS feeds. Comments read by
`video_comments` are never stored. See [PRIVACY.md](PRIVACY.md) for the full
picture, including what the first run downloads and how to delete everything.
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for a history of notable changes, in
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
## Read next
- [backend/README.md](backend/README.md) — YouTube API quotas, all 24 tools
with descriptions, how to read `period_by`, running with and without
Docker, the DDD layer structure.
- [frontend/README.md](frontend/README.md) — dashboard screens, where the
data comes from, how the palette is built.
- [extension/README.md](extension/README.md) — what the extension shows on
each kind of YouTube page, how to load it unpacked, and what it costs in
API quota.
Connection Info
You Might Also Like
No recommendations available