Ir al contenido

API de Twitter en Node.js: guía 2026 con código funcional en fetch

Node.js lee datos de Twitter/X con su fetch integrado: envías una solicitud HTTPS con una clave de API en un encabezado, procesas el JSON y devuelves el cursor recibido para pedir la página siguiente. La API oficial de X cobra $0.005 por cada post leído.

Respuesta corta: Node.js no necesita ningún paquete para leer datos de X: fetch viene integrado. La API oficial de X, incluso con twitter-api-v2, exige una cuenta de desarrollador y créditos prepagados: $0.005 por post, y $0.015 con su autor a partir del 22 de noviembre de 2026. Para datos públicos, usa Sorsa API: un solo encabezado ApiKey, 20 tweets por solicitud desde $0.07 por 1,000; con las 100 solicitudes gratis obtienes 2,000.

Endpoint
POST /search-tweets
Tamaño de página
20 tweets por solicitud
Precio
desde $0.07 por 1,000 tweets

#¿Qué paquete de npm funciona con la API oficial de X en 2026?

Dos paquetes llaman a la API oficial de X desde Node.js. twitter-api-v2, un cliente de la comunidad, llegó a la versión 1.31.0 el 25 de octubre de 2026 y se instala unas 336 mil veces por semana. El SDK de TypeScript de la propia X, @xdevplatform/xdk, está en la 0.6.6. Los dos envuelven la misma plataforma de pago, así que ninguno funciona sin una cuenta de desarrollador, un bearer token y créditos prepagados. Las mismas solicitudes en Python, con Tweepy y xdk en ese papel, están en la guía de la API de Twitter en Python.

Los créditos son lo que omiten los tutoriales viejos de Node. X no tiene un nivel gratuito para desarrolladores nuevos y cobra cada objeto que devuelve una respuesta: $0.005 por post y $0.010 por usuario, hasta 3 millones de lecturas de posts al mes (tabla de precios de X (se abre en una pestaña nueva)). A partir del 22 de noviembre de 2026, los autores y los medios que llegan mediante expansiones cuestan lo mismo que las lecturas directas (aviso de X del 23 de octubre (se abre en una pestaña nueva)). Una búsqueda típica con twitter-api-v2 paga entonces por cada autor que adjunta:

twitter-api-v2
import { TwitterApi } from "twitter-api-v2";

const client = new TwitterApi("YOUR_BEARER_TOKEN").readOnly;
const page = await client.v2.search("nodejs lang:en", {
  max_results: 100,
  expansions: ["author_id"],
});
// 100 posts: $0.50. From Nov 22, 2026, with authors: up to $1.50

Sus paginadores añaden una segunda trampa: la propia documentación de la librería dice que un bucle for await sobre un paginador sigue pidiendo hasta que se acaban los resultados o tu límite de tasa, y cada página se cobra. Todas las tarifas, topes y fechas están en precios de la API de X.

Lo que exige la vía oficial antes de la primera llamada

  • Una cuenta de desarrollador en console.x.com, abierta con una cuenta de X que acepte el Acuerdo para Desarrolladores de X.
  • Una app, cuyo bearer token X muestra una sola vez.
  • Créditos comprados por adelantado y gastados por cada objeto de post, usuario y medio que se devuelve.
  • Tokens de usuario de OAuth para todo lo que publique, dé me gusta o siga cuentas.

Leer posts y perfiles públicos no necesita nada de eso. Una API de datos de X con su propia clave responde por HTTPS simple, y el fetch de Node es todo el cliente.

#Obtén tweets en Node.js con una sola clave de API

Para leer datos de X desde Node.js, usa Sorsa API, una API y scraper de Twitter (X): un solo encabezado ApiKey en lugar de OAuth, 20 solicitudes por segundo en todos los planes, también en las cuentas gratuitas, y resultados de búsqueda desde $0.07 por 1,000 tweets. Cada tweet llega con el perfil completo de su autor, así que el código no define expansiones ni listas de campos. Sorsa API nunca pide un inicio de sesión de X, de modo que ninguna cuenta tuya de X corre riesgo.

