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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@montoulieu/threads-api

v1.6.3

Published

Unofficial, Reverse-Engineered Node.js/TypeScript client for Meta's [Threads](https://threads.net).

Downloads

5

Readme

Threads API

NPM MIT License Prettier Code Formatting

Unofficial, Reverse-Engineered Node.js/TypeScript client for Meta's Threads.

threads-api in Action

✨ The App Registry is officially live! We invite you to explore it on our website at threads.junho.io. Modify threads-web-ui/data/apps.ts to add your projects!

🚀 Usage (Read)

import { ThreadsAPI } from 'threads-api';

// or in Deno 🦖:
// import ThreadsAPI from "npm:threads-api";

const main = async () => {
  const threadsAPI = new ThreadsAPI();

  const username = '_junhoyeo';

  // 👤 Details for a specific user
  const userID = await threadsAPI.getUserIDfromUsername(username);
  if (!userID) {
    return;
  }
  const user = await threadsAPI.getUserProfile(userID);
  console.log(JSON.stringify(user));
  const posts = await threadsAPI.getUserProfileThreads(userID);
  console.log(JSON.stringify(posts));
  const replies = await threadsAPI.getUserProfileReplies(userID);
  console.log(JSON.stringify(replies));

  // 📖 Details for a specific thread
  const postID = threadsAPI.getPostIDfromURL(
    'https://www.threads.net/t/CuX_UYABrr7/?igshid=MzRlODBiNWFlZA==',
  );
  // or use `threadsAPI.getPostIDfromThreadID('CuX_UYABrr7')`
  if (!postID) {
    return;
  }
  const post = await threadsAPI.getThreads(postID);
  console.log(JSON.stringify(post.containing_thread));
  console.log(JSON.stringify(post.reply_threads));

  const likers = await threadsAPI.getThreadLikers(postID);
  console.log(JSON.stringify(likers));
};
main();

Read: Private(Auth Required)

💡 Get User Profile (from v1.6.2)
  • getUserProfile but with auth
const userID = '5438123050';
const { user } = await threadsAPI.getUserProfileLoggedIn();
console.log(JSON.stringify(user));
💡 Get Timeline
const { items: threads, next_max_id: cursor } = await threadsAPI.getTimeline();
console.log(JSON.stringify(threads));
💡 Get Threads/Replies from a User (with pagination)
const { threads, next_max_id: cursor } = await threadsAPI.getUserProfileThreadsLoggedIn(userID);
console.log(JSON.stringify(threads));
const { threads, next_max_id: cursor } = await threadsAPI.getUserProfileRepliesLoggedIn(userID);
console.log(JSON.stringify(threads));
💡 Get Followers/Followings of a User (with Pagination)
const { users, next_max_id: cursor } = await threadsAPI.getUserFollowers(userID);
console.log(JSON.stringify(users));
const { users, next_max_id: cursor } = await threadsAPI.getUserFollowings(userID);
console.log(JSON.stringify(users));
💡 Get Details(with Following Threads) for a specific Thread (from v1.6.2)
  • getThreads but with auth (this will return more data)
let data = await threadsAPI.getThreadsLoggedIn(postID);
console.log(JSON.stringify(data.containing_thread));
console.log(JSON.stringify(data.reply_threads));
console.log(JSON.stringify(data.subling_threads));

if (data.downwards_thread_will_continue) {
  const cursor = data.paging_tokens.downward;
  data = await threadsAPI.getThreadsLoggedIn(postID, cursor);
}
🔔 Get Notifications (from v1.6.2)
let data = await threadsAPI.getNotifications(
  ThreadsAPI.NotificationFilter.MENTIONS, // {MENTIONS, REPLIES, VERIFIED}
);

if (!data.is_last_page) {
  const cursor = data.next_max_id;
  data = await threadsAPI.getNotifications(ThreadsAPI.NotificationFilter.MENTIONS, cursor);
}
💎 Get Recommended Users (from v1.6.2)
let data = await threadsAPI.getRecommendedUsers();
console.log(JSON.stringify(data.users)); // ThreadsUser[]

if (data.has_more) {
  const cursor = data.paging_token;
  data = await threadsAPI.getRecommendedUsers(cursor);
}
🔍 Search Users (from v1.6.2)
const query = 'zuck';
const count = 40; // default value is set to 30
const data = await threadsAPI.searchUsers(query, count);

console.log(JSON.stringify(data.num_results));
console.log(JSON.stringify(data.users)); // ThreadsUser[]

🚀 Usage (Write)

Note From v1.4.0, you can also call login to update your token and userID(for current credentials). Or you can just use the methods below, and they'll take care of the authentication automatically (e.g. if it's the first time you're using those).

New API (from v1.2.0)

✨ Text Threads
import { ThreadsAPI } from 'threads-api';

