npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

threads-bot

v1.0.0

Published

Threads (threads.com) automation library — cookie/credential auth, language-independent direct private-API client. Post (text/image/video/carousel), reply, quote, like, follow, repost, mute/block/restrict, search, feed, notifications, media download, prof

Readme

threads-bot

npm version license node

Full-featured automation library for Threads (threads.com). Cookie- or credential-based auth and a direct private-API client — fast and lightweight, talking straight to the API (no UI scraping).

No browser is required at runtime — everything runs over plain HTTP. puppeteer-core is an optional dependency used only for credential login and self-healing.

🌍 Language / Dil: English · Türkçe


English

Features

  • Auth — cookies (browser-export array / object / string / file) or username+password login (real-browser, cached, auto-relogin on session loss)
  • Posts — text, image, video, carousel (multi-image), reply (any nesting depth), quote (embeds the original), delete
  • Interactions — like/unlike, follow/unfollow, repost/unrepost, mute/unmute, block/unblock, restrict/unrestrict
  • Reading — feed (for-you/following + pagination), profile & posts, single thread + replies, post counts, notifications, user/keyword search
  • Media — download a post's images/videos; upload from local files
  • Profile — edit bio/name/link/privacy, change/remove profile photo
  • Live events — poll notifications and emit typed events (follow, like, reply, mention, repost, quote) to build reactive bots
  • Resilient — retry + exponential backoff, never crashes on 429 (throws a catchable RateLimitError)

Install

npm install threads-bot
# optional — only for credential login / self-healing:
npm install puppeteer-core

Requires Node.js ≥ 18 (uses the global fetch).

Quick start

const { ThreadsClient } = require("threads-bot");

const t = new ThreadsClient({ cookies: "./cookies.json" });
await t.init();

await t.createPost("Hello from threads-bot! 🤖");
const feed = await t.getFeed({ limit: 10 });
await t.like(feed.items[0].id);
await t.follow("zuck");

Authentication

Option A — cookies. Export your threads.com cookies (e.g. with a "Cookie-Editor" extension) and pass them in any form:

new ThreadsClient({ cookies: "./cookies.json" });                       // path to a .json
new ThreadsClient({ cookies: [{ name: "sessionid", value: "…" }, …] }); // browser-export array
new ThreadsClient({ cookies: { sessionid: "…", ds_user_id: "…", csrftoken: "…" } });
new ThreadsClient({ cookies: "sessionid=…; ds_user_id=…; csrftoken=…" }); // cookie string

Required cookies: sessionid, ds_user_id, csrftoken. Recommended: ig_did, mid, rur.

Option B — credentials. Logs in via a real Chrome window (needs puppeteer-core + Chrome), caches the cookies, and auto-relogins if the session expires mid-run:

const t = new ThreadsClient({
  credentials: { username: "you", password: "secret" },
  cookieFile: "./cookies.json",   // cached here and reused next run
  loginHeadless: false,           // visible window lets you solve 2FA/checkpoints
});
await t.init();

💡 Cookies exported from another device tend to get invalidated after writes. For a stable session, log in with credentials from the machine that runs the bot — those cookies are IP-bound.

API reference

Reading

| Method | Returns | |---|---| | me() / viewer() | The logged-in user | | getFeed({ variant, cursor, limit }) | { items, pageInfo }variant: "for_you" \| "following" | | iterateFeed({ max, variant }) | async generator over posts | | getUser(idOrUsername) | Profile | | getUserPosts(idOrUsername, { cursor, limit }) | { items, pageInfo } | | getThread(postId) | { post, replies, pageInfo } | | getReplies(postId, { cursor, limit, sort }) | Replies (works on a reply too → nested comments) | | getPostCounts(ids) | { counts: [{ likeCount, replyCount, repostCount, quoteCount }] } | | getNotifications({ cursor, limit }) | Activity feed | | searchUsers(q) · searchTags(q) · search(q) | Search | | resolveUserId(username) | @username → numeric id |

Writing & interactions

| Method | Description | |---|---| | createPost(text, { media, replyTo, replyControl }) | media = an image/video path, or an array of images for a carousel | | reply(postId, text) · quote(postId, text) | Reply (nestable) · quote (embeds original) | | like(id) / unlike(id) | Like / unlike | | follow(u) / unfollow(u) | Follow / unfollow | | repost(id) / unrepost(id) | Repost / remove repost | | mute(u) / unmute(u) | Mute / unmute | | block(u) / unblock(u) | Block / unblock | | restrict(u) / unrestrict(u) | Restrict / unrestrict | | deletePost(id) | Delete your own post |

Media & profile

| Method | Description | |---|---| | downloadMedia(postOrId, { dir }) | Download a post's images/videos to disk | | getMediaUrls(postOrId) | List a post's media URLs | | updateProfile({ bio, name, link, isPrivate }) | Edit profile (unset fields keep their current value) | | setProfilePhoto(file) / removeProfilePhoto() | Change / remove profile photo |