Configura la clave y envía la primera solicitud

  1. Obtén una clave. Regístrate y copia tu clave de API desde el panel. Las primeras 100 solicitudes son gratis, no piden tarjeta y nunca vencen.

  2. Revisa Node y guarda la clave. Ejecuta node -v: las líneas LTS de noviembre de 2026 son la 22, la 24 y la 26, y las tres traen fetch y --env-file integrados. Pon la clave en un archivo .env que git ignore, y llama a la API solo desde código de servidor.

    Terminal
    node -v                                  # v22 or newer
    echo 'SORSA_API_KEY=your_key' > .env
    echo '.env' >> .gitignore
    
  3. Busca tweets. Guarda esto como first.mjs y ejecuta node --env-file=.env first.mjs. Envía una consulta con la sintaxis de búsqueda de X a POST /search-tweets (se abre en una pestaña nueva) con la clave en el encabezado ApiKey; la extensión .mjs activa el await de nivel superior.

    const API = "https://api.sorsa.io/v3";
    const KEY = process.env.SORSA_API_KEY ?? "YOUR_API_KEY";
    
    const res = await fetch(`${API}/search-tweets`, {
      method: "POST",
      headers: { ApiKey: KEY, "Content-Type": "application/json" },
      body: JSON.stringify({ query: "nodejs lang:en", order: "latest" }),
    });
    if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).message}`);
    
    const { tweets, next_cursor } = await res.json();
    for (const t of tweets) {
      console.log(t.user.username, t.full_text.slice(0, 60));
    }
    console.log("next page:", next_cursor);
    
  4. Lee la página. Cada respuesta trae hasta 20 tweets y un next_cursor para la página siguiente. Los valores de abajo son datos de demostración con la forma documentada.

    Response200 OK
    {
      "tweets": [
        {
          "id": "1985432176540981234",
          "full_text": "Moved our nightly X report to one Node script.",
          "created_at": "2026-11-01T18:42:07Z",
          "lang": "en",
          "likes_count": 58,
          "retweet_count": 9,
          "reply_count": 4,
          "quote_count": 1,
          "view_count": 4920,
          "bookmark_count": 6,
          "is_reply": false,
          "user": {
            "id": "1592041833471827968",
            "username": "node_stream_digest",
            "display_name": "Node Stream Digest",
            "followers_count": 2310,
            "verified": false
          }
        }
      ],
      "next_cursor": "DAABCgABF7Y8kQ3wAAA"
    }
    

Cada campo de abajo sale directo de la respuesta; el tipo de JavaScript es el que te da res.json(), y los IDs siguen siendo strings a propósito.

CampoTipo de JavaScriptQué contiene
idstringEl ID de 19 dígitos del tweet: nunca lo conviertas a Number
full_textstringEl texto completo del post
created_atstringISO 8601 en UTC: new Date(t.created_at) lo interpreta
likes_count, retweet_count, reply_count, quote_countnumberConteos de interacción
view_count, bookmark_countnumberVistas y guardados
userobjectEl perfil del autor: 19 campos como username y followers_count
quoted_status, retweeted_statusobject o ausenteEl tweet citado o republicado, con la misma forma
  • id

    Tipo de JavaScript
    string
    Qué contiene
    El ID de 19 dígitos del tweet: nunca lo conviertas a Number
  • full_text

    Tipo de JavaScript
    string
    Qué contiene
    El texto completo del post
  • created_at

    Tipo de JavaScript
    string
    Qué contiene
    ISO 8601 en UTC: new Date(t.created_at) lo interpreta
  • likes_count, retweet_count, reply_count, quote_count

    Tipo de JavaScript
    number
    Qué contiene
    Conteos de interacción
  • view_count, bookmark_count

    Tipo de JavaScript
    number
    Qué contiene
    Vistas y guardados
  • user

    Tipo de JavaScript
    object
    Qué contiene
    El perfil del autor: 19 campos como username y followers_count
  • quoted_status, retweeted_status

    Tipo de JavaScript
    object o ausente
    Qué contiene
    El tweet citado o republicado, con la misma forma

#Reintenta los 429 y los errores del servidor en una sola función

Pon cada llamada detrás de una función que reintente solo lo que vale la pena reintentar. Un 429 significa que más de 20 solicitudes empezaron dentro de un mismo segundo con tu clave; un 5xx o un tiempo de espera agotado es una falla pasajera. El resto de esta guía importa esta función sorsa.

sorsa.mjs
// sorsa.mjs: one place for the key, timeouts and retries
const API = "https://api.sorsa.io/v3";
const KEY = process.env.SORSA_API_KEY ?? "YOUR_API_KEY";
const RETRY = new Set([429, 500, 502, 503, 504]);
const sleep = (ms) => new Promise((ok) => setTimeout(ok, ms));

export async function sorsa(path, { body, query } = {}) {
  const url = new URL(API + path);
  if (query) url.search = query; // a URLSearchParams for GET endpoints

  for (let attempt = 0; ; attempt++) {
    let res;
    try {
      res = await fetch(url, {
        method: body ? "POST" : "GET",
        headers: { ApiKey: KEY, "Content-Type": "application/json" },
        body: body && JSON.stringify(body),
        signal: AbortSignal.timeout(30_000),
      });
    } catch (err) { // timeout or dropped connection
      if (attempt === 4) throw err;
      await sleep(1000 * 2 ** attempt);
      continue;
    }
    if (res.ok) return res.json();
    if (!RETRY.has(res.status) || attempt === 4) {
      const { message } = await res.json().catch(() => ({}));
      throw new Error(`${res.status} on ${path}: ${message}`);
    }
    await sleep(1000 * 2 ** attempt); // 1, 2, 4, 8 seconds
  }
}

Un 401 o un 403 nunca merece un reintento: la clave es incorrecta o falta, o sus solicitudes se agotaron, y el campo message dice cuál es el caso. Las solicitudes fallidas nunca se cobran, así que un reintento no cuesta nada. Todos los endpoints de Sorsa API solo leen, de modo que repetir un POST como /search-tweets no puede crear nada dos veces. Sorsa API no envía encabezados de límite de tasa porque la ventana se reinicia cada segundo: la primera espera de un segundo despeja un 429.

#Recorre los resultados con next_cursor

Un cursor es una clave opaca hacia la página siguiente: devuelve next_cursor tal como llegó y detente cuando una respuesta no traiga ninguno. Un generador asíncrono encaja bien en este bucle, porque el código que lee las páginas nunca ve el cursor.

pages.mjs
import { sorsa } from "./sorsa.mjs";

export async function* pages(path, body, maxPages = 100) {
  for (let n = 0; n < maxPages; n++) {
    const page = await sorsa(path, { body });
    yield page;
    if (!page.next_cursor) return; // null, empty or absent: the end
    body = { ...body, next_cursor: page.next_cursor };
  }
}
search.mjs
import { pages } from "./pages.mjs";

const search = { query: "nodejs lang:en", order: "latest" };
for await (const page of pages("/search-tweets", search, 50)) {
  for (const t of page.tweets) console.log(t.id, t.created_at);
}
Tu código for await yield page 1 yield page 2 return query query + "c1" query + "c2" solicitud página página 1 página 2 página 3 Sorsa API POST /search-tweets 20 tweets next_cursor: "c1" 17 tweets next_cursor: "c2" 12 tweets next_cursor: null
El generador devuelve cada cursor y se detiene en null; una página corta a la mitad no es el final.

La búsqueda y los timelines devuelven hasta 20 tweets por página, y una página puede traer menos mientras quedan más, así que la cantidad nunca te dice el final. Mantén sin cambios la consulta y order a lo largo de un mismo cursor, y trata maxPages como un presupuesto: 50 páginas son 50 solicitudes, sin importar lo que coincida con la consulta. Los endpoints GET reciben el cursor en la cadena de consulta: GET /followers (se abre en una pestaña nueva) devuelve hasta 200 perfiles por página, y query.set("next_cursor", page.next_cursor) lo avanza. POST /user-tweets (se abre en una pestaña nueva) funciona con el mismo generador; para descargar todos los tweets de un usuario con un cursor reanudable, esa guía tiene el script completo.

#Obtén 100 tweets o perfiles por solicitud

Cuando ya tienes IDs o nombres de usuario, envíalos en lotes. POST /tweet-info-bulk (se abre en una pestaña nueva) acepta hasta 100 IDs o enlaces de tweets en tweet_links, y GET /info-batch (se abre en una pestaña nueva) acepta hasta 100 nombres de usuario; cada lote es una solicitud.

batch.mjs
import { sorsa } from "./sorsa.mjs";
// tweetIds and usernames: arrays of strings you already hold

const chunks = (list, size = 100) =>
  Array.from({ length: Math.ceil(list.length / size) },
    (_, i) => list.slice(i * size, (i + 1) * size));

const tweets = [];
for (const ids of chunks(tweetIds)) {
  const body = { tweet_links: ids }; // up to 100 IDs or links
  tweets.push(...(await sorsa("/tweet-info-bulk", { body })).tweets);
}

const users = [];
for (const names of chunks(usernames)) {
  const query = new URLSearchParams();
  for (const name of names) query.append("usernames", name);
  users.push(...(await sorsa("/info-batch", { query })).users);
}

GET /info-batch lee usernames como un parámetro repetido (usernames=a&usernames=b), así que constrúyelo con append. Pasar un arreglo a new URLSearchParams({ usernames }) une los nombres con comas en un solo valor. Una solicitud cuesta lo mismo sin importar lo que devuelva, así que un lote de 100 tweets cuesta lo que cuesta un tweet: desde $0.014 por 1,000 tweets, más de 250 veces menos que los $5.00 de la API oficial de X. Las respuestas por lote no traen cursor; el lote completo viene en tweets o en users.

#Ejecuta 20 solicitudes por segundo con una sola clave

Sorsa API permite 20 solicitudes por segundo por clave en todos los planes, y un solo proceso de Node lo alcanza con facilidad: el bucle de eventos mantiene decenas de solicitudes en vuelo en un solo hilo. El límite que hay que respetar es la tasa de inicio, así que pon un único regulador delante de cada llamada y divide el trabajo en cadenas independientes. Una cadena de cursor no puede correr en paralelo, porque cada página necesita el cursor de la anterior; corre entonces una cadena por cuenta o una por día de una búsqueda.

lanes.mjs
import { sorsa } from "./sorsa.mjs";

// Hands out start times 1/19 s apart, however many lanes are waiting.
function pacer(perSecond) {
  const gap = 1000 / perSecond;
  let next = 0;
  return () => {
    const now = Date.now();
    const start = Math.max(next, now);
    next = start + gap;
    return new Promise((ok) => setTimeout(ok, start - now));
  };
}

const slot = pacer(19); // one pacer per key, one start under the limit

async function lane(query, maxPages = 100) {
  const tweets = [];
  let body = { query };
  for (let n = 0; n < maxPages; n++) {
    await slot();
    const page = await sorsa("/search-tweets", { body });
    tweets.push(...page.tweets);
    if (!page.next_cursor) break;
    body = { ...body, next_cursor: page.next_cursor };
  }
  return tweets;
}

const day = (d) => new Date(Date.UTC(2026, 9, d)).toISOString().slice(0, 10);
const queries = Array.from({ length: 31 }, (_, i) =>
  `nodejs lang:en since:${day(i + 1)} until:${day(i + 2)}`); // Oct 1-31
const results = await Promise.all(queries.map((q) => lane(q)));
console.log(results.flat().length, "tweets");

El regulador no necesita ningún bloqueo: JavaScript ejecuta un callback a la vez, así que dos cadenas nunca pueden tomar el mismo instante de inicio. Con 19 inicios por segundo deja un inicio de margen, porque la variación de los temporizadores puede empujar el inicio número 20 a la ventana siguiente. La función de reintentos atrapa cualquier 429 que aun así se cuele. Promise.all sin regulador es el error más común: 60 llamadas lanzadas de golpe mandan 40 directo a 429 y pasan segundos en espera.

Un proceso Node.js pacer(19) 1 oct 2 oct 3 oct 4 oct una API key 19 inicios por segundo bajo el límite de 20 por key Tres instancias serverless pacer(19) pacer(19) pacer(19) cada una cuenta solo sus inicios la misma API key 57 inicios por segundo 37 reciben un 429 y esperan
Un regulador solo cuenta los inicios de su propio proceso, así que da a cada clave un solo regulador o reparte la tasa entre las instancias.

Las plataformas serverless rompen esa regla sin avisar. Cada instancia de función en Lambda, Vercel o Cloud Run carga su propia copia de lanes.mjs. Tres instancias activas ejecutan entonces tres reguladores sobre una misma clave y entre todas inician hasta 57 solicitudes por segundo. Dale a cada instancia una parte de la tasa (pacer(6) para tres), o corre el trabajo masivo en un solo worker. El límite se cuenta por clave, así que una segunda clave para un segundo worker trae sus propios 20 por segundo. A 20 solicitudes por segundo, los lotes de 100 mueven hasta 2,000 tweets por segundo y las páginas de búsqueda, 400.

#Guarda los tweets en JSONL o CSV

Escribe cada página según llegue, en lugar de mantener todos los tweets en memoria. JSON Lines, un objeto JSON por línea, conserva todos los campos y se puede ampliar sin riesgo; el CSV se abre en Excel y Google Sheets. Los dos flujos de abajo esperan a drain cuando el disco se atrasa.

save.mjs
import { createWriteStream } from "node:fs";
import { once } from "node:events";
import { pages } from "./pages.mjs";

const jsonl = createWriteStream("tweets.jsonl");
const csv = createWriteStream("tweets.csv");
const put = async (out, line) => {
  if (!out.write(line)) await once(out, "drain"); // respect backpressure
};
const cell = (v) => `"${String(v ?? "").replaceAll('"', '""')}"`;
const BOM = String.fromCharCode(0xfeff); // tells Excel the file is UTF-8

