How to Build a News Aggregator App in 30 Minutes (2026)

Erick Horn

Erick Horn

·

18 mins läsa

How to Build a News Aggregator App in 30 Minutes (2026)

How to Build a News Aggregator App in 30 Minutes (APITube + Vanilla JS)

A news aggregator app is a single interface that pulls articles from many publishers through one API and displays them together. No RSS scraping, no per-site parsers — one fetch call returns a unified feed. This tutorial builds a working one in vanilla HTML and JavaScript, with search, language filter, source-quality badges, and honest rate-limit handling, all in under 30 minutes.

This article is for developers who know basic JavaScript (arrays, fetch, DOM) and want a shippable project, not another copy-paste exercise that breaks on deploy.

Disclosure: this tutorial uses APITube, a news API I work on. The code works with any JSON-returning news API if you swap the endpoint.

Key takeaways

  • A news aggregator app pulls articles from many publishers through one API call, not many.
  • You can ship a working one in vanilla HTML and JavaScript in under 30 minutes.
  • Only three production traps matter: API-key secrecy, rate-limit handling, and CORS.
  • APITube's free tier (30 requests per 30 minutes) is enough to build and demo; production needs a backend proxy.

What you'll build (1 min)

A single-page aggregator that:

  • Shows 20 current articles in a card layout
  • Has a search box (title match) and a language dropdown
  • Displays the source name, a 3-tier source-quality badge, and the article category
  • Handles quota-exhausted responses gracefully instead of blanking out

By the end: one index.html + style.css + app.js. No framework, no build step, no backend. Zero dependencies.

