⏱️ Lectura: 14 min

Hacker Times apareció hace pocos días en Hacker News con un formato poco común: presenta las historias del sitio como la portada de un periódico, con ediciones por hora y enlaces directos a la fuente original. Detrás de ese diseño no hay ningún acuerdo especial con Y Combinator ni acceso privilegiado a datos: hay una API de Hacker News pública, gratuita y sin autenticación que cualquiera puede consultar desde su propia terminal.

📑 En este artículo
  1. TL;DR
  2. ¿Qué es la API de Hacker News?
  3. Por qué importa
  4. Cómo funciona por dentro
    1. Flujo de un lector básico
  5. Ejemplos prácticos
    1. Secuencia de peticiones
  6. Cómo empezar
  7. Casos de uso reales
  8. Errores comunes y buenas prácticas
  9. Comparativa con alternativas
  10. Profundizando
  11. Preguntas frecuentes
    1. ¿El endpoint público de Hacker News necesita una API key?
    2. ¿Con qué frecuencia se actualiza topstories.json en Hacker News?
    3. ¿La interfaz REST de Hacker News permite buscar por palabra clave?
    4. ¿Qué significa que un item de Hacker News tenga dead o deleted en true?
    5. ¿Hay límite de peticiones por segundo en la Hacker News API?
  12. Referencias
    1. 📚 Artículos relacionados

Construir algo similar no exige pedir permiso ni token de acceso. Alcanza con entender los endpoints disponibles, cómo se estructuran los datos y qué límites prácticos tiene esa interfaz cuando la usás en serio.

TL;DR

  • La API de Hacker News vive en hacker-news.firebaseio.com/v0/ y no pide API key ni registro.
  • topstories.json, newstories.json y beststories.json devuelven arrays de IDs, nunca el contenido completo.
  • Cada item.json trae un objeto con by, score, time, title, type y url, o null si fue borrado.
  • Algolia replica el mismo contenido en hn.algolia.com/api con búsqueda de texto completo.
  • Un lector personalizado funcional entra en menos de 30 líneas de JavaScript con fetch nativo de Node.js.

¿Qué es la API de Hacker News?

La API de Hacker News es la interfaz pública de solo lectura que expone en JSON cada historia, comentario y usuario del sitio de Y Combinator. Corre sobre Firebase Realtime Database, no requiere autenticación ni clave, y permite construir lectores o bots con los mismos datos que usa el sitio original.

El proyecto es open source y lo mantiene el propio equipo de Hacker News en GitHub. La documentación completa, con cada endpoint y el esquema de cada tipo de dato (story, comment, job, poll, pollopt), vive en el repositorio HackerNews/API.

A diferencia de muchas APIs comerciales, no hay cuotas pagadas ni planes. Es un recurso que la comunidad mantiene para la comunidad, y por eso un script que dispare miles de peticiones por segundo termina perjudicando a todos los demás clientes que comparten el mismo backend.

El endpoint topstories.json devuelve hasta 500 IDs, nunca el contenido completo de cada historia. Foto de Julio Lopez en Unsplash

Por qué importa

Antes de esta API, enterarse de qué pasaba en Hacker News significaba abrir el sitio y actualizar la pestaña a mano. Hoy existen lectores alternativos, bots de Slack, extensiones de navegador y boletines automatizados que corren sobre los mismos endpoints, sin pedir permiso a nadie.

Hacker Times es un ejemplo reciente: toma las historias del día y las presenta como una edición de periódico, con portada propia y actualizaciones por hora. El proyecto se publicó como Show HN y, como cualquier otro cliente, solo necesita hacer peticiones HTTP a la misma interfaz pública que vas a usar en este artículo.

También importa como caso de estudio de diseño de API: expone datos crudos sin capas de permisos, delega la búsqueda de texto a un tercero (Algolia) en lugar de construirla él mismo, y deja la presentación completamente en manos del desarrollador. Esa apertura tiene un costo, eso sí: sin llaves ni cuotas, la única barrera contra el abuso es la buena fe de quien consume los datos, así que cachear y espaciar peticiones queda en manos de cada cliente, no del servidor.

Cómo funciona por dentro