await put(csv, BOM + "id,created_at,username,likes_count,full_text\r\n");
const search = { query: "nodejs lang:en" };
for await (const page of pages("/search-tweets", search, 500)) {
  for (const t of page.tweets) {
    await put(jsonl, JSON.stringify(t) + "\n");
    const row = [t.id, t.created_at, t.user.username, t.likes_count,
      t.full_text];
    await put(csv, row.map(cell).join(",") + "\r\n");
  }
}
jsonl.end();
csv.end();

La marca de orden de bytes al inicio del CSV le indica a Excel que el archivo es UTF-8, así que los emoji y los acentos se ven bien. Cada celda va entre comillas, de modo que las comas, las comillas y los saltos de línea dentro de un tweet se quedan en su columna. Quinientas páginas dan hasta 10,000 tweets con 500 solicitudes; la memoria se mantiene estable sin importar cuánto dure la ejecución.

Para tener en cuenta

Los números de JavaScript guardan enteros con exactitud solo hasta 2^53, unos 9 mil billones, y los IDs de tweets tienen 19 dígitos. Number("1985432176540981234") devuelve 1985432176540981200, que es otro tweet. Sorsa API envía cada ID y cada cursor como string, así que déjalos como strings, compáralos como strings y usa BigInt(id) cuando necesites ordenar por ID.