Prerequisites (1 min)

  • A browser (Chrome or Firefox — I'll explain a production CORS note later)
  • A code editor
  • An APITube free API key (next step)

No Node.js, no npm. If you can open an HTML file in a browser, you're set.

Step 1 — Get your APITube API key (2 min)

Go to apitube.io, sign up, and copy the API key from your dashboard. The free tier is 30 requests per 30 minutes, first page only — enough to develop and test this tutorial several times over.

Create a .env file in your project folder:

APITUBE_KEY=your_key_here

Add .env to a .gitignore file next to it:

.env

Why bother with .env in a vanilla-JS project? Because you'll eventually move this key behind a server or serverless function for production — and checking keys into git is a one-way mistake. We'll load it into the browser via a config.js placeholder for now, but the discipline starts here.

Step 2 — Set up the project (3 min)

Create three files in a folder called news-app:

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>News Aggregator</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
    <h1>News Aggregator</h1>
    <div class="controls">
      <input id="search" placeholder="Search headlines..." />
      <select id="lang">
        <option value="en">English</option>
        <option value="de">German</option>
        <option value="fr">French</option>
        <option value="es">Spanish</option>
      </select>
    </div>
  </header>
  <main id="feed"></main>
  <script src="config.js"></script>
  <script src="app.js"></script>
</body>
</html>

config.js (gitignored eventually; for the tutorial, hardcode your key here and keep it out of git):

window.APITUBE_KEY = "your_key_here";

style.css (minimal, copy as-is):

* { box-sizing: border-box; margin: 0; padding: 0; font-family: system-ui, sans-serif; }
body { background: #f6f7f9; color: #1a1a1a; padding: 24px; max-width: 960px; margin: 0 auto; }
header { margin-bottom: 24px; }
h1 { font-size: 28px; margin-bottom: 12px; }
.controls { display: flex; gap: 8px; }
.controls input, .controls select { padding: 8px 12px; font-size: 14px; border: 1px solid #ddd; border-radius: 6px; }
.controls input { flex: 1; }
.card { background: white; padding: 16px; border-radius: 8px; margin-bottom: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
.card h2 { font-size: 18px; margin-bottom: 6px; }
.card a { color: #0066cc; text-decoration: none; }
.meta { font-size: 13px; color: #666; margin-top: 8px; display: flex; gap: 8px; flex-wrap: wrap; }
.badge { padding: 2px 8px; border-radius: 4px; font-size: 12px; }
.badge-tier1 { background: #d4edda; color: #155724; }
.badge-tier2 { background: #fff3cd; color: #856404; }
.badge-tier3 { background: #f8d7da; color: #721c24; }
.error { background: #fff3cd; padding: 16px; border-radius: 8px; color: #856404; }

Step 3 — Fetch articles from APITube (8 min)

Create app.js:

const API = "https://api.apitube.io/v1/news/everything";

async function fetchNews({ query = "", language = "en" } = {}) {
  const params = new URLSearchParams({
    "language.code": language,
    "per_page": 20,
    "sort.by": "published_at",
    "sort.order": "desc"
  });
  if (query) params.set("title", query);

  const res = await fetch(`${API}?${params}`, {
    headers: { "X-API-Key": window.APITUBE_KEY }
  });

  if (res.status === 429) throw new Error("QUOTA_EXHAUSTED");
  if (!res.ok) throw new Error(`HTTP ${res.status}`);

  const data = await res.json();
  return data.results || [];
}

Three things worth noting:

  1. Async/await, not .then(). Error handling with try/catch reads cleaner and matches any modern codebase you'll land in.
  2. HTTP 429 gets a named error. Every news API sends 429 when you hit the quota. Catching it specifically lets us show something useful instead of a white page.
  3. The API key lives in a header, not a query parameter. Query-string keys leak into browser history, referrer headers, and server logs. APITube enforces header-only auth for a reason.

A note on CORS: this code runs in the browser because APITube allows cross-origin requests with the X-API-Key header. Not every news API does — NewsAPI.org, notably, blocks browser-origin requests on its free plan entirely. If you swap APIs later, you may need a tiny serverless proxy (Cloudflare Worker or Vercel function — 15 lines).

Step 4 — Render article cards with source rank and category (7 min)

Most tutorials render title + description + image and call it done. APITube's response has 15+ fields. Here are two that make your app look less like a toy:

  • source.rank.level — integer 1-3 where 1 = tier-1 outlet (Reuters, BBC), 3 = long tail
  • categories[0].name — e.g., "Technology", "Finance"

Add this to app.js:

const feedEl = document.getElementById("feed");

function render(articles) {
  feedEl.innerHTML = "";
  if (articles.length === 0) {
    feedEl.innerHTML = "<p>No articles found.</p>";
    return;
  }
  for (const a of articles) {
    const tier = a.source?.rank?.level || 3;
    const category = a.categories?.[0]?.name || "General";
    const card = document.createElement("article");
    card.className = "card";
    card.innerHTML = `
      <h2><a href="${a.href}" target="_blank" rel="noopener">${a.title}</a></h2>
      <p>${a.description || ""}</p>
      <div class="meta">
        <span>${a.source?.name || "Unknown"}</span>
        <span class="badge badge-tier${tier}">Tier ${tier}</span>
        <span class="badge">${category}</span>
        <span>${new Date(a.published_at).toLocaleDateString()}</span>
      </div>
    `;
    feedEl.appendChild(card);
  }
}

Note: textContent isn't used here because we trust the API's cleaned output — but if you were rendering user-submitted search terms into the DOM, you'd want to sanitize. The API fields themselves are safe to interpolate.

Step 5 — Add search and language filter (6 min)

Wire the inputs to a re-fetch on change. Debounce search by 400 ms so we don't burn quota on every keystroke:

const searchEl = document.getElementById("search");
const langEl = document.getElementById("lang");

let timer;
function debouncedLoad() {
  clearTimeout(timer);
  timer = setTimeout(load, 400);
}

async function load() {
  try {
    const articles = await fetchNews({
      query: searchEl.value.trim(),
      language: langEl.value
    });
    render(articles);
  } catch (err) {
    showError(err);
  }
}

searchEl.addEventListener("input", debouncedLoad);
langEl.addEventListener("change", load);

load();

That's the entire interactivity layer. Typing "climate" filters to articles with "climate" in the title. Changing language swaps the feed.

Step 6 — Handle rate limits and errors (3 min)

This is the step every tutorial skips. On the free tier, the app above burns through 30 requests fast during development. Without handling, your UI goes blank and users blame the app. Handle it:

function showError(err) {
  const msg = err.message === "QUOTA_EXHAUSTED"
    ? "You've hit the free-tier limit (30 requests per 30 minutes). Try again shortly."
    : `Couldn't load news: ${err.message}`;
  feedEl.innerHTML = `<div class="error">${msg}</div>`;
}

Quota math for real usage: 30 requests per 30 minutes = one refresh every 60 seconds if a user holds the tab open. Fine for personal use, not fine for anything deployed to more than one user. Two production moves:

  1. Cache responses in localStorage with a 5-minute TTL — cuts calls by roughly 80% for normal browsing
  2. Move the fetch server-side when you deploy — one backend call can serve many users from one cached response

Both are 20-line additions, not rewrites. The free tier exists to prototype; pick a production path before you deploy.

Complete code

You now have three files: index.html, style.css, app.js, and a gitignored config.js holding your key. Open index.html in a browser — you'll see 20 articles with search and language filters that actually work.

A runnable version: github.com/apitube-examples/news-aggregator-30min (clone, add your key to config.js, open index.html).

Which news API should you use?

Every tutorial picks one API without explaining why. I've used these four across client projects. The criteria: free-tier usability, source count, response richness, and whether the API actively blocks browser usage.

APIFree TierSourcesResponse RichnessBrowser-Friendly
APITube30 req / 30 min, first page300,000+Sentiment, entities, source rank, categories, summaryYes
NewsAPI.org100 req/day~80,000Title, description, url, imageNo (CORS blocked on free)
NewsData.io200 req/day~60,000Title, description, categoryPartial
GNews100 req/day~60,000Title, description, imageYes

Unlike NewsAPI.org, which blocks browser requests on its free tier, APITube and GNews allow direct client-side calls — which means you can ship this tutorial to a demo URL without a serverless proxy.

Methodology: I built this same aggregator against each API, counted distinct sources returned for title=climate&language.code=en, and checked whether the browser request worked without a proxy.

Rough guide:

  • Rich fields + browser-ready → APITube
  • Tightest budget, willing to add a backend → NewsAPI.org
  • Simple needs, Latin-alphabet languages → GNews

If you want the long version with monthly-cost math at scale, see the pillar comparison: apitube.io/blog/best-news-api-2026-comparison. For language-specific ergonomics: apitube.io/blog/best-news-api-javascript-nodejs-2026.

FAQ

What is a news aggregator app?

A news aggregator app is a client application that fetches articles from many publishers through one API and displays them in a single unified interface. Unlike a per-site news reader that connects to each publisher separately, a news aggregator pulls from hundreds or thousands of sources in one call, which means you write one fetch instead of one parser per outlet.

Which API is best for building a news aggregator?

The best news API for a beginner aggregator is APITube, because it allows browser-based requests without a proxy and returns rich fields (sentiment, source ranking, entities, categories) that let you render a better UI in fewer lines of code. NewsAPI.org is cheaper per request but blocks browser calls on the free tier, so it requires a backend. GNews is the simplest option for Latin-alphabet-only projects.

How long does it take to build a news aggregator?

Building a functional news aggregator with search, filters, and error handling takes about 30 minutes when you use a news API, which is the target for this tutorial. Building the same app from scratch (per-publisher scrapers, parsers, storage) takes 1–2 weeks; adding production features like caching, a backend proxy, and auth adds roughly one weekend on top of the 30-minute prototype.

Is it legal to build a news aggregator?

Building a news aggregator is legal when you use a licensed news API such as APITube or NewsAPI.org, because the API provider handles publisher licensing on your behalf. What is not legal is scraping headlines and article bodies directly from publisher websites and republishing them without permission — that is a copyright issue regardless of how the aggregator is built.

Do I need a backend for a news aggregator app?

A news aggregator app does not need a backend for personal or demo use; this tutorial runs entirely in the browser with one fetch call. A backend is required in production, because the API key must stay off the client, responses should be cached to avoid per-user quota burn, and some news APIs (NewsAPI.org, for example) block browser calls outright. A 15-line Cloudflare Worker or Vercel serverless function is the minimum viable backend.

Next steps

With 30 minutes of work you have a news aggregator that reads more fields than most tutorials, survives a rate-limit hit without crashing, and justifies its API choice. Three natural extensions:

  1. Save articles to localStorage for offline reading
  2. Add category filters using categories[].id
  3. Deploy behind a serverless function so the API key lives on the server

Try APITube free — 30 requests every 30 minutes on the free tier, no credit card. apitube.io

Resources

Related guides:

APITube - News API

Relaterade artiklar

Nyhets-API Snabbstart: Din första begäran på 5 minuter</h4><h2></h2>
Developer Guides

Nyhets-API Snabbstart: Din första begäran på 5 minuter</h4><h2></h2>

Nå en verklig nyhets-API-slutpunkt på 5 minuter — curl, JavaScript och Python sida vid sida, med ett kommenterat JSON-svar och lösningar för de 401/429-fel du faktiskt kommer att stöta på.</h4><h2></h2>

Next.js Flerspråkig App-handledning 2026: UI Innehåll i18n</h4><h2></h2>
Developer Guides

Next.js Flerspråkig App-handledning 2026: UI Innehåll i18n</h4><h2></h2>

Bygg en flerspråkig Next.js 16-app: next-intl för UI-strängar, APITube för innehåll på 60 språk, fungerande hreflang och en flerspråkig webbplatskarta. Serverkomponenter, RTL och Vercel Edge-distribution – gratis nivå inkluderad.</h4><h2></h2>

10 Nyhets-API-filtermönster du bör känna till (2026)</h4><h2></h2>
Developer Guides

10 Nyhets-API-filtermönster du bör känna till (2026)</h4><h2></h2>

10 körbara nyhets-API-filtermönster – titelsökning, datum, entiteter, sentiment, källor och sammansatta frågor – med curl-, Python- och JSON-exempel plus tricket som slösar bort din första dag.

Telegram Nyhetsbot i Python (2026): aiogram APScheduler
Developer Guides

Telegram Nyhetsbot i Python (2026): aiogram APScheduler

Bygg en Telegram-nyhetsbot i Python med aiogram 3.27, APScheduler och APITube. Asynkron, sentiment-filtrerad, automatisk kanalinläggning — fullständig kod Docker.

Vi använder cookies

Genom att klicka på "Acceptera" godkänner du att cookies lagras på din enhet för funktion och analys.