DEV Community

eli6
eli6

Posted on • Originally published at eli6movies.vercel.app

I built a free streaming site from scratch — no ads, no framework, no BS

What I built

ELI6 Movies is a free streaming platform — films, shows, and anime. No sign-up wall, no ads, no subscription. You open it and things play.

I wanted to prove you don't need React, a paid CDN, or $15/month to deliver a decent streaming experience.


Stack

Layer Tech
Frontend Vanilla JS + CSS (no framework)
Backend Node.js + Express
Database MongoDB (Mongoose)
Hosting Vercel (frontend) + Render (backend)
Metadata TMDB API
Email Resend

Things I'm proud of

No framework on the frontend. I went full vanilla — custom routing, component patterns, theme switching, all without a build step. The entire frontend deploys as static files.

JWT with per-device session management. Each login creates a session with a JTI (JWT ID). Users can see and revoke individual sessions from their profile — like Netflix's "sign out of all devices" but per-session.

Custom analytics dashboard. No Google Analytics. I built my own: page views, daily chart, top pages, countries (via ip-api.com with a circuit breaker), device types, browser breakdown, referrers, and live active sessions. All stored in MongoDB.

Password reset + email verification using Resend's HTTP API — no new npm dependencies, just native fetch.

GeoIP circuit breaker. After 5 consecutive failures or a quota hit from ip-api.com, the system backs off for 5 minutes instead of hammering the free tier.


Things that bit me

The router.use(auth, adminOnly) trap. Express's router.use(fn) without a path prefix intercepts all requests entering the router — not just the routes you defined. I had an analytics router with unscoped auth middleware that silently intercepted /api/health, causing Render's health check to receive 401 on every deploy. The service rolled back with update_failed in a loop for days. Fix was one line: router.use('/admin/analytics', auth, adminOnly).

ua-parser-js v2 on Render. The library crashing on import caused a crash loop. Replaced with 15 lines of inline regex.


What's live

  • Films, TV shows, anime
  • Watchlist (synced to account)
  • Resume watching
  • Light/dark/system theme
  • Mobile-friendly
  • Admin analytics panel

Live at: eli6movies.vercel.app

Feedback welcome — roast the code, suggest features, or just tell me what's broken.

Top comments (0)