# How to Collect Tweets With JavaScript and Node.js

To collect tweets with Node.js, install the apify-client package, call apidojo's Tweet Scraper V2 with an X search query, and list the items in the run's dataset.

[![apidojo](/blog/authors/apidojo.png)**Apidojo** *15+ years of experience in data retrieval.*](/blog/authors/apidojo/)

**7 October 2026** Published

**3 min** Read

![Cover card reading 'How to Collect Tweets With JavaScript and Node.js'](/blog/covers/scrape-tweets-javascript.png)

**To collect tweets with Node.js, install the `apify-client` package, call apidojo’s Tweet Scraper V2 with an X search query, and list the items in the run’s dataset.** A short script returns posts with text, date, author and engagement at $0.40 per 1,000 tweets, with no X developer account.

This guide builds a complete Node.js collector: setup, a first run, date windows, deduplication and a CSV export. The Python version is in [how to collect tweets with Python](/blog/twitter-scraping/scrape-tweets-python/). Every other collection task is mapped in [how to scrape Twitter (X) data](/blog/twitter-scraping/how-to-scrape-twitter/).

## What Do You Need to Collect Tweets With Node.js?

**You need Node.js 18 or later, the `apify-client` npm package, and an Apify API token from a paid plan.** Tweet Scraper V2 can’t be called through the API on the free plan ([Apify](https://apify.com/apidojo/tweet-scraper)). Listed below are the 3 setup steps.

1.  **Install** the client: `npm install apify-client`.
2.  **Copy** your API token from Apify Console.
3.  **Store** it in an environment variable: `export APIFY_TOKEN=your_token`.

## How Do You Run a First Collection in Node.js?

**Create a client, call the actor with a `searchTerms` query, and read the items from its default dataset.** `call()` starts the run and waits for it to finish.

```
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor("apidojo/tweet-scraper").call({
  searchTerms: ["from:NASA -filter:retweets"],
  sort: "Latest",
  maxItems: 500,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const tweet of items) {
  console.log(tweet.createdAt, tweet.likeCount, tweet.text.slice(0, 80));
}
```

Save the file as `collect.mjs` so the `import` syntax works, then run `node collect.mjs`. The field names come from the actor’s output example (Apify).

## How Do You Handle Tweet IDs in JavaScript?

**Keep tweet IDs as strings, because JavaScript numbers can’t hold 19-digit IDs exactly.** `Number("1728108619189874825")` changes the last digits. Use `BigInt` only when you need arithmetic, such as reading the creation time from an ID.

```
const id = BigInt("1728108619189874825");
const ms = Number((id >> 22n) + 1288834974657n);
console.log(new Date(ms).toISOString());
```

The ID format is explained in [since: and until: explained](/blog/twitter-search/since-until-operators/).

## How Do You Collect a Large History in Node.js?

**Generate one query per month, run them in batches of 5, and store posts in a `Map` keyed by ID to remove duplicates.** Tweet Scraper V2 accepts up to 5 batched queries per run and one concurrent run (Apify).

```
const queries = [];
for (let m = 0; m < 12; m++) {
  const start = new Date(Date.UTC(2025, m, 1)).toISOString().slice(0, 10);
  const end = new Date(Date.UTC(2025, m + 1, 1)).toISOString().slice(0, 10);
  queries.push(`from:NASA since:${start} until:${end}`);
}

const tweets = new Map();
for (let i = 0; i < queries.length; i += 5) {
  const run = await client.actor("apidojo/tweet-scraper").call({
    searchTerms: queries.slice(i, i + 5),
    includeSearchTerms: true,
    sort: "Latest",
  });
  const { items } = await client.dataset(run.defaultDatasetId).listItems();
  for (const t of items) tweets.set(t.id, t);
}
console.log(tweets.size, "unique tweets");
```

Window sizes are discussed in [how to scrape tweets by date range](/blog/twitter-scraping/scrape-tweets-by-date/), and pagination in [Twitter scraper pagination](/blog/twitter-scraping/pagination/).

## How Do You Save Tweets to CSV in Node.js?

**Write the columns you need, wrapping text in quotes and doubling any quotes inside it.**

```
import { writeFileSync } from "node:fs";

const esc = (v) => `"${String(v ?? "").replace(/"/g, '""')}"`;
const header = "id,url,createdAt,author,likes,text";
const rows = [...tweets.values()].map((t) =>
  [t.id, t.url, t.createdAt, t.author?.userName, t.likeCount, t.text].map(esc).join(",")
);
writeFileSync("tweets.csv", [header, ...rows].join("\n"));
```

Other formats, including downloading a dataset directly as CSV or Excel, are covered in [how to export tweets to CSV or JSON](/blog/twitter-scraping/export-tweets-csv-json/).

## The scrapers behind this

-   [Tweet Scraper V2 Tweets from searches, profiles, Lists and URLs; 49–64 tweets/sec; minimum 50 per query $0.40 / 1K tweets](/scrapers/twitter-scraper/)

## Questions people ask

### Can you run this in the browser?

Keep the API token on a server; calling the actor from browser code would expose it.

### Can you use TypeScript?

Yes, `apify-client` ships its own type definitions.

### How do you scrape threads in Node.js?

Call `apidojo/twitter-scraper-lite` with `conversationIds`; see [how to scrape a Twitter thread and all its replies](/blog/twitter-scraping/scrape-thread-replies/).

### Where do you start?

At the [apidojo Twitter Scraper](/scrapers/twitter-scraper/).

## More on scraping X data

-   [How to Scrape Twitter (X) Data in 2026 What Twitter data you can scrape, the 3 ways to collect it, which apidojo actor fits each task, prices, limits and Python code.](/blog/twitter-scraping/how-to-scrape-twitter/)
-   [How to Scrape Tweets by Keyword (2026 Guide) Scrape tweets by keyword with apidojo's Tweet Scraper V2: query rules, batching, Python code, costs and fixes for low results.](/blog/twitter-scraping/scrape-tweets-by-keyword/)
-   [How to Scrape Tweets by Date Range Scrape tweets between two dates by splitting periods into windows, running them in batches and removing duplicates, with Python code.](/blog/twitter-scraping/scrape-tweets-by-date/)
-   [How to Scrape Tweets From a User Profile Scrape any public profile's tweets with from:username, collect a full history in date windows, and compare two apidojo actors.](/blog/twitter-scraping/scrape-user-tweets/)
-   [How to Scrape Twitter Search Results Turn any X search into a JSON, CSV or Excel dataset with apidojo's Tweet Scraper V2, using search queries or search result URLs.](/blog/twitter-scraping/scrape-search-results/)
-   [How to Scrape a Twitter Thread and All Replies Scrape every reply in a thread with conversation\_id:, keep only the author's thread, filter replies and see what each thread costs.](/blog/twitter-scraping/scrape-thread-replies/)
-   [How to Scrape Images and Videos From Tweets Collect tweets with media, find the media URLs in the output, download images with Python and pick the best video file.](/blog/twitter-scraping/scrape-twitter-media/)
-   [How to Export Tweets to CSV or JSON Export tweets to CSV, Excel, JSON or JSONL: your own archive, any search through a scraper, the columns you get and the API call.](/blog/twitter-scraping/export-tweets-csv-json/)
-   [How to Collect Tweets With Python (2026) A complete Python tweet collector: setup, first run, date parsing, date-window batching, deduplication and CSV export.](/blog/twitter-scraping/scrape-tweets-python/)
-   [Twitter Scraper Pagination: Cursors and Limits How pagination works in the X API and apidojo's actors, why searches stop early, and how to deduplicate and resume collections.](/blog/twitter-scraping/pagination/)
-   [How to rebuild an X conversation tree from replies Replies arrive as a flat list. Two fields, conversationId and inReplyToId, are what turn that list back into the threaded conversation you saw on X.](/blog/twitter-scraping/x-reply-tree/)
-   [When the X replies endpoint under-returns A thread that looks busy on X can come back thin from a scrape. Here is how to tell a quiet conversation from a short run, and what the second flow fixes.](/blog/twitter-scraping/x-replies-vs-search-flow/)
-   [Reading account age in X reply data Every reply carries the responder's account creation date, follower counts and post history. Here is what those fields can and cannot tell you.](/blog/twitter-scraping/x-replier-account-age/)

![apidojo](/blog/authors/apidojo.png)

## [Apidojo](/blog/authors/apidojo/)

15+ years of experience in data retrieval.

API Dojo is always ready for you. With 15+ years of experience, data acquisition has never been that easy. Cheapest prices with high availability.

-   🏯 15+ years of experience in data retrieval.
-   💰 Cheapest prices, qualified data.
-   ⚙️ High availability, extreme maintenance.
-   🐉 Hyper communicative, excellent support.

-   [apify.com](https://apify.com/apidojo)
-   [x.com](https://x.com/apidojo_)
-   [github.com](https://github.com/apidojo-io)