#Agrega tipos de TypeScript para las respuestas

Quien usa TypeScript obtiene seguridad de tipos con unas pocas interfaces que se llaman exactamente como los campos de la API. Las de abajo siguen la referencia OpenAPI vigente y cubren los campos que lee la mayoría del código; la referencia lista el resto.

sorsa-types.ts
// sorsa-types.ts: field names as in the Sorsa API reference
export interface SorsaUser {
  id: string; // 64-bit ID: keep it a string
  username: string;
  display_name: string;
  description: string;
  followers_count: number;
  followings_count: number;
  tweets_count: number;
  verified: boolean;
  protected: boolean;
  created_at: string; // ISO 8601
}

export interface SorsaTweet {
  id: string;
  full_text: string;
  created_at: string;
  lang: string;
  likes_count: number;
  retweet_count: number;
  reply_count: number;
  quote_count: number;
  view_count: number;
  bookmark_count: number;
  is_reply: boolean;
  user: SorsaUser;
  quoted_status?: SorsaTweet;
  retweeted_status?: SorsaTweet;
}

export interface TweetsPage {
  tweets: SorsaTweet[];
  next_cursor?: string | null;
}

Los campos opcionales llevan un ?: un tweet citado o republicado existe solo en las citas y los reposts, así que el compilador te obliga a comprobarlo antes de leerlo. Haz la conversión en el borde, const page = (await sorsa(path, { body })) as TweetsPage, y el resto del código queda verificado. Node 22.18 y posteriores ejecutan archivos .ts directamente quitando los tipos, así que node --env-file=.env job.ts funciona sin paso de compilación. Para todos los endpoints a la vez, un generador de OpenAPI como openapi-typescript puede convertir la referencia completa en tipos.