La API corre sobre Firebase Realtime Database, el mismo servicio de Google que usan miles de apps móviles para sincronizar datos. Eso explica por qué cada URL termina en .json: no es una convención REST elegida a propósito, es literalmente cómo Firebase expone cualquier nodo de su árbol de datos.

Los endpoints se dividen en dos grupos. El primero son listas de IDs: topstories, newstories, beststories, askstories, showstories y jobstories. Cada una devuelve un array plano de números enteros, nunca el contenido de la historia. El segundo grupo son items individuales, en /v0/item/{id}.json, que trae el objeto completo de una historia, comentario, encuesta, opción de encuesta o posición de trabajo, según el valor de su campo type.

Cada item tiene un set de campos fijo según su tipo. Una story trae by (usuario), score, time (timestamp Unix), title, url y kids (los IDs de sus comentarios de primer nivel). Un comment trae parent en lugar de url, y su propio kids con las respuestas anidadas. Si pedís un id borrado o marcado como muerto por moderación, los campos deleted o dead vienen en true.

Hay un detalle que rompe expectativas la primera vez: pedir /v0/item/999999999.json, un id que nunca existió, no devuelve un error 404. Devuelve null con código 200. El código tiene que filtrar nulls antes de leer story.title, o el script revienta con un TypeError.

curl https://hacker-news.firebaseio.com/v0/maxitem.json

Ese comando confirma que la API de Hacker News está viva: devuelve un entero que crece con cada historia o comentario nuevo en el sitio, por ejemplo 45102873. Si ese número no cambia en varios minutos de actividad normal, el problema está en tu red, no en Firebase.

Flujo de un lector básico

flowchart TD
    A["Tu script"] --> B["GET /v0/topstories.json"]
    B --> C["Array de hasta 500 IDs"]
    C --> D["GET /v0/item/ID.json (por cada ID)"]
    D --> E["Objeto story: title, score, by, url"]
    E --> F["Tu lector o filtro"]

Ejemplos prácticos

El ejemplo más corto posible es pedir una sola historia ya publicada, para ver la forma exacta de la respuesta:

curl https://hacker-news.firebaseio.com/v0/item/8863.json

Esa es, literalmente, la respuesta documentada en el repositorio oficial para el id 8863: la historia con la que Drew Houston presentó Dropbox en Hacker News en 2007.

{
  "by": "dhouston",
  "id": 8863,
  "score": 111,
  "time": 1175714200,
  "title": "My YC app: Dropbox - Throw away your USB drive",
  "type": "story",
  "url": "http://www.getdropbox.com/u/2/screencast.html"
}

El formato no cambió en casi veinte años. El segundo paso es traer una lista de portada completa. Con fetch nativo de Node.js, incluido desde la versión 18 sin instalar nada:

const res = await fetch("https://hacker-news.firebaseio.com/v0/topstories.json");
const ids = await res.json();
console.log(ids.slice(0, 5));

Eso imprime un array de cinco enteros, por ejemplo [41234567, 41234321, 41233890, 41233654, 41233112]. Los valores cambian todo el tiempo porque la lista se reordena cuando una historia sube o baja en el ranking, pero la forma, un array plano de números, es siempre la misma.

El tercer paso combina ambas llamadas para construir algo útil: una función que trae las N historias más nuevas de portada y las filtra por puntaje mínimo.