Live events (build a reactive bot)

Threads has no webhooks, so the client polls notifications on an interval you choose and emits typed events:

client.on("follow",  (e) => client.follow(e.fromUser.id));         // auto follow-back
client.on("reply",   (e) => client.reply(e.postId, "thanks! 🙏"));  // auto-reply
client.on("mention", (e) => client.reply(e.postId, "👀"));
client.on("like",    (e) => console.log("liked by", e.fromUser.username));
client.on("rateLimited", () => console.log("backing off…"));

client.startListening({ intervalMs: 60000 });
// client.stopListening();

Events: notification (every item) + follow · like · reply · mention · repost · quote · followRequest. Payload: { id, type, fromUser:{ id, username }, postId, text, raw }. The loop is resilient — a failed poll (incl. 429) keeps the loop alive.

Rate limits

Every request retries on 429/5xx with exponential backoff (honoring Retry-After); if still limited it throws a catchable RateLimitError — it never crashes the process. Pace bursty loops:

const { RateLimitError } = require("threads-bot");
try { await client.follow(id); }
catch (e) { if (e instanceof RateLimitError) await sleep(60_000); else throw e; }

Events emitted by the client

ready · loginRequired · error · login · postCreated · liked · followed · reposted · blocked · profileUpdated · closed — plus the listener events above.

How it works

The library reverse-engineers threads.com's web app: GraphQL persisted queries (/graphql/query, /api/graphql) for reads and most mutations, and IG-style REST (/api/v1/media/configure_*, rupload_*) for posting/media. Session tokens (lsd, fb_dtsg) are bootstrapped from the home page HTML over plain HTTP. Because it talks to the API directly, it needs no browser at runtime.

Disclaimer

Unofficial. Not affiliated with Meta or Threads. Uses private endpoints that may change without notice and may be against the Threads Terms of Service. For automating your own account — use responsibly and at your own risk.


Türkçe

Threads (threads.com) için tam kapsamlı otomasyon kütüphanesi. Cookie veya kullanıcı adı+şifre ile giriş, ve doğrudan private-API istemcisi — hızlı ve hafif, doğrudan API ile konuşur (arayüz kazıma yok).

Çalışma anında tarayıcı gerekmez — her şey düz HTTP üzerinden döner. puppeteer-core yalnızca credential login ve self-healing için opsiyonel bir bağımlılıktır.