#¿Se puede llamar a una API de Twitter desde JavaScript en el navegador?

No: una clave de API en el código del navegador la puede leer cualquiera que abra las herramientas de desarrollo, y Sorsa API está pensada para llamadas desde el servidor, así que los navegadores reciben errores de CORS. Pon una ruta pequeña en tu servidor, guarda la clave ahí y deja que el front end llame a tu ruta.

// server.mjs: npm install express
import express from "express";
import { sorsa } from "./sorsa.mjs";

const app = express();
app.get("/api/tweets", async (req, res) => {
  const query = String(req.query.q ?? "").slice(0, 200);
  const page = await sorsa("/search-tweets", { body: { query } });
  res.json(page.tweets.map((t) => ({ id: t.id, text: t.full_text })));
});
app.listen(3000);

El navegador ejecuta entonces fetch("/api/tweets?q=nodejs") contra tu propio dominio y nunca ve la clave. El mismo patrón sirve para cualquier entorno de servidor: un Cloudflare Worker o una función de Lambda guarda la clave en sus variables de entorno, y la página solo habla con ella. Guarda en caché la respuesta de la ruta durante un minuto cuando muchos visitantes piden lo mismo: Sorsa API devuelve datos frescos en cada solicitud, y una respuesta en caché sirve a todos por el costo de una solicitud.