async function getTopStories(limit = 10, minScore = 100) {
  const idsRes = await fetch("https://hacker-news.firebaseio.com/v0/topstories.json");
  const ids = (await idsRes.json()).slice(0, limit);

  const stories = await Promise.all(
    ids.map(id =>
      fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`).then(r => r.json())
    )
  );

  return stories.filter(story => story && story.score >= minScore);
}

getTopStories().then(stories => {
  stories.forEach(s => console.log(`${s.score} pts - ${s.title}`));
});

Promise.all dispara las N peticiones de item.json en paralelo en vez de esperarlas una por una, lo que reduce el tiempo total de varios segundos a unos pocos cientos de milisegundos. La salida, impresa con forEach, se ve así (los puntajes y títulos cambian en cada corrida real):

342 pts - Rust 1.90 ya esta disponible
218 pts - Show HN: construi mi propio lector de Hacker News
155 pts - A deep dive into io_uring

💡 Tip: cachear el resultado de topstories.json en memoria durante 60 segundos evita golpear la API en cada render de tu interfaz sin perder frescura real.

Agregar un filtro por palabra clave, para armar algo parecido a una alerta temática, es una función más encima de la anterior:

function filterByKeyword(stories, keyword) {
  return stories.filter(s =>
    s.title && s.title.toLowerCase().includes(keyword.toLowerCase())
  );
}

Secuencia de peticiones

sequenceDiagram
    participant C as Cliente
    participant F as Firebase HN API
    C->>F: GET /v0/topstories.json
    F-->>C: array de hasta 500 ids
    loop por cada id
        C->>F: GET /v0/item/id.json
        F-->>C: objeto story o null
    end
    Note over C,F: sin autenticacion, solo HTTPS
Node.js incluye fetch de forma nativa desde la versión 18, sin instalar paquetes adicionales. Foto de Albert Stoynov en Unsplash

Cómo empezar

Requisitos: Node.js 18 o superior y una conexión a internet, sin cuenta ni token de ningún tipo.

  1. Instalá Node en Linux o macOS con nvm (nvm install 22) o el gestor de paquetes de tu distribución; en Windows, winget install OpenJS.NodeJS.LTS hace lo mismo en un solo comando.
  2. Verificá la versión con node -v: debe imprimir v18 o más nuevo, por ejemplo v22.11.0.
  3. Creá una carpeta y un archivo lector.js.
  4. Pegá dentro la función getTopStories del ejemplo anterior junto con el bloque que la ejecuta.
  5. Corré node lector.js desde la terminal.
  6. Deberías ver una lista de líneas con puntaje y título, una por historia que pasó el filtro de score mínimo.

Casos de uso reales

  • Lectores alternativos con diseño propio: Hacker Times es el ejemplo que abrió este artículo, con formato de periódico y ediciones por hora, pero el mismo patrón sirve para un lector minimalista en terminal.
  • Búsqueda de texto completo: hn.algolia.com es, en sí mismo, un lector construido por Algolia sobre los mismos datos, con un índice de búsqueda que la API oficial no ofrece.
  • Bots de chat: scripts que postean en Slack, Discord o Telegram las historias que superan cierto puntaje apenas aparecen en topstories.
  • Dashboards de tendencias: acumular topstories cada hora para graficar qué temas, como IA o seguridad, dominan la semana.
  • Archivos personales: guardar en una base local las historias con más de X puntos, para tener un archivo histórico propio sin depender del sitio.

Errores comunes y buenas prácticas

  • No filtrar nulls: item.json puede devolver null; acceder a .title sobre null tira un TypeError.
  • Ignorar dead y deleted: mostrarlos igual puede confundir al usuario final; lo normal es ocultarlos o marcarlos como eliminados.
  • Pedir items en serie: un for con await secuencial multiplica por N el tiempo de respuesta frente a Promise.all.
  • Asumir orden estable: topstories.json cambia constantemente, así que para comparar posiciones hay que trackear por ID, no por índice del array.
  • No cachear: pedir el mismo item.json varias veces en segundos desperdicia peticiones; unos minutos de caché alcanzan para un lector personal.
  • Polling agresivo: no hay rate limit documentado, pero eso no es invitación a golpear el servidor cada 100 ms; 30 a 60 segundos sobra para cualquier lector humano.

⚠️ Ojo: un id inexistente responde 200 con body null, no 404. Validar explícitamente ese caso evita que tu lector se caiga entero por una sola historia borrada.

Comparativa con alternativas

La API oficial no es la única puerta a los datos de Hacker News. Elegir entre ella, Algolia y el scraping depende de si necesitás búsqueda, qué tan en tiempo real querés los datos y cuánto mantenimiento estás dispuesto a asumir.

Opción Cuándo usarla Ventaja Limitación
API oficial (Firebase) Lector básico, bots, dashboards Gratis, sin auth, datos casi en tiempo real Sin búsqueda de texto; un request por item
Algolia HN Search API Buscar por palabra clave o rango de fechas Búsqueda full-text con filtros por fecha y tipo No la mantiene YC directamente, sino Algolia
Scraping HTML Datos que ningún endpoint expone (orden visual exacto) Acceso a cualquier dato visible en la página Rompe con cada cambio de diseño del sitio

Profundizando

Todo lo anterior usa polling: pedís datos, esperás la respuesta, repetís cada N segundos. Pero como la base es Firebase Realtime Database, existe una alternativa que empuja los cambios en vez de que el cliente los pida: suscribirse directamente con el SDK de Firebase.

El propio repositorio de la API de Hacker News documenta esta vía: en lugar de pedir REST, el cliente Firebase se conecta al proyecto y usa .on('value', callback) sobre un nodo como v0/item/{id}, de forma que el callback se dispara solo cuando ese nodo cambia, sin que el código tenga que volver a preguntar.

Para detectar cambios sin suscribirse nodo por nodo existe además /v0/updates.json, que devuelve dos arrays: items (IDs de historias o comentarios que cambiaron recientemente) y profiles (usuarios que actualizaron su perfil). Para confirmar que realmente refleja actividad reciente, pedilo dos veces con un minuto de diferencia: con tráfico normal, el array items debería traer IDs distintos en cada corrida.

La contrapartida de usar el SDK de Firebase en vez de REST es sumar una dependencia más y un modelo de conexión persistente, en lugar de simples peticiones HTTP sin estado. Para un bot simple o un script que corre una vez al día, fetch alcanza; para un dashboard que necesita reflejar cambios en vivo, la suscripción evita miles de peticiones repetidas.

stateDiagram-v2
    [*] --> Polling
    Polling --> Polling : GET cada N segundos
    Polling --> Desactualizado : intervalo largo
    [*] --> Suscripcion
    Suscripcion --> Actualizado : push automatico via SDK Firebase

Tu próximo paso: cloná la función getTopStories de este artículo, modificala para guardar en un archivo JSON local las historias con score mayor a 300, y programala con cron para correr una vez por hora.

📖 Resumen en Telegram: Ver resumen

📬 Recibí lo nuevo en tu email

Te avisamos de artículos grandes (1-2 por mes).

Preguntas frecuentes

¿El endpoint público de Hacker News necesita una API key?

No. Es de solo lectura, pública y no exige registro, token ni cabecera de autenticación: cualquier petición GET a hacker-news.firebaseio.com/v0/ funciona directo desde el navegador o la terminal.

¿Con qué frecuencia se actualiza topstories.json en Hacker News?

No hay un intervalo fijo documentado: el array se reordena cada vez que el algoritmo de ranking del sitio recalcula posiciones, lo que en horas de tráfico alto puede ser cada pocos minutos.

¿La interfaz REST de Hacker News permite buscar por palabra clave?

No de forma nativa. Para búsqueda de texto completo, por fecha o por autor, el proyecto comunitario Algolia expone los mismos datos indexados en hn.algolia.com/api.

¿Qué significa que un item de Hacker News tenga dead o deleted en true?

dead indica que la historia o el comentario fue removido por moderación pero su ID sigue existiendo; deleted indica que el propio autor lo borró. En ambos casos item.json puede devolver el objeto con esos flags.

¿Hay límite de peticiones por segundo en la Hacker News API?

No hay un rate limit documentado públicamente, pero al ser un servicio gratuito mantenido por la comunidad, lo correcto es cachear resultados y espaciar las peticiones: abusar de la frecuencia perjudica a todos los demás clientes que comparten el mismo backend.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

Imagen destacada: Foto de Mika Baumeister en Unsplash

¿Te sirvió? ¿Te dio otro error? Contalo abajo: las preguntas se responden y le sirven al siguiente que llegue.

Dejar un comentario

Clara Vásquez

Analista de ciberseguridad enfocada en vulnerabilidades críticas, zero-days y amenazas emergentes. Cubre CVEs de alto impacto, análisis de malware, incidentes de ransomware y tendencias de seguridad para LATAM.

0 Comentarios

Deja un comentario

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Podés incluir código entre <code>…</code> o, para varias líneas, <pre><code>…</code></pre>.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.