Özellikler

  • Giriş — cookie (tarayıcı-export array / obje / string / dosya) veya kullanıcı adı+şifre (gerçek tarayıcı, cache'li, session düşünce otomatik yeniden giriş)
  • Gönderiler — metin, görsel, video, carousel (çoklu görsel), yanıt (sınırsız iç içe), alıntı (orijinali gömer), silme
  • Etkileşim — beğen/geri al, takip et/bırak, repost/geri al, sustur/aç, engelle/kaldır, kısıtla/kaldır
  • Okuma — feed (senin için/takip + sayfalama), profil & gönderiler, gönderi + yanıtlar, sayaçlar, bildirimler, kullanıcı/kelime arama
  • Medya — gönderinin görsel/videolarını indir; yerel dosyadan yükle
  • Profil — bio/ad/link/gizlilik düzenle, profil fotoğrafı değiştir/kaldır
  • Canlı event — bildirimleri yoklayıp tipli event yayar (follow, like, reply, mention, repost, quote) → tepkisel botlar
  • Dayanıklı — retry + üstel backoff, 429'da asla çökmez (yakalanabilir RateLimitError fırlatır)

Kurulum

npm install threads-bot
# opsiyonel — sadece credential login / self-healing için:
npm install puppeteer-core

Node.js ≥ 18 gerekir (global fetch kullanır).

Hızlı başlangıç

const { ThreadsClient } = require("threads-bot");

const t = new ThreadsClient({ cookies: "./cookies.json" });
await t.init();

await t.createPost("threads-bot'tan selam! 🤖");
const feed = await t.getFeed({ limit: 10 });
await t.like(feed.items[0].id);
await t.follow("zuck");

Kimlik doğrulama

Seçenek A — cookie. threads.com cookie'lerini ("Cookie-Editor" eklentisi gibi) dışa aktar ve istediğin biçimde ver:

new ThreadsClient({ cookies: "./cookies.json" });                       // .json yolu
new ThreadsClient({ cookies: [{ name: "sessionid", value: "…" }, …] }); // tarayıcı-export dizi
new ThreadsClient({ cookies: { sessionid: "…", ds_user_id: "…", csrftoken: "…" } });
new ThreadsClient({ cookies: "sessionid=…; ds_user_id=…; csrftoken=…" }); // cookie string

Zorunlu cookie'ler: sessionid, ds_user_id, csrftoken. Önerilen: ig_did, mid, rur.

Seçenek B — kullanıcı adı/şifre. Gerçek bir Chrome penceresinde giriş yapar (puppeteer-core + Chrome gerekir), cookie'leri cache'ler ve session düşerse otomatik yeniden giriş yapar:

const t = new ThreadsClient({
  credentials: { username: "sen", password: "gizli" },
  cookieFile: "./cookies.json",   // burada cache'lenir, sonraki çalışmada kullanılır
  loginHeadless: false,           // görünür pencere 2FA/checkpoint çözmeni sağlar
});
await t.init();

💡 Başka cihazdan export edilen cookie'ler write işlemlerinden sonra geçersiz kılınabilir. Kararlı session için botu çalıştıracağın makineden credential ile giriş yap — o cookie'ler o IP'ye bağlıdır.

API başvurusu

Okuma

| Metot | Döner | |---|---| | me() / viewer() | Giriş yapan kullanıcı | | getFeed({ variant, cursor, limit }) | { items, pageInfo }variant: "for_you" \| "following" | | iterateFeed({ max, variant }) | gönderiler üzerinde async generator | | getUser(idVeyaKullanıcıAdı) | Profil | | getUserPosts(idVeyaKullanıcıAdı, { cursor, limit }) | { items, pageInfo } | | getThread(postId) | { post, replies, pageInfo } | | getReplies(postId, { cursor, limit, sort }) | Yanıtlar (bir yanıt id'siyle → iç içe yorumlar) | | getPostCounts(ids) | { counts: [{ likeCount, replyCount, repostCount, quoteCount }] } | | getNotifications({ cursor, limit }) | Bildirim akışı | | searchUsers(q) · searchTags(q) · search(q) | Arama | | resolveUserId(kullanıcıAdı) | @kullanıcı → sayısal id |

Yazma & etkileşim

| Metot | Açıklama | |---|---| | createPost(text, { media, replyTo, replyControl }) | media = görsel/video yolu, ya da carousel için görsel dizisi | | reply(postId, text) · quote(postId, text) | Yanıt (iç içe) · alıntı (orijinali gömer) | | like(id) / unlike(id) | Beğen / geri al | | follow(u) / unfollow(u) | Takip et / bırak | | repost(id) / unrepost(id) | Repost / geri al | | mute(u) / unmute(u) | Sustur / aç | | block(u) / unblock(u) | Engelle / kaldır | | restrict(u) / unrestrict(u) | Kısıtla / kaldır | | deletePost(id) | Kendi gönderini sil |

Medya & profil

| Metot | Açıklama | |---|---| | downloadMedia(postVeyaId, { dir }) | Gönderinin görsel/videolarını diske indir | | getMediaUrls(postVeyaId) | Gönderinin medya URL'leri | | updateProfile({ bio, name, link, isPrivate }) | Profili düzenle (verilmeyen alan mevcut değerini korur) | | setProfilePhoto(dosya) / removeProfilePhoto() | Profil fotoğrafını değiştir / kaldır |

Canlı event (tepkisel bot)

Threads'in webhook'u yok; istemci bildirimleri senin belirlediğin aralıkta yoklar ve tipli event yayar:

client.on("follow",  (e) => client.follow(e.fromUser.id));         // otomatik geri takip
client.on("reply",   (e) => client.reply(e.postId, "teşekkürler 🙏")); // yoruma yanıt
client.on("mention", (e) => client.reply(e.postId, "👀"));
client.on("like",    (e) => console.log(e.fromUser.username, "beğendi"));
client.on("rateLimited", () => console.log("yavaşlıyor…"));

client.startListening({ intervalMs: 60000 });
// client.stopListening();

Event'ler: notification (her öğe) + follow · like · reply · mention · repost · quote · followRequest. Payload: { id, type, fromUser:{ id, username }, postId, text, raw }. Döngü dayanıklıdır — başarısız bir poll (429 dahil) döngüyü durdurmaz.

Rate limit

Her istek 429/5xx'te üstel backoff ile retry yapar (Retry-After'a saygılı); hâlâ limitliyse yakalanabilir RateLimitError fırlatır — process asla çökmez. Yoğun döngüleri yavaşlat:

const { RateLimitError } = require("threads-bot");
try { await client.follow(id); }
catch (e) { if (e instanceof RateLimitError) await sleep(60_000); else throw e; }

Nasıl çalışır

Kütüphane threads.com web uygulamasını reverse-engineer eder: okuma ve çoğu mutation için GraphQL persisted query'ler (/graphql/query, /api/graphql), gönderi/medya için IG-tarzı REST (/api/v1/media/configure_*, rupload_*). Session token'ları (lsd, fb_dtsg) ana sayfa HTML'inden düz HTTP ile alınır. API ile doğrudan konuştuğu için çalışma anında tarayıcı gerektirmez.

Sorumluluk reddi

Resmi değildir. Meta veya Threads ile bağlantılı değildir. Haber verilmeden değişebilen ve Threads Kullanım Şartları'na aykırı olabilen özel endpoint'ler kullanır. Kendi hesabını otomatikleştirmek içindir — sorumlu kullan, risk sana aittir.


License / Lisans

MIT © alpersamur3