#Cuánto cuesta un trabajo en Node.js

Sorsa API cobra por solicitud, sin importar lo que devuelva el endpoint: los resultados de búsqueda cuestan desde $0.07 por 1,000 tweets, los lotes desde $0.014, y las solicitudes fallidas nunca se cobran. La API oficial de X cobra en cambio por objeto: $5.00 por 1,000 posts, y a partir del 22 de noviembre de 2026 hasta $15.00 por 1,000 cuando el código expande el autor de cada post, como hacen la mayoría de las búsquedas con twitter-api-v2.

Tweets que tu código recolecta por búsqueda

API oficial de X

$5,000

para 1M tweets

$0.005 por post

Sorsa API

desde$70

para 1M tweets

desde $0.07 por 1,000

Cada tweet incluye el perfil de su autor

El constructor de abajo escribe el bucle de Node.js para un trabajo y muestra sus solicitudes, el tiempo mínimo con una sola clave y el costo con la tarifa más baja de Sorsa API.

Tarea
Cuántos
job.mjs
// sorsa() y pages() vienen de los helpers de arriba
const body = { query: "nodejs lang:en" };
for await (const page of pages("/search-tweets", body, 5000)) {
  save(page.tweets); // hasta 20 tweets por página
}
Solicitudes
5,000
Lo más rápido con una sola clave
unos 4 min
Sorsa API
desde $7

Tiempo a 20 solicitudes por segundo; costo a $1.40 por cada 1,000 solicitudes. Una búsqueda es una sola cadena de cursores, así que divídela en ventanas de fechas para correr carriles en paralelo.

El tiempo es el más rápido que permite una clave; una sola cadena de cursores avanza al ritmo de sus idas y vueltas, así que divide las tareas grandes en carriles.

La tarifa por 1,000 solicitudes va de $4.90 en Starter a $1.40 en Hyperscale, y todos los endpoints usan la misma tarifa. Consultar cuánto te queda no cuesta nada: GET /key-usage-info (se abre en una pestaña nueva) nunca descuenta de tus solicitudes.

usage.mjs
import { sorsa } from "./sorsa.mjs";
const usage = await sorsa("/key-usage-info");
console.log(usage.remaining_requests, "left until", usage.valid_until);

#Cómo pasar el código de twitter-api-v2 a Sorsa API

La mayoría de las llamadas de twitter-api-v2 se corresponden con un endpoint de Sorsa API, y el código pierde sus expansiones y listas de campos, porque cada tweet ya trae su autor y sus conteos. La tabla empareja los métodos comunes de client.v2 con sus endpoints; para migrar desde la API de Twitter/X en todo un código base, esa guía mapea cada endpoint v2 y cada campo de respuesta.

