AI-powered fact-checker for viral videos — detects bias, verifies claims, and exposes misinformation in YouTube Shorts, Instagram Reels, TikTok videos, and pasted transcripts.
Paste a short-form video link, upload a file, or paste a transcript and Unreel will:
- Download & transcribe the video audio using Groq Whisper
- Extract on-screen text via OCR from key video frames
- Identify factual claims using LLaMA 3 via Groq
- Fact-check each claim against live web sources via Tavily Search
- Measure bias on a 0–100 scale with type detection and indicators
- Persist results to MongoDB so you can retrieve past analyses anytime
- Bot Link: https://t.me/unreel_analyser_bot
- Use case: Analyze short-form video links directly inside Telegram chat
- Supports: Public Telegram post links, Instagram Reels, YouTube Shorts
- Mini Portfolio Widget: Added an animated, interactive mini-portfolio floating widget (fixed top-right). Built with framer-motion, featuring 4 animated states (collapsed → expanded → bio → menu) with social links (GitHub, LinkedIn, Twitter/X, CV). Converted from a Next.js/Tailwind/TypeScript source to Vite/vanilla-CSS/JSX.
- Content Platform Expansion: Added a comprehensive Markdown-powered Blog system, real-time Platform Statistics, and a curated Insights section.
- Live Trending News: Replaced the static trending section with a live daily news feed powered by GNews API. News about misinformation, fact-checking, and media literacy is fetched automatically and cached for 24 hours. Includes a dedicated
/newspage with full article listings. - Blog Image Resilience: Added graceful gradient fallback placeholders for blog images that fail to load in deployment (Unsplash rate limits, CORS, etc.).
- Removed Leaderboard: Removed the "Most Analysed Reels" leaderboard section from the homepage for a cleaner layout.
- Added Telegram bot integration in backend startup flow (
modules/telegramBot.js+server.js). - Added Telegram bot environment config (
TELEGRAM_BOT_TOKEN,TELEGRAM_BOT_POLLING,TELEGRAM_ANALYZE_API_URL). - Expanded bot URL intake beyond Telegram links to include:
- Instagram
/reel/...and/reels/... - YouTube Shorts
/shorts/...andyoutu.be/...
- Instagram
- Improved bot UX with:
- Better
/startwelcome and guided instructions /help,/supported,/examples,/statuscommands- Persistent quick-action keyboard buttons
- Progress typing indicator while analysis runs
- Better
- Improved scenario handling messages for:
- invalid links
- unsupported links
- multiple links in one message
- private/login-protected links
- timeouts and rate limits
- concurrent in-chat requests
- Reworked Telegram analysis output into a professional report format:
- video overview
- fact-check summary + verdict breakdown
- top findings with confidence/recency
- bias assessment summary
- Added homepage dashboard section to promote Telegram bot with direct CTA link.
- UI Restructure: Replaced the dashboard input card with a premium Landing Page intro section, featuring a "Start Analyzing" CTA button.
- Analyze Page Refactor: Moved all URL, Upload, and Transcript input forms into a dedicated, two-phase
/analyzeUI. - Refined Navigation: Cleaned up the Navbar by removing in-page hash links (How it Works, Features) and updated Blog images to use reliable absolute URLs in production.
- Auth system with JWT + Google login.
- Optional analysis history persistence per user.
- Date-aware fact-checking with content date and recency reason fields.
- Better downloader diagnostics and user-facing download failure hints.
- Fallback-safe frontend serving in production.
- Optional webhook mode for Telegram bot (alternative to polling).
- Additional bot report enhancements (richer source preview formatting).
- Optional dedicated Telegram user mapping for persistent per-chat history.
| Layer | Technology |
|---|---|
| Frontend | React 18, Vite, React Router, Lucide Icons, Framer Motion |
| Backend | Node.js, Express |
| Auth | JWT, Google OAuth, bcryptjs |
| Database | MongoDB, Mongoose |
| AI/ML | Groq Whisper (STT), Groq LLaMA 3.1 (LLM), Tavily (search), GNews (news) |
| Video | yt-dlp (download), ffmpeg (keyframe extraction) |
unreel/
├── client/ # React frontend (Vite)
│ ├── src/
│ │ ├── components/ # Navbar, Hero, HowItWorks, Features, Footer,
│ │ │ # ResultsOverlay, ResultsPage, BlogSection,
│ │ │ # StatsSection, TrendingSection, MiniPortfolio
│ │ ├── context/ # AuthContext (JWT + Google OAuth)
│ │ ├── pages/ # AnalyzePage, HistoryPage, LoginPage, RegisterPage,
│ │ │ # BlogPage, BlogPostPage, TrendingNewsPage
│ │ ├── App.jsx
│ │ ├── App.css
│ │ └── main.jsx
│ ├── index.html
│ └── vite.config.js
├── middleware/ # Auth middleware (JWT verification)
│ └── authMiddleware.js
├── models/ # Mongoose schemas
│ ├── AnalysisResult.js
│ └── User.js
├── modules/ # Backend service modules
│ ├── audioExtractor.js # ffmpeg keyframe extraction
│ ├── biasAnalyzer.js # Bias scoring via Groq LLaMA
│ ├── claimExtractor.js # Claim extraction via Groq LLaMA
│ ├── downloader.js # yt-dlp video downloader
│ ├── factChecker.js # Fact-checking via Tavily + Groq
│ ├── ocrExtractor.js # On-screen text extraction
│ └── transcriber.js # Audio transcription via Groq Whisper
├── routes/ # Express route handlers
│ ├── analyze.js # POST /api/analyze/url, /upload, /text
│ ├── auth.js # POST /api/auth/register, /login, /google
│ ├── blog.js # GET /api/blogs, /api/blogs/:slug
│ ├── history.js # GET / DELETE /api/history
│ ├── leaderboard.js # GET /api/top-analysed
│ ├── news.js # GET /api/news (GNews-powered daily feed)
│ ├── trending.js # GET /api/trending
│ └── results.js # GET /api/results, /api/results/:id
├── .env.example
├── Dockerfile
├── render.yaml
├── package.json
└── server.js # App entry point
- Node.js 18+
- MongoDB (local or MongoDB Atlas)
- yt-dlp — add to PATH
- ffmpeg — add to PATH
git clone https://github.com/your-username/unreel.git
cd unreel
npm install
npm install --prefix clientcp .env.example .envFill in .env:
GROQ_API_KEY=your_groq_api_key # Whisper transcription + LLaMA 3.1 (free)
TAVILY_API_KEY=your_tavily_api_key # Web search (free tier available)
GNEWS_API_KEY=your_gnews_api_key # Trending news feed (free: 100 req/day)
MONGODB_URI=mongodb://127.0.0.1:27017/unreel
JWT_SECRET=replace_with_a_strong_secret
PORT=3000
VITE_API_BASE_URL= # optional, set when frontend and backend are on different domains
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your_email_username
SMTP_PASS=your_email_password_or_app_password
SMTP_FROM="Unreel" <no-reply@unreeled.in>
MAIL_BRAND_NAME=Unreel
MAIL_BRAND_COLOR=#7c3aed
MAIL_LOGO_URL=https://www.unreeled.in/og-image.pngIf SMTP variables are set, Unreel sends a standard welcome email to newly created accounts (email signup and first-time Google signup).
Use MAIL_BRAND_* values to customize the email branding without touching code.
npm run devThis runs both the backend (nodemon) and frontend (Vite) concurrently with hot reload. The Vite dev server proxies API requests to Express on port 3000.
npm run build # Builds the React frontend
npm start # Starts the Express server serving the built frontendIf you already created a Telegram bot token, add this to .env:
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_BOT_POLLING=true
TELEGRAM_ANALYZE_API_URL=http://127.0.0.1:3000Then start the server with npm start or npm run dev:server.
In Telegram:
- Open your bot and send
/start - Send one link like:
https://t.me/channel_name/123https://www.instagram.com/reel/abc123/https://www.youtube.com/shorts/abc123
- The bot replies with fact-check + bias summary
The bot currently accepts public Telegram post links, Instagram Reels, and YouTube Shorts links.
| Route | Page |
|---|---|
/ |
Landing Page (intro, stats, trending news, blog) |
/analyze |
Analysis input form and loading page |
/results/:id |
Full analysis results |
/history |
Past analyses (authenticated users) |
/login |
Login page |
/register |
Register page |
/blog |
Blog listing page |
/blog/:slug |
Individual blog post page |
/news |
Trending news feed (full page) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/analyze/url |
Optional | Analyze video from URL |
| POST | /api/analyze/upload |
Optional | Analyze uploaded video file |
| POST | /api/analyze/text |
Optional | Analyze pasted transcript text |
| GET | /api/results |
— | Fetch recent analyses |
| GET | /api/results/:id |
— | Fetch a single analysis by ID |
| GET | /api/blogs |
— | Fetch blog posts (paginated) |
| GET | /api/blogs/:slug |
— | Fetch single blog post |
| GET | /api/news |
— | Fetch live trending news (GNews, 24h cache) |
| GET | /api/trending |
— | Fetch trending content issues |
| GET | /api/top-analysed |
— | Fetch leaderboard (sortable) |
| GET | /api/history |
Required | Fetch user's past analyses |
| DELETE | /api/history/:id |
Required | Delete one history item |
| DELETE | /api/history |
Required | Clear all history items |
| POST | /api/auth/register |
— | Register with email/password |
| POST | /api/auth/login |
— | Login with email/password |
| POST | /api/auth/google |
— | Login/register via Google OAuth |
| GET | /api/health |
— | Server & MongoDB health check |
| Service | Free Tier | Link |
|---|---|---|
| Groq (Whisper + LLaMA 3.1) | Generous free tier | https://console.groq.com |
| Tavily Search | 1,000 searches/month | https://tavily.com |
| GNews | 100 requests/day | https://gnews.io |
Render is the recommended host — it runs a full Docker container so yt-dlp, ffmpeg, and long-running analysis all work correctly.
git add .
git commit -m "deploy: ready for Render"
git push origin main- Go to mongodb.com/atlas and create a free cluster
- Create a database user and whitelist 0.0.0.0/0 in Network Access
- Copy your connection string:
mongodb+srv://user:pass@cluster0.xxxxx.mongodb.net/unreel
-
Go to render.com → New → Web Service
-
Connect your GitHub repo
-
Render will auto-detect the
render.yaml— confirm settings:- Runtime: Docker
- Plan: Free
-
Add environment variables under Environment:
Key Value GROQ_API_KEYyour key TAVILY_API_KEYyour key GNEWS_API_KEYyour key (optional — trending news) MONGODB_URIyour Atlas connection string JWT_SECRETa strong random secret -
Click Deploy — first build takes ~5 minutes
Note: The free tier spins down after 15 minutes of inactivity. Upgrade to the Starter plan to keep it always-on.
MIT