const main = async () => {
  const threadsAPI = new ThreadsAPI({
    username: '_junhoyeo', // Your username
    password: 'PASSWORD', // Your password
  });

  await threadsAPI.publish({
    text: '🤖 Hello World',
  });
};

main();

💡 TIP: Use the url field in ThreadsAPIPublishOptions to render Link Attachments(link previews).

✨ Reply Control (from v1.4.6)
await threadsAPI.publish({
  text: '🤖 Threads with Reply Control',
  replyControl: 'accounts_you_follow', // 'everyone' | 'accounts_you_follow' | 'mentioned_only'
});
✨ Threads with Link Attachment
await threadsAPI.publish({
  text: '🤖 Threads with Link Attachment',
  attachment: {
    url: 'https://github.com/junhoyeo/threads-api',
  },
});
✨ Threads with Image
await threadsAPI.publish({
  text: '🤖 Threads with Image',
  attachment: {
    image: 'https://github.com/junhoyeo/threads-api/raw/main/.github/cover.jpg',
  },
});

ThreadsAPI.Image in attachment.image can also be type of ThreadsAPI.ExternalImage or ThreadsAPI.RawImage.

✨ Threads with Sidecar (Multiple Images)

Info The term "sidecar" is what Threads uses to represent a group of images and/or videos that share the same post.

await threadsAPI.publish({
  text: '🤖 Threads with Sidecar',
  attachment: {
    sidecar: [
      'https://github.com/junhoyeo/threads-api/raw/main/.github/cover.jpg',
      'https://github.com/junhoyeo/threads-api/raw/main/.github/cover.jpg',
      { path: './zuck.jpg' }, // ThreadsAPI.ExternalImage
      { type: '.jpg', data: Buffer.from(…) }, // ThreadsAPI.RawImage
    ],
  },
});
✨ Reply to Other Threads
const parentURL = 'https://www.threads.net/t/CugF-EjhQ3r';
const parentPostID = threadsAPI.getPostIDfromURL(parentURL); // or use `getPostIDfromThreadID`

await threadsAPI.publish({
  text: '🤖 Beep',
  link: 'https://github.com/junhoyeo/threads-api',
  parentPostID: parentPostID,
});
✨ Quote a Thread (from v1.4.2)
const threadURL = 'https://www.threads.net/t/CuqbBI8h19H';
const postIDToQuote = threadsAPI.getPostIDfromURL(threadURL); // or use `getPostIDfromThreadID`

await threadsAPI.publish({
  text: '🤖 Quote a Thread',
  quotedPostID: postIDToQuote,
});
✨ Like/Unlike a Thread (from v1.3.0)
const threadURL = 'https://www.threads.net/t/CugK35fh6u2';
const postIDToLike = threadsAPI.getPostIDfromURL(threadURL); // or use `getPostIDfromThreadID`

// 💡 Uses current credentials
await threadsAPI.like(postIDToLike);
await threadsAPI.unlike(postIDToLike);
✨ Follow/Unfollow a User (from v1.3.0)
const userIDToFollow = await threadsAPI.getUserIDfromUsername('junhoyeo');

// 💡 Uses current credentials
await threadsAPI.follow(userIDToFollow);
await threadsAPI.unfollow(userIDToFollow);
✨ Repost/Unrepost a Thread (from v1.4.2)
const threadURL = 'https://www.threads.net/t/CugK35fh6u2';
const postIDToRepost = threadsAPI.getPostIDfromURL(threadURL); // or use `getPostIDfromThreadID`

// 💡 Uses current credentials
await threadsAPI.repost(postIDToRepost);
await threadsAPI.unrepost(postIDToRepost);
✨ Delete a Post (from v1.3.1)
const postID = await threadsAPI.publish({
  text: '🤖 This message will self-destruct in 5 seconds.',
});

await new Promise((resolve) => setTimeout(resolve, 5_000));
await threadsAPI.delete(postID);
🔇 Mute/Unmute a User/Post (from v1.6.2)
const userID = await threadsAPI.getUserIDfromUsername('zuck');
const threadURL = 'https://www.threads.net/t/CugK35fh6u2';
const postID = threadsAPI.getPostIDfromURL(threadURL); // or use `getPostIDfromThreadID`

// 💡 Uses current credentials

// Mute User
await threadsAPI.mute({ userID });
await threadsAPI.unfollow({ userID });

// Mute a Post of User
await threadsAPI.mute({ userID, postID });
await threadsAPI.unfollow({ userID, postID });
🔇 Block/Unblock a User (from v1.6.2)
const userID = await threadsAPI.getUserIDfromUsername('zuck');