Método de twitter-api-v2EndpointQué cambia
searchPOST /search-tweetsCualquier fecha desde 2006, no solo los últimos 7 días
searchAllPOST /search-tweetsEl mismo endpoint con since: y until: en la consulta
userTimelinePOST /user-tweetsBasta con un nombre de usuario, y no hay tope de 3,200 posts
userByUsernameGET /info (se abre en una pestaña nueva)Todos los campos del perfil, sin user.fields
usersByUsernamesGET /info-batch100 nombres de usuario por solicitud
tweetsPOST /tweet-info-bulk100 IDs o enlaces por solicitud
followersGET /followers200 seguidores por página
tweetRetweetedByPOST /retweeters (se abre en una pestaña nueva)El mismo bucle de cursor
tweetningunoSolo lectura: publica con la API oficial de X
  • search

    Endpoint
    POST /search-tweets
    Qué cambia
    Cualquier fecha desde 2006, no solo los últimos 7 días
  • searchAll

    Endpoint
    POST /search-tweets
    Qué cambia
    El mismo endpoint con since: y until: en la consulta
  • userTimeline

    Endpoint
    POST /user-tweets
    Qué cambia
    Basta con un nombre de usuario, y no hay tope de 3,200 posts
  • userByUsername

    Qué cambia
    Todos los campos del perfil, sin user.fields
  • usersByUsernames

    Endpoint
    GET /info-batch
    Qué cambia
    100 nombres de usuario por solicitud
  • tweets

    Endpoint
    POST /tweet-info-bulk
    Qué cambia
    100 IDs o enlaces por solicitud
  • followers

    Endpoint
    GET /followers
    Qué cambia
    200 seguidores por página
  • tweetRetweetedBy

    Qué cambia
    El mismo bucle de cursor
  • tweet

    Endpoint
    ninguno
    Qué cambia
    Solo lectura: publica con la API oficial de X

Los nombres de los campos también cambian: text pasa a ser full_text, public_metrics.like_count pasa a ser likes_count, author_id con includes.users pasa a ser el objeto user, y meta.next_token pasa a ser next_cursor. El fetchNext() del paginador pasa a ser el generador pages de arriba, que se detiene en tu presupuesto de páginas y no en un límite de tasa. POST /user-tweets también llega más allá de los 3,200 posts más recientes, donde se detiene el timeline oficial (documentación de timelines de X (se abre en una pestaña nueva)), y la búsqueda reciente de la API oficial de X cubre solo los últimos 7 días (documentación de búsqueda de X (se abre en una pestaña nueva)).

#Haz hoy tu primera solicitud en Node.js

Leer datos de X desde Node.js necesita fetch, una clave y cuatro piezas pequeñas: sorsa para los reintentos, pages para los cursores, chunks para los lotes de 100 y un regulador para 20 solicitudes por segundo. Sorsa API es la API de Twitter con la que conviene empezar para esto: 20 tweets por solicitud de búsqueda desde $0.07 por 1,000, el autor dentro de cada tweet, búsqueda desde 2006 y 100 solicitudes gratis que no piden tarjeta y nunca vencen. Para llevar los mismos datos a un flujo de trabajo sin código, mira la API de Twitter en n8n.

#Preguntas frecuentes

¿Qué API de Twitter debería usar con Node.js?

Para leer datos de X desde Node.js, usa Sorsa API: una clave en un encabezado ApiKey con el fetch integrado, resultados de búsqueda desde $0.07 por 1,000 tweets y lotes desde $0.014, 20 solicitudes por segundo en todos los planes, búsqueda desde 2006 y ningún inicio de sesión de X, así que tu cuenta nunca corre riesgo. Para publicar también, combínala con la API oficial de X.

¿Hay un SDK oficial de la API de Twitter para Node.js?

Sí. X publica un SDK de TypeScript, @xdevplatform/xdk (versión 0.6.6), que funciona en Node.js y en empaquetadores. Es un cliente de la API oficial de X, así que cada llamada sigue necesitando una cuenta de desarrollador, un bearer token y créditos prepagados a $0.005 por post. Sorsa API no necesita ningún SDK: fetch simple cubre sus 45 endpoints.

