Note
API MAYBE Temporarily Paused due to suspiciously too many requests. My hosted version of this API is only for testing purposes. You MUST host your own instance to use the API.
A serverless API aggregating anime news from 13 sources in real-time.
Smart caching, keyword search, RSS feeds, date filtering, cursor pagination, and source health monitoring.
Built for speed, reliability, and the anime community.
Table of Contents • Features • API Docs • Quick Start • Deployment • Contributing
- Overview
- Features
- News Sources
- Tech Stack
- Architecture
- Project Structure
- Quick Start
- Configuration
- API Endpoints
- API Response Schema
- Deployment
- Available Scripts
- Performance
- Changelog Highlights
- Troubleshooting
- FAQ
- Roadmap
- Contributing
- Acknowledgements
- License
- Author
- Star History
AniNewsAPI is a serverless anime news aggregation API that scrapes, deduplicates, and serves articles from 13 major anime news sources — all through a clean REST API with zero database setup.
💡 No database, no auth for reads, no complex setup. Just deploy to Vercel and you have a production API.
- 📰 13 Sources — ANN, MAL, Crunchyroll, Anime Corner, Otaku USA, Anime Herald, Comic Book, Tokyo Otaku Mode, Anime Trending, Anime UK News, Random Curiosity, Honey's Anime, Otaku News
- ⚡ Smart Caching — Two-tier cache (memory + disk) with 10-minute TTL, survives serverless cold starts
- 🔍 Full-Text Search — Relevance-scored search across titles, excerpts, sources, and tags
- 🗞️ RSS Feeds — Standards-compliant RSS 2.0 for any feed reader
- 📄 Full Article Extraction — Get readable article content by slug
- 🏷️ Tag Filtering — Browse articles by tag with count aggregation
- 📊 Source Health — Real-time per-source health checks, latency, and article counts
- 🔒 CORS Enabled — Works from any frontend, no proxy needed
- 🚀 Zero-Config Deploy — One click to Vercel, Docker, or standalone with Express
- 🆔 Request ID Tracing — Every request gets a UUID for debugging
- ⏳ HEAD Support — All GET endpoints respond to HEAD requests
- 📦 Docker Ready — Dockerfile with health check included
flowchart TD
A["🌐 Client Request<br/>(Browser / App / curl)"] --> B["🛡️ Vercel Edge / Express Server<br/>CORS · Security Headers · Rate Limiting"]
B --> C{"💾 Cache Check<br/>(node-cache + disk)"}
C -- HIT --> D["⚡ Return Cached Response<br/>~200ms"]
C -- MISS --> E["📰 13 Concurrent Fetchers<br/>ANN · MAL · Crunchyroll · Anime Corner<br/>Otaku USA · Anime Herald · Comic Book<br/>Tokyo Otaku Mode · Anime Trending<br/>Anime UK News · Random Curiosity<br/>Honey's Anime · Otaku News"]
E --> F["🔄 RSS / Google News RSS / Web Scraping<br/>3 retries · 15s timeout · exponential backoff"]
F --> G["🧹 Deduplicate · Enrich · Cache"]
G --> H["📤 Respond<br/>JSON · RSS 2.0 XML · SSE"]
style A fill:#1e1e2e,stroke:#a78bfa,color:#f1f5f9
style B fill:#1e1e2e,stroke:#6366f1,color:#f1f5f9
style C fill:#1e1e2e,stroke:#f43f8e,color:#f1f5f9
style D fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
style E fill:#1e1e2e,stroke:#a855f7,color:#f1f5f9
style F fill:#1e1e2e,stroke:#eab308,color:#f1f5f9
style G fill:#1e1e2e,stroke:#06b6d4,color:#f1f5f9
style H fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
|
|
|
|
| Feature | Description | Status |
|---|---|---|
| 📰 13 News Sources | ANN, MAL, Crunchyroll, Anime Corner, Otaku USA, Anime Herald, Comic Book, Tokyo Otaku Mode, Anime Trending, Anime UK News, Random Curiosity, Honey's Anime, Otaku News | ✅ |
| ⚡ Smart Caching | Two-tier (memory + disk) with 10-min TTL | ✅ |
| 🔍 Full-Text Search | Relevance scoring — title (10pts) vs excerpt (3pts) | ✅ |
| 📄 Article Extraction | Full content parsing from original URLs | ✅ |
| 🗞️ RSS 2.0 Feed | Standards-compliant XML with media:thumbnail | ✅ |
| 📅 Date Filtering | ?from=YYYY-MM-DD&to=YYYY-MM-DD on news & search |
✅ |
| 🔄 Cursor Pagination | Opaque base64url cursors for stable paging | ✅ |
| 🏷️ Tag System | Tag listing with counts, filter by tag | ✅ |
| 📊 Source Health | Real-time fetch status, latency, article counts | ✅ |
| 🔒 Cache Auth | API key protection for cache clear endpoint | ✅ |
| 📡 SSE Stream | Server-Sent Events for real-time push | ✅ |
| 📋 OpenAPI Spec | Machine-readable 3.0.3 specification | ✅ |
| 🚀 One-Click Deploy | Vercel button deployment | ✅ |
| 🏗️ Express Mode | Standalone server with npm start |
✅ |
| 🆔 Request ID | UUID v4 tracing on every request | ✅ |
| ⏳ HEAD Support | HEAD method on all GET endpoints | ✅ |
| 🐳 Docker | Dockerfile with health check | ✅ |
| 📦 Shared Fetch Logic | DRY module for all endpoints | ✅ |
| 📋 ESLint Config | Code quality enforcement | ✅ |
| Source | Key | Method | Articles | Website |
|---|---|---|---|---|
| Anime News Network | ann |
Google News RSS | ~15 | animenewsnetwork.com |
| Anime Corner | animecorner |
RSS Feed | ~12 | animecorner.me |
| MyAnimeList | myanimelist |
Direct Scraping | ~15 | myanimelist.net |
| Otaku USA Magazine | otakuusa |
Google News RSS | ~12 | otakuusamagazine.com |
| Crunchyroll | crunchyroll |
Google News RSS | ~15 | crunchyroll.com/news |
| Anime Herald | animeherald |
RSS Feed | ~10 | animeherald.com |
| Comic Book | comicbook |
Direct Scraping | ~10 | comicbook.com/anime |
| Tokyo Otaku Mode | tokyootakumode |
RSS Feed | ~10 | otakumode.com |
| Anime Trending | animetrending |
RSS Feed | ~10 | anitrendz.net |
| Anime UK News | animeuknews |
RSS + OG Images | ~12 | animeuknews.net |
| Random Curiosity | randomcuriosity |
RSS Feed | ~10 | randomc.net |
| Honey's Anime | honeysanime |
RSS Feed | ~12 | honeysanime.com |
| Otaku News | otakunewsnew |
RSS + OG Images | ~12 | otakunews.com |
Total: 150+ unique articles after cross-source deduplication
- Create
utils/fetchNewSource.js— export async function returning[{ title, slug, source, excerpt, date, image, link, tags }] - Register in
utils/sources.js→SOURCESobject - Test with
npm test, submit a PR
| Technology | Purpose | Version | Documentation |
|---|---|---|---|
| 🟢 Node.js | JavaScript runtime | >= 20 | Docs |
| ⚡ Express | HTTP server framework | 5.1 | Docs |
| ▲ Vercel Functions | Serverless deployment | — | Docs |
| 🔍 Cheerio | HTML parsing & scraping | 1.0 | Docs |
| 🌐 Axios | HTTP client | 1.7 | Docs |
| 📡 rss-parser | RSS/Atom feed parsing | 3.13 | Docs |
| 💾 node-cache | In-memory caching | 5.1 | Docs |
| 🔤 he | HTML entity decoding | 1.2 | Docs |
{
"express": "^5.1.0", // HTTP server
"axios": "^1.7.2", // HTTP client for scraping
"cheerio": "^1.0.0-rc.12", // HTML parsing
"rss-parser": "^3.13.0", // RSS feed parsing
"node-cache": "^5.1.2", // In-memory cache
"he": "^1.2.0" // HTML entity decoding
}| Stage | Component | Description |
|---|---|---|
| 1 | Client | Browser, app, or curl sends request |
| 2 | Vercel Edge / Express | Routes request, applies CORS + security headers + rate limit |
| 3 | Cache Check | node-cache with 10-min TTL — hit = instant response |
| 4 | Fetch Sources | 13 concurrent scrapers (3 retries each, 15s timeout) |
| 5 | Deduplicate | Cross-source dedup by normalized title |
| 6 | Enrich & Respond | Filter, paginate, sort, format → JSON/RSS/SSE |
flowchart TD
A["📥 Request"] --> B{"🧠 Memory Cache<br/>(node-cache)"}
B -- HIT --> C["⚡ Return Cached<br/>~200ms"]
B -- MISS --> D{"💾 Disk Cache<br/>(JSON files)"}
D -- HIT --> E["🔄 Promote to Memory<br/>Return"]
D -- MISS --> F["📰 Fetch from 13 Sources<br/>(concurrent)"]
F --> G["💾 Cache Result<br/>(memory + disk)"]
G --> H["📤 Return Fresh"]
style A fill:#1e1e2e,stroke:#a78bfa,color:#f1f5f9
style B fill:#1e1e2e,stroke:#f43f8e,color:#f1f5f9
style C fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
style D fill:#1e1e2e,stroke:#6366f1,color:#f1f5f9
style E fill:#1e1e2e,stroke:#06b6d4,color:#f1f5f9
style F fill:#1e1e2e,stroke:#eab308,color:#f1f5f9
style G fill:#1e1e2e,stroke:#a855f7,color:#f1f5f9
style H fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
💡 Serverless functions have read-only filesystems except
/tmp. The disk cache writes to/tmpon Vercel, surviving across warm invocations.
| Source | Primary | Fallback | Notes |
|---|---|---|---|
| ANN | Google News RSS | Direct scraping | Cloudflare blocks direct access |
| Anime Corner | RSS Feed | Direct scraping | RSS has real descriptions |
| MyAnimeList | Direct scraping | Page 2 scraping | Custom date format parser |
| Otaku USA | Google News RSS | Direct scraping | 520 errors on direct access |
| Crunchyroll | Google News RSS | Direct scraping | Blocks direct scraping |
| Anime Herald | RSS Feed | Direct scraping | RSS has real descriptions |
| Comic Book | Direct scraping | RSS Feed | Uses subheadline selector |
| Tokyo Otaku Mode | RSS Feed | Direct scraping | Merchandise & culture news |
| Anime Trending | RSS Feed | Direct scraping | Images in content:encoded |
| Anime UK News | RSS + OG Images | Direct scraping | UK/EU perspective |
| Random Curiosity | RSS Feed | Direct scraping | Images in description |
| Honey's Anime | RSS Feed | Direct scraping | Music/anisong focus |
| Otaku News | RSS + OG Images | Direct scraping | UK/US interviews |
AniNewsAPI/
├── 📂 api/ # 🌐 Vercel serverless functions
│ ├── 📂 cache/
│ │ └── 📄 clear.js # 🔐 Cache management (API key protected)
│ ├── 📄 health.js # 💚 Health check endpoint
│ ├── 📄 news.js # 📰 Main news endpoint (pagination, filtering)
│ ├── 📂 news/
│ │ ├── 📄 [slug].js # 📄 Full article by slug
│ │ └── 📄 tags.js # 🏷️ Tag listing & filtering
│ ├── 📄 openapi.js # 📋 OpenAPI 3.0.3 specification
│ ├── 📄 rss.js # 🗞️ RSS 2.0 XML feed
│ ├── 📄 search.js # 🔍 Full-text search with scoring
│ ├── 📄 sources.js # 📊 Per-source health & stats
│ ├── 📄 stats.js # 📈 Cache hit/miss statistics
│ └── 📄 stream.js # 📡 Server-Sent Events
│
├── 📂 public/
│ ├── 📄 index.html # 🏠 Landing page
│ ├── 📄 manifest.json # 📱 PWA manifest
│ ├── 📄 og-image.png # 🖼️ Open Graph image
│ └── 📄 og-image.svg # 🖼️ Open Graph vector
│
├── 📂 utils/ # ⚙️ Core logic
│ ├── 📄 cacheHandler.js # 💾 Two-tier cache (memory + disk)
│ ├── 📄 constants.js # 📌 Shared config, CACHE_KEYS, RATE_LIMIT
│ ├── 📄 contentParser.js # 📄 Full-article content extraction
│ ├── 📄 dateParser.js # 📅 Multi-format date parsing
│ ├── 📄 fetchAllSources.js # 🔄 Shared fetch logic (DRY)
│ ├── 📄 fetchANN.js # 📰 Anime News Network fetcher
│ ├── 📄 fetchAnimeCorner.js # 📰 Anime Corner fetcher
│ ├── 📄 fetchAnimeHerald.js # 📰 Anime Herald fetcher
│ ├── 📄 fetchComicBook.js # 📰 Comic Book fetcher
│ ├── 📄 fetchCrunchyroll.js # 📰 Crunchyroll fetcher
│ ├── 📄 fetchMyAnimeList.js # 📰 MyAnimeList fetcher
│ ├── 📄 fetchOtakuNews.js # 📰 Otaku USA fetcher
│ ├── 📄 generateSlug.js # 🔗 URL-safe slug generator
│ └── 📄 sources.js # 📋 Centralized source registry
│
├── 📂 data/ # 💾 Disk cache files (auto-generated)
│
├── 🐳 Dockerfile # 🐳 Docker deployment with health check
├── 📄 .eslintrc.json # 🔍 ESLint configuration
├── 📄 server.js # 🚀 Express server entry point
├── 📄 index.js # ▲ Vercel serverless entry point
├── 📄 test.js # 🧪 Integration test suite
├── 📄 vercel.json # ▲ Vercel routing & headers config
├── 📄 package.json # 📦 Dependencies & scripts
├── 📄 CHANGELOG.md # 📝 Version history
├── 📄 CONTRIBUTING.md # 🤝 Contribution guidelines
├── 📄 LICENSE # 📜 MIT License
└── 📄 README.md # 📖 This file
| Requirement | Minimum | Recommended |
|---|---|---|
| 📦 Node.js | 20.x | 20.x LTS |
| 📦 npm | 9.0+ | 10.x |
| 💻 OS | Windows, macOS, Linux | Any |
# 1️⃣ Clone the repository
git clone https://github.com/Shineii86/AniNewsAPI.git
cd AniNewsAPI
# 2️⃣ Install dependencies
npm install
# 3️⃣ Start development server
npm run dev🌐 Open http://localhost:3000 in your browser.
# Start production server
npm start
# Run tests
npm test# Using yarn
yarn install
yarn dev
# Using pnpm
pnpm install
pnpm dev
# Using bun
bun install
bun dev| Variable | Default | Description |
|---|---|---|
CACHE_TTL |
600 |
Cache duration in seconds (10 minutes) |
PORT |
3000 |
Server port (Express mode only) |
CACHE_CLEAR_KEY |
— | API key for POST /api/cache/clear (optional) |
RATE_LIMIT |
100 |
Max requests per minute per IP |
API_URL |
http://localhost:3000 |
Base URL for test suite |
The vercel.json file handles:
- Rewrites — Maps clean URLs to serverless functions
- Headers — CORS, caching, and rate limit headers
- Environment — Sets
CACHE_TTLfor production
Latest anime news from all or specific sources.
| Param | Type | Default | Description |
|---|---|---|---|
limit |
1-100 |
20 |
Max articles per page |
offset |
>=0 |
0 |
Pagination offset |
cursor |
string |
— | Pagination cursor (from meta.nextCursor) |
sort |
latest|oldest |
latest |
Sort order |
source |
string |
all |
Filter by source key |
from |
YYYY-MM-DD |
— | Start date filter |
to |
YYYY-MM-DD |
— | End date filter |
refresh |
boolean |
false |
Bypass cache |
# Basic usage
curl "https://aninews.vercel.app/api/news?limit=10"
# Filter by source with pagination
curl "https://aninews.vercel.app/api/news?source=crunchyroll&limit=10&offset=10"
# Date range filtering
curl "https://aninews.vercel.app/api/news?from=2026-05-20&to=2026-05-27"
# Cursor-based pagination (use nextCursor from previous response)
curl "https://aninews.vercel.app/api/news?limit=20&cursor=eyJvZmZzZXQiOjIwfQ"📄 Example Response
{
"success": true,
"data": [
{
"title": "Demon Slayer Season 4 Announced",
"slug": "ann-demon-slayer-season-4-announced",
"source": "Anime News Network",
"excerpt": "The official website confirmed...",
"date": "2026-05-27T10:30:00.000Z",
"image": "https://example.com/image.jpg",
"link": "https://www.animenewsnetwork.com/news/...",
"tags": ["news", "anime"]
}
],
"meta": {
"total": 62,
"returned": 10,
"offset": 0,
"limit": 10,
"hasMore": true,
"nextCursor": "eyJvZmZzZXQiOjEwfQ",
"source": "all",
"sort": "latest",
"from": "2026-05-20",
"to": "2026-05-27",
"responseTime": "234ms",
"timestamp": "2026-05-27T12:00:00.000Z"
}
}Full-text search with relevance scoring. Title matches rank higher than excerpt matches.
| Param | Required | Description |
|---|---|---|
q |
Yes | Search query (min 2 chars) |
source |
No | Filter by source key |
limit |
No | Max results (1-100) |
offset |
No | Pagination offset |
from |
No | Start date (YYYY-MM-DD) |
to |
No | End date (YYYY-MM-DD) |
Scoring Algorithm:
- Title match: +10 points per search term
- Excerpt match: +3 points per search term
- Tiebreaker: newest date first
curl "https://aninews.vercel.app/api/search?q=demon+slayer"
curl "https://aninews.vercel.app/api/search?q=manga&source=ann&limit=5"
curl "https://aninews.vercel.app/api/search?q=crunchyroll&from=2026-05-20&to=2026-05-27"List available tags with article counts, or filter articles by tag.
# List all tags with counts
curl "https://aninews.vercel.app/api/news/tags"
# Filter articles by tag
curl "https://aninews.vercel.app/api/news/tags?tag=official"
# Filter by tag and source
curl "https://aninews.vercel.app/api/news/tags?tag=news&source=ann"📄 Example Response (tag listing)
{
"success": true,
"data": {
"tags": [
{ "name": "anime", "count": 45 },
{ "name": "news", "count": 38 },
{ "name": "official", "count": 22 }
],
"totalTags": 15,
"totalArticles": 62
},
"meta": { "timestamp": "2026-05-27T12:00:00.000Z" }
}Full article content extraction from the original URL.
curl "https://aninews.vercel.app/api/news/ann-demon-slayer-season-4-announced"📄 Example Response
{
"success": true,
"data": {
"title": "Demon Slayer Season 4 Announced",
"slug": "ann-demon-slayer-season-4-announced",
"source": "Anime News Network",
"excerpt": "The official website confirmed...",
"date": "2026-05-27T10:30:00.000Z",
"link": "https://www.animenewsnetwork.com/news/...",
"content": "<p>Full article HTML content...</p>",
"author": "John Doe",
"publishDate": "2026-05-27"
},
"meta": { "cached": false, "timestamp": "2026-05-27T12:00:00.000Z" }
}Standards-compliant RSS 2.0 XML feed. Works with any feed reader.
| Param | Default | Description |
|---|---|---|
source |
all |
Filter by source |
limit |
20 |
Max items |
curl "https://aninews.vercel.app/api/rss"
curl "https://aninews.vercel.app/api/rss?source=crunchyroll&limit=10"Per-source health monitoring. Returns fetch status, article counts, and latency.
curl "https://aninews.vercel.app/api/sources"📄 Example Response
{
"success": true,
"data": [
{
"key": "ann",
"name": "Anime News Network",
"status": "healthy",
"articleCount": 15,
"latency": "1234ms",
"lastFetch": "2026-05-27T12:00:00.000Z",
"lastError": null
},
{
"key": "crunchyroll",
"name": "Crunchyroll",
"status": "degraded",
"articleCount": 0,
"latency": "15001ms",
"lastFetch": "2026-05-27T11:55:00.000Z",
"lastError": { "message": "Timeout", "time": "2026-05-27T11:55:00.000Z" }
}
],
"meta": {
"total": 7,
"healthy": 6,
"degraded": 1,
"responseTime": "2345ms"
}
}Health check and cache statistics.
curl "https://aninews.vercel.app/api/health"
curl "https://aninews.vercel.app/api/stats"Manual cache flush. Requires API key when CACHE_CLEAR_KEY is set.
# Clear all caches
curl -X POST "https://aninews.vercel.app/api/cache/clear" \
-H "X-Api-Key: your-secret-key"
# Clear specific cache key
curl -X POST "https://aninews.vercel.app/api/cache/clear" \
-H "Content-Type: application/json" \
-H "X-Api-Key: your-secret-key" \
-d '{"key": "news_all"}'Server-Sent Events stream. Sends an initial burst of status data then closes.
curl -N "https://aninews.vercel.app/api/stream"
⚠️ Vercel Hobby functions timeout at 10s. This endpoint sends a single burst and closes. For real-time updates, poll/api/news?refresh=true.
OpenAPI 3.0.3 specification in JSON format. Use with Swagger UI, Postman, or any OpenAPI-compatible tool.
curl "https://aninews.vercel.app/api/openapi"| Field | Type | Description | Example |
|---|---|---|---|
title |
string |
Article headline | "Demon Slayer Season 4" |
slug |
string |
URL-safe identifier | "ann-demon-slayer-season-4" |
source |
string |
Display name of source | "Anime News Network" |
excerpt |
string |
Article description/summary | "The official website..." |
date |
string |
ISO 8601 publish date | "2026-05-27T10:30:00.000Z" |
image |
string |
Thumbnail URL | "https://..." |
link |
string |
Original article URL | "https://..." |
tags |
string[] |
Category tags | ["news", "anime"] |
| Field | Type | Description |
|---|---|---|
total |
number |
Total matching articles |
returned |
number |
Articles in this response |
offset |
number |
Current offset |
limit |
number |
Page size |
hasMore |
boolean |
Whether more pages exist |
nextCursor |
string|null |
Opaque cursor for next page |
source |
string |
Source filter applied |
sort |
string |
Sort order applied |
responseTime |
string |
Server processing time |
- Click the button above (or import manually on vercel.com)
- Vercel auto-detects the project — no config needed
- Your API is live! 🎉
# Or use Vercel CLI
npx vercel --prod# Clone and install
git clone https://github.com/Shineii86/AniNewsAPI.git
cd AniNewsAPI && npm install
# Start production server
npm start
# → http://localhost:3000# Build and run
docker build -t aninews-api .
docker run -p 3000:3000 aninews-api
# Or with environment variables
docker run -p 3000:3000 -e CACHE_TTL=300 -e RATE_LIMIT=200 aninews-apiThe Dockerfile includes:
- Alpine-based Node.js 20 image
npm ci --omit=devfor production-only deps- Health check via
/api/health - Graceful shutdown on SIGTERM
| Command | Description | Details |
|---|---|---|
npm run dev |
🔥 Start development server | Runs on localhost:3000 |
npm start |
🚀 Start production server | NODE_ENV=production node server.js |
npm test |
🧪 Run integration tests | Tests all endpoints |
npm run lint |
🔍 Run ESLint | Check code quality |
npm run lint:fix |
🔧 Auto-fix lint issues | Fix what's possible |
npm run build |
📦 Build (no-op for serverless) | Vercel handles this |
| Metric | Value |
|---|---|
| ⚡ Cached response | ~200ms |
| 🔄 Fresh fetch (all 13 sources) | ~3-6s |
| 💾 Cache TTL | 10 minutes |
| 🔁 Retry attempts | 3 per source |
| ⏱️ Timeout per source | 15 seconds |
| 📰 Total articles (avg) | 150+ after dedup |
| 📦 Total codebase | ~50KB |
- 💾 Two-tier cache — Memory-first with disk fallback
- ⚡ Concurrent fetching — All 13 sources hit simultaneously
- 🔄 Exponential backoff — 1s, 2s, 3s delays on retry
- 🧹 Auto-cleanup — Stale rate limit buckets purged every 5 min
- 📁 Disk persistence — Source metrics survive serverless cold starts
- 🗜️ Minimal deps — Only 6 production dependencies
| Version | Date | Key Changes |
|---|---|---|
| 5.1.0 | 2026-08-01 | 6 new sources (13 total), shared image extraction utility |
| 5.0.0 | 2026-07-31 | Shared fetch module, Docker, HEAD support, request IDs, ESLint, version sync |
| 4.2.2 | 2026-05-28 | TOS/Privacy route restoration |
| 4.2.0 | 2026-05-28 | Code style overhaul — AlisaReactionBot-style documentation |
| 4.1.6 | 2026-05-27 | Full excerpts, no truncation — removed 200-char limit |
| 4.1.0 | 2026-05-26 | Date range filtering, cursor pagination, search scoring |
📝 See CHANGELOG.md for the full version history.
| Problem | Cause | Solution |
|---|---|---|
❌ npm install fails |
Node.js version too old | Upgrade to Node.js 20+ (node -v) |
| ❌ No articles returned | All sources down | Check /api/sources for health status |
| ❌ Cache always empty | Serverless cold start | Normal — first request after idle is slow |
| ❌ Rate limited (429) | Exceeded 100 req/min | Wait for X-RateLimit-Reset seconds |
| ❌ CORS errors | Frontend domain blocked | CORS is * — check browser extension |
| ❌ RSS feed empty | No cached articles | Hit /api/news first to populate cache |
| ❌ Article content empty | Source blocked parsing | Falls back to "View original article" link |
| ❌ 404 on API routes | Wrong URL format | Use /api/news not /news |
| ❌ Deploy fails on Vercel | Build error | Check npm run build locally first |
| ❌ Tests failing | Server not running | Start server first with npm run dev |
# Run with verbose logging
NODE_ENV=development npm run dev
# Run tests against local server
API_URL=http://localhost:3000 npm test
# Check cache state
curl http://localhost:3000/api/stats
curl http://localhost:3000/api/health📰 How do I add a new news source?
1. Create
utils/fetchNewSource.js exporting an async function that returns an array of article objects: [{ title, slug, source, excerpt, date, image, link, tags }]2. Register it in
utils/sources.js — add an import and entry to the SOURCES object3. Run
npm test to verify, then submit a PR
🔄 How often does the data refresh?
The cache TTL is 10 minutes by default. After that, the next request triggers a fresh fetch from all 13 sources. You can force a refresh with
?refresh=true or change the TTL with the CACHE_TTL environment variable.
📡 Can I use this in my frontend app?
Yes! CORS is enabled for all origins (
*). Just make fetch requests to the API endpoints. No API key needed for read operations. Example: fetch('https://aninews.vercel.app/api/news?limit=10')
🗞️ How do I subscribe to the RSS feed?
Add
https://aninews.vercel.app/api/rss to any feed reader (Feedly, Inoreader, NetNewsWire, etc.). You can filter by source: /api/rss?source=crunchyroll
📊 How does deduplication work?
Articles are deduplicated by normalized title — punctuation is stripped, whitespace is collapsed, and compared case-insensitively. The first occurrence (from the source that responded fastest) wins.
🔒 Is the cache clear endpoint secure?
When
CACHE_CLEAR_KEY is set, the endpoint requires an X-Api-Key header. Without the env var, the endpoint is open — so set it in production. Read endpoints (/api/news, etc.) are always open.
⏱️ Why is the first request slow?
On serverless (Vercel), the first request after idle triggers a "cold start" — the function initializes and fetches from all 13 sources (~3-6s). Subsequent requests hit the cache (~200ms). Warm functions stay alive for ~5 minutes.
🌐 Can I self-host this?
Yes! Use
npm start to run the Express server on any VPS, Docker container, or PaaS. The Vercel serverless functions are optional — server.js handles everything.
- 🔐 API key authentication — Per-user rate limits and usage tracking
- 📊 Admin dashboard — Web UI for cache management and source monitoring
- 🌙 Dark/light mode — Theme toggle for the landing page
- 📱 PWA support — Install as app on mobile devices
- 🔔 Webhook notifications — Push new articles to Discord/Slack
- 📈 Analytics — Track popular endpoints and search queries
- 🗄️ Database option — Optional Supabase/Postgres for persistence
- 🌐 Multi-language — Support for Japanese, Korean news sources
- 🤖 AI summaries — Auto-generate article summaries
- 📦 NPM package — Client SDK for easy integration
- 📰 13 news sources with concurrent fetching
- 💾 Two-tier caching (memory + disk)
- 🔍 Full-text search with relevance scoring
- 📅 Date range filtering
- 🔄 Cursor-based pagination
- 🗞️ RSS 2.0 feed
- 📄 Full article extraction
- 🏷️ Tag filtering with counts
- 📊 Source health monitoring
- 📋 OpenAPI 3.0.3 specification
- 📡 SSE stream
- 🔒 Cache clear authentication
- 🚀 One-click Vercel deployment
- 📖 Comprehensive documentation
- 🐳 Docker deployment with Dockerfile
- 🆔 Request ID tracing (UUID v4)
- ⏳ HEAD method support on all GET endpoints
- 📦 Shared fetch module (DRY — fetchAllSources.js)
- 📋 ESLint configuration for code quality
- 🔄 Retry-After header on 429 responses
- 📌 Centralized CACHE_KEYS constants
- 📰 6 additional sources (Tokyo Otaku Mode, Anime Trending, Anime UK News, Random Curiosity, Honey's Anime, Otaku News)
- 🖼️ Shared image extraction utility (extractImage.js)
- 🔧 ESLint false-positive fix (no-promise-executor-return)
Contributions are welcome and appreciated! Here's how you can help:
|
Found something broken? |
Have an idea for the notebook? |
Ready to contribute code? |
# 1️⃣ Fork the repository
# Click the "Fork" button on GitHub
# 2️⃣ Clone your fork
git clone https://github.com/YOUR_USERNAME/AniNewsAPI.git
cd AniNewsAPI
# 3️⃣ Create a feature branch
git checkout -b feature/amazing-feature
# 4️⃣ Make your changes
# Edit files, add features, fix bugs...
# 5️⃣ Test your changes
npm test
# 6️⃣ Commit your changes
git commit -m 'feat: add amazing feature'
# 7️⃣ Push to your fork
git push origin feature/amazing-feature
# 8️⃣ Open a Pull Request
# Go to GitHub and create a PR- ✅ Follow the existing code style and documentation conventions
- ✅ Write meaningful commit messages (use conventional commits)
- ✅ Run
npm testbefore submitting - ✅ Update CHANGELOG.md with your changes
- ✅ Keep PRs focused — one feature or fix per PR
- ✅ Add JSDoc comments for new functions
- ❌ Don't commit
node_modulesor cache files - ❌ Don't add unrelated changes to a single PR
- Check existing issues first
- Create a new issue with:
- Clear title and description
- Steps to reproduce
- Expected vs actual behavior
- API endpoint and parameters used
- Check the Roadmap for planned features
- Open a feature request with:
- Clear description of the feature
- Use case / motivation
- Example API usage if applicable
| Source | About |
|---|---|
| Anime News Network | Industry-leading anime journalism |
| Anime Corner | Community-driven anime news & polls |
| MyAnimeList | The largest anime/manga database |
| Otaku USA Magazine | English-language anime culture magazine |
| Crunchyroll | Official streaming platform news |
| Anime Herald | Anime news, reviews & editorials |
| Comic Book | Anime & manga coverage at ComicBook |
| Tokyo Otaku Mode | Anime culture & merchandise news |
| Anime Trending | Weekly community charts & rankings |
| Anime UK News | UK/EU anime news & reviews |
| Random Curiosity | Season previews & episode reviews |
| Honey's Anime | Music/anisong & VTuber news |
| Otaku News | UK/US interviews & industry news |
- Express — Fast, unopinionated web framework
- Cheerio — Fast, flexible HTML parsing
- Axios — Promise-based HTTP client
- rss-parser — RSS/Atom feed parser
- node-cache — In-memory caching
- Vercel — Serverless deployment platform
- Shields.io — Badges for README
- Star History — GitHub star history charts
This project is licensed under the MIT License.
Free to use, modify, and distribute — see the LICENSE file for details.
Shinei Nouzen
Full-Stack Developer & Anime Enthusiast
⭐ If you found this project useful, please consider giving it a star!
Made With ❤️ For The Anime Community
© Shinei Nouzen. All Rights Reserved.