// 💡 Uses current credentials
await threadsAPI.block({ userID });
await threadsAPI.unblock({ userID });
🔔 Set Notifications Seen (from v1.6.2)
// 💡 Uses current credentials
await threadsAPI.setNotificationsSeen();
✨ Threads with Image
await threadsAPI.publish({
  text: '🤖 Threads with Image',
  image: 'https://github.com/junhoyeo/threads-api/raw/main/.github/cover.jpg',
});
✨ Threads with Link Attachment
await threadsAPI.publish({
  text: '🤖 Threads with Link Attachment',
  url: 'https://github.com/junhoyeo/threads-api',
});
import { ThreadsAPI } from 'threads-api';

const main = async () => {
  const threadsAPI = new ThreadsAPI({
    username: 'jamel.hammoud', // Your username
    password: 'PASSWORD', // Your password
  });

  await threadsAPI.publish('🤖 Hello World');
};

main();

You can also provide custom deviceID (Default is android-${(Math.random() * 1e24).toString(36)}).

const deviceID = `android-${(Math.random() * 1e24).toString(36)}`;

const threadsAPI = new ThreadsAPI({
  username: 'jamel.hammoud',
  password: 'PASSWORD',
  deviceID,
});

Installation

yarn add threads-api
# or with npm
npm install threads-api
# or with pnpm
pnpm install threads-api
// or in Deno 🦖
import ThreadsAPI from 'npm:threads-api';

const threadsAPI = new ThreadsAPI.ThreadsAPI({});

Roadmap

  • [x] ✅ Read public data
    • [x] ✅ Fetch UserID(314216) via username(zuck)
    • [x] ✅ Read timeline feed
    • [x] ✅ Read User Profile Info
    • [x] ✅ Read list of User Threads
      • [x] ✅ With Pagination (If auth provided)
    • [x] ✅ Read list of User Replies
      • [x] ✅ With Pagination (If auth provided)
    • [x] ✅ Fetch PostID(3140957200974444958) via ThreadID(CuW6-7KyXme) or PostURL(https://www.threads.net/t/CuW6-7KyXme)
    • [x] ✅ Read Threads via PostID
    • [x] ✅ Read Likers in Thread via PostID
    • [x] ✅ Read User Followers
    • [x] ✅ Read User Followings
  • [x] ✅ Write data (i.e. write automated Threads)
    • [x] ✅ Create new Thread with text
      • [x] ✅ Make link previews to get shown
    • [x] ✅ Create new Thread with a single image
    • [x] ✅ Create new Thread with multiple images
    • [x] ✅ Reply to existing Thread
    • [x] ✅ Quote Thread
    • [x] ✅ Delete Thread
  • [x] ✅ Friendships
    • [x] ✅ Follow User
    • [x] ✅ Unfollow User
  • [x] ✅ Interactions
    • [x] ✅ Like Thread
    • [x] ✅ Unlike Thread
  • [x] 🏴‍☠️ Restructure the project as a monorepo
    • [x] 🏴‍☠ Add Demo App with Next.js
    • [x] 🏴‍☠️ Cool CLI App to run Threads in the Terminal

Projects made with threads-api

Add yours by just opening an pull request!

🏴‍☠️ react-threads: Embed Static Threads in your React/Next.js application.

NPM MIT License Prettier Code Formatting

Embed Static Threads in your React/Next.js application. UI components for Meta's Threads. Powered by junhoyeo/threads-api.

cover

Demo

Warning Vercel Deployment is currently sometimes unstable. 🏴‍☠️

cover

To use the threads-api command line interface, run the following command:

$ npx threads-api --help
Usage: threads-api [command] [options]

Options:
  -v, --version                                                                   output the current version
  -h, --help                                                                      display help for command

Commands:
  help                                                                            display help for command
  getUserIDfromUsername|userid|uid|id <username>                                  det user ID from username
  getUserProfile|userprofile|uprof|up <username> <userId> [stringify]             get user profile
  getUserProfileThreads|uthreads|ut <username> <userId> [stringify]               get user profile threads
  getUserProfileReplies|userreplies|ureplies|ur <username> <userId> [stringify]   get user profile replies
  getPostIDfromURL|postid|pid|p <postURL>                                         get post ID from URL
  getThreads|threads|t <postId> [stringify]                                       get threads
  getThreadLikers|threadlikers|likers|l <postId> [stringify]                      get thread likers

👤 threads-card: Share your Threads profile easily

👤 Strings: Web-Frontend for Threads

Screenshot (84)

👤 threads-projects: Unleashing the power of Meta's Threads.net platform with insightful bots and efficient workflows

🧵 thread-count: Custom status badges for Meta's Threads.net follower counts

| parameter | demo | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Default (_junhoyeo's account) | | | Custom Text and Colors | | | Scale Badge Size | https://www.threads.net/@zuck |

🤖 thread-year-prog-bot: Bot weaving the fabric of time

License

If you find this project intriguing, please consider starring it(⭐) or following me on GitHub (I wouldn't say Threads). I code 24/7 and ship mind-breaking things on a regular basis, so your support definitely won't be in vain.