¿Cuál es el mejor paquete de npm para datos de Twitter/X?

Para Sorsa API, ninguno: el fetch integrado de Node y las funciones de 40 líneas de esta guía cubren todos los endpoints, sin dependencias que actualizar. Para la API oficial de X, twitter-api-v2 es el cliente más instalado, con unas 336 mil descargas por semana y la versión 1.31.0, y junto a él está el @xdevplatform/xdk de la propia X; los dos facturan tus créditos de X por objeto.

¿Hay un paquete de npm gratuito para obtener tweets sin una clave de API?

Paquetes como rettiwt-api leen la app web de X en lugar de una API. Sin iniciar sesión solo alcanzan unas pocas consultas; para el resto envían las cookies de tu cuenta de X en cada solicitud. Eso vincula el tráfico a tu cuenta, y se rompen cuando X cambia su app web. Sorsa API nunca pide tu inicio de sesión de X, y sus 100 solicitudes gratis no piden tarjeta. Los pros y contras están en cómo hacer scraping de Twitter.

¿Puedo publicar tweets desde Node.js con Sorsa API?

No. Sorsa API es de solo lectura por diseño: lee posts, perfiles y seguidores públicos y nunca publica, da me gusta, sigue cuentas ni envía mensajes, así que una clave no puede actuar sobre ninguna cuenta de X. Para publicar desde Node.js, usa la API oficial de X con un token de usuario de OAuth, por ejemplo el client.v2.tweet de twitter-api-v2 a $0.015 por post, y deja Sorsa API para las lecturas.

¿Puedo obtener datos de Twitter en Node.js sin una cuenta de desarrollador?

Sí. Sorsa API solo necesita su propia clave: te registras, defines el encabezado ApiKey y llamas a cualquiera de sus endpoints desde Node.js, sin cuenta de desarrollador de X, sin revisión de app y sin OAuth. Las primeras 100 solicitudes son gratis y obtienen hasta 2,000 tweets por búsqueda o 10,000 en lotes de 100. Las opciones se comparan en API de Twitter sin cuenta de desarrollador.

#Cómo lo comprobamos

Escribimos cada solicitud a partir de la referencia OpenAPI vigente de Sorsa API (45 endpoints) y de su documentación sobre autenticación, límites de tasa y paginación, leída el 2 de noviembre de 2026. No teníamos una clave de Sorsa API para esta revisión, así que la respuesta usa valores de demostración. Ejecutamos los bloques de Node.js en Node 26 contra un mock local que responde con las formas documentadas: la primera solicitud, la función de reintentos (dos 503 y luego una ráfaga de 60 llamadas), el generador de cursores, los lotes de 100, la exportación a JSONL y CSV, la consulta de uso de la clave y el regulador. Con 19 inicios por segundo, el regulador corrió 31 cadenas, 93 solicitudes, sin un solo 429 en tres ejecuciones; con exactamente 20, una ejecución de tres envió 29 solicitudes a los reintentos. Los fragmentos de Express, Next.js y twitter-api-v2 no se ejecutaron. El mismo día leímos los precios de X, su aviso del 22 de noviembre sobre expansiones y su página de herramientas en docs.x.com, las fichas de npm de twitter-api-v2 y @xdevplatform/xdk, y la tabla de versiones de Node.js.

Por el equipo de Sorsa API. Creamos y operamos Sorsa API, la API y scraper de Twitter/X de solo lectura, en producción desde 2022 (antes TweetScout API) y con más de 6 mil millones de solicitudes procesadas. Acerca de Sorsa API

Qué cambió
  • Reescrita desde cero: precios actuales de la API oficial de X con la facturación por expansiones del 22 de noviembre, twitter-api-v2 1.31.0 y el SDK de TypeScript de X 0.6.6, y un camino en Node.js con una sola clave de API: reintentos, un generador asíncrono para los cursores, lotes de 100, un regulador de 20 solicitudes por segundo con la trampa de serverless, JSONL y CSV, tipos de TypeScript, rutas de Express y Next.js, y una tabla de equivalencias con los métodos de twitter-api-v2.
  • Primera publicación.