Threads Data Extraction Guide 2025
Threads launched as Meta's answer to Twitter, and it's grown fast—over 100 million users.
For developers and researchers, Threads data is increasingly valuable. But Meta hasn't released a public API yet.
Here's how to actually get Threads data in 2025.
Need Threads data? Check our Threads API alternatives for the best options.
What Data Can You Extract?
Profile Data
- Username and display name
- Bio/description
- Follower and following counts
- Profile picture URL
- Verified status
- Link to Instagram account
Thread Posts
- Text content
- Media attachments (images, videos)
- Like count
- Reply count
- Repost count
- Timestamp
- Parent thread (for replies)
User Activity
- Recent posts
- Replies
- Reposts
The API Situation
Official Meta API
As of 2025, Meta has:
- No public Threads API for third-party developers
- Basic API access for verified publishers only
- Plans for a broader API "coming soon" (since launch)
If you're not a verified publisher, the official route is blocked.
Third-Party Solutions
This is where most developers turn:
const API_KEY = process.env.SOCIAVAULT_API_KEY;
async function getThreadsProfile(username) {
const response = await fetch(
`https://api.sociavault.com/v1/scrape/threads/profile?username=${username}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
return response.json();
}
const profile = await getThreadsProfile('zuck');
console.log(profile.data);
Response:
{
"username": "zuck",
"name": "Mark Zuckerberg",
"bio": "Building things to help people connect...",
"followers": 3200000,
"following": 450,
"verified": true,
"profile_pic_url": "https://...",
"instagram_username": "zuck"
}
Code Examples
Get User's Threads
async function getUserThreads(username, count = 20) {
const response = await fetch(
`https://api.sociavault.com/v1/scrape/threads/posts?username=${username}&count=${count}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
return response.json();
}
const threads = await getUserThreads('zuck', 30);
threads.data.posts.forEach(thread => {
console.log({
content: thread.text,
likes: thread.like_count,
replies: thread.reply_count,
posted: thread.timestamp
});
});
Get Thread Details
async function getThread(threadUrl) {
const response = await fetch(
`https://api.sociavault.com/v1/scrape/threads/post?url=${encodeURIComponent(threadUrl)}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
return response.json();
}
Search Threads
async function searchThreads(keyword, count = 50) {
const response = await fetch(
`https://api.sociavault.com/v1/scrape/threads/search?query=${encodeURIComponent(keyword)}&count=${count}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
return response.json();
}
const results = await searchThreads('AI startups', 100);
Python Examples
import os
import requests
API_KEY = os.getenv('SOCIAVAULT_API_KEY')
API_BASE = 'https://api.sociavault.com/v1/scrape/threads'
def get_threads_profile(username):
response = requests.get(
f'{API_BASE}/profile',
params={'username': username},
headers={'Authorization': f'Bearer {API_KEY}'}
)
response.raise_for_status()
return response.json()
def get_user_threads(username, count=20):
response = requests.get(
f'{API_BASE}/posts',
params={'username': username, 'count': count},
headers={'Authorization': f'Bearer {API_KEY}'}
)
response.raise_for_status()
return response.json()
# Example usage
profile = get_threads_profile('zuck')
print(f"{profile['data']['name']}: {profile['data']['followers']} followers")
threads = get_user_threads('zuck', 10)
for thread in threads['data']['posts']:
print(f"- {thread['text'][:50]}... ({thread['like_count']} likes)")
Use Cases
1. Brand Monitoring
Track mentions of your brand on Threads:
async function monitorBrand(brandName) {
const mentions = await searchThreads(brandName, 100);
const analyzed = mentions.data.posts.map(post => ({
author: post.username,
content: post.text,
engagement: post.like_count + post.reply_count,
sentiment: analyzeSentiment(post.text),
url: post.url,
timestamp: post.timestamp
}));
// Filter for high-engagement mentions
const significant = analyzed.filter(m => m.engagement > 10);
return {
totalMentions: analyzed.length,
significantMentions: significant,
averageSentiment: average(analyzed.map(m => m.sentiment))
};
}
2. Competitor Tracking
Monitor what competitors are posting:
async function trackCompetitors(competitorUsernames) {
const insights = [];
for (const username of competitorUsernames) {
const profile = await getThreadsProfile(username);
const threads = await getUserThreads(username, 30);
const avgEngagement = average(threads.data.posts.map(t =>
t.like_count + t.reply_count
));
insights.push({
username,
followers: profile.data.followers,
postFrequency: calculateFrequency(threads.data.posts),
avgEngagement,
topPosts: getTopPosts(threads.data.posts, 3),
contentThemes: extractThemes(threads.data.posts)
});
}
return insights;
}
3. Influencer Discovery
Find influential accounts in your niche:
async function findInfluencers(niche, minFollowers = 10000) {
// Search for niche-related content
const results = await searchThreads(niche, 200);
// Get unique authors
const authors = [...new Set(results.data.posts.map(p => p.username))];
// Filter by follower count
const influencers = [];
for (const username of authors) {
const profile = await getThreadsProfile(username);
if (profile.data.followers >= minFollowers) {
influencers.push({
username: profile.data.username,
name: profile.data.name,
followers: profile.data.followers,
verified: profile.data.verified,
bio: profile.data.bio
});
}
await sleep(500);
}
return influencers.sort((a, b) => b.followers - a.followers);
}
4. Content Research
Analyze what content performs well:
async function analyzeTopContent(topic) {
const results = await searchThreads(topic, 500);
// Sort by engagement
const sorted = results.data.posts.sort((a, b) => {
const engA = a.like_count + a.reply_count * 2;
const engB = b.like_count + b.reply_count * 2;
return engB - engA;
});
const topPosts = sorted.slice(0, 20);
return {
topPosts,
commonPatterns: extractPatterns(topPosts),
avgLength: average(topPosts.map(p => p.text.length)),
hasMedia: topPosts.filter(p => p.has_media).length / topPosts.length,
bestPostingTimes: extractPostingTimes(topPosts)
};
}
Building a Threads Monitor
const Database = require('better-sqlite3');
const db = new Database('threads_monitor.db');
// Initialize
db.exec(`
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY,
username TEXT UNIQUE,
followers INTEGER,
updated_at DATETIME
);
CREATE TABLE IF NOT EXISTS threads (
id INTEGER PRIMARY KEY,
account_id INTEGER,
thread_id TEXT UNIQUE,
text TEXT,
likes INTEGER,
replies INTEGER,
created_at DATETIME,
FOREIGN KEY (account_id) REFERENCES accounts(id)
);
`);
async function syncAccount(username) {
const profile = await getThreadsProfile(username);
const threads = await getUserThreads(username, 50);
// Upsert account
db.prepare(`
INSERT INTO accounts (username, followers, updated_at)
VALUES (?, ?, datetime('now'))
ON CONFLICT(username) DO UPDATE SET
followers = excluded.followers,
updated_at = excluded.updated_at
`).run(username, profile.data.followers);
const account = db.prepare('SELECT id FROM accounts WHERE username = ?').get(username);
// Insert threads
const insert = db.prepare(`
INSERT OR REPLACE INTO threads (account_id, thread_id, text, likes, replies, created_at)
VALUES (?, ?, ?, ?, ?, ?)
`);
for (const thread of threads.data.posts) {
insert.run(
account.id,
thread.id,
thread.text,
thread.like_count,
thread.reply_count,
thread.timestamp
);
}
}
Threads vs Twitter Comparison
When migrating from Twitter data collection:
| Feature | Threads | |
|---|---|---|
| Text length | 280 chars | 500 chars |
| Media | Images, video, GIFs | Images, video |
| Threading | Reply chains | Native threads |
| Engagement | Likes, retweets, replies | Likes, reposts, replies |
| Profile data | Comprehensive | Basic |
| API availability | $100/mo+ | Third-party only |
Best Practices
1. Respect Rate Limits
async function batchFetch(usernames, delayMs = 500) {
const results = [];
for (const username of usernames) {
const data = await getThreadsProfile(username);
results.push(data);
await new Promise(r => setTimeout(r, delayMs));
}
return results;
}
2. Cache Profile Data
const profileCache = new Map();
const CACHE_TTL = 3600000; // 1 hour
async function getCachedProfile(username) {
const cached = profileCache.get(username);
if (cached && Date.now() - cached.time < CACHE_TTL) {
return cached.data;
}
const data = await getThreadsProfile(username);
profileCache.set(username, { data, time: Date.now() });
return data;
}
3. Handle Private Accounts
async function safeGetProfile(username) {
try {
const data = await getThreadsProfile(username);
return { success: true, data };
} catch (error) {
if (error.message.includes('private')) {
return { success: false, reason: 'private' };
}
throw error;
}
}
Ready to extract Threads data?
Get started with 50 free credits at SociaVault.
Related:
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API. No credit card required.