Track Hashtag Performance Across TikTok, Instagram & Twitter
Hashtags behave differently on every platform.
A hashtag that's blowing up on TikTok might be dead on Instagram. A trending Twitter hashtag might not even exist on TikTok.
If you're running a campaign, doing brand monitoring, or tracking trends, you need visibility across all platforms—not just one.
I'll show you how to build a unified hashtag tracker that:
- Monitors hashtags on TikTok, Instagram, and Twitter simultaneously
- Tracks metrics like views, posts, and engagement
- Stores historical data for trend analysis
- Alerts you when a hashtag is gaining momentum
Skip the build? Get hashtag data instantly at sociavault.com/free/social-media-api.
Why Track Hashtags Across Platforms?
Different Platforms, Different Behaviors
Here's what I've seen tracking hashtags for clients:
| Platform | Hashtag Lifespan | Peak Speed | Best For |
|---|---|---|---|
| TikTok | 2-7 days | Very fast | Viral challenges, trends |
| 3-14 days | Medium | Brand campaigns, niches | |
| Hours-2 days | Instant | News, events, real-time |
A hashtag strategy that works on Instagram will fail on TikTok. You need data from all platforms to make good decisions.
Real Use Cases
Brand monitoring: Is your campaign hashtag getting traction? Where?
Competitor tracking: Which hashtags are competitors winning on?
Trend spotting: What's emerging before it goes mainstream?
Influencer campaigns: Are your creators actually using your hashtag?
Project Setup
mkdir hashtag-tracker
cd hashtag-tracker
npm init -y
npm install better-sqlite3 dotenv node-cron
Create your .env:
SOCIAVAULT_API_KEY=your_api_key_here
Database Schema
We need to track hashtags and their metrics over time:
// db.js
const Database = require('better-sqlite3');
const db = new Database('hashtags.db');
// Initialize tables
db.exec(`
CREATE TABLE IF NOT EXISTS hashtags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS hashtag_metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
hashtag_id INTEGER NOT NULL,
platform TEXT NOT NULL,
post_count INTEGER DEFAULT 0,
view_count INTEGER DEFAULT 0,
engagement_count INTEGER DEFAULT 0,
sample_posts TEXT,
recorded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (hashtag_id) REFERENCES hashtags(id)
);
CREATE INDEX IF NOT EXISTS idx_metrics_hashtag
ON hashtag_metrics(hashtag_id);
CREATE INDEX IF NOT EXISTS idx_metrics_platform
ON hashtag_metrics(platform);
CREATE INDEX IF NOT EXISTS idx_metrics_time
ON hashtag_metrics(recorded_at);
`);
module.exports = db;
Platform Collectors
TikTok Hashtag Collector
// collectors/tiktok.js
require('dotenv').config();
const API_BASE = 'https://api.sociavault.com/v1/scrape/tiktok';
const API_KEY = process.env.SOCIAVAULT_API_KEY;
async function fetchTikTokHashtag(hashtag) {
const cleanTag = hashtag.replace('#', '');
const response = await fetch(
`${API_BASE}/hashtag?name=${encodeURIComponent(cleanTag)}&count=30`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
if (!response.ok) {
throw new Error(`TikTok API error: ${response.status}`);
}
const data = await response.json();
// Calculate metrics from returned videos
const videos = data.data?.videos || [];
const totalViews = videos.reduce((sum, v) => sum + (v.play_count || 0), 0);
const totalLikes = videos.reduce((sum, v) => sum + (v.like_count || 0), 0);
const totalComments = videos.reduce((sum, v) => sum + (v.comment_count || 0), 0);
const totalShares = videos.reduce((sum, v) => sum + (v.share_count || 0), 0);
return {
platform: 'tiktok',
hashtag: cleanTag,
post_count: data.data?.challenge_info?.video_count || videos.length,
view_count: data.data?.challenge_info?.view_count || totalViews,
engagement_count: totalLikes + totalComments + totalShares,
sample_posts: videos.slice(0, 5).map(v => ({
id: v.video_id,
author: v.author?.username,
views: v.play_count,
likes: v.like_count,
caption: v.description?.slice(0, 100)
}))
};
}
module.exports = { fetchTikTokHashtag };
Instagram Hashtag Collector
// collectors/instagram.js
require('dotenv').config();
const API_BASE = 'https://api.sociavault.com/v1/scrape/instagram';
const API_KEY = process.env.SOCIAVAULT_API_KEY;
async function fetchInstagramHashtag(hashtag) {
const cleanTag = hashtag.replace('#', '');
const response = await fetch(
`${API_BASE}/hashtag?name=${encodeURIComponent(cleanTag)}&count=30`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
if (!response.ok) {
throw new Error(`Instagram API error: ${response.status}`);
}
const data = await response.json();
const posts = data.data?.posts || [];
const totalLikes = posts.reduce((sum, p) => sum + (p.like_count || 0), 0);
const totalComments = posts.reduce((sum, p) => sum + (p.comment_count || 0), 0);
// Instagram doesn't expose views for regular posts
const reelViews = posts
.filter(p => p.media_type === 'video')
.reduce((sum, p) => sum + (p.view_count || 0), 0);
return {
platform: 'instagram',
hashtag: cleanTag,
post_count: data.data?.media_count || posts.length,
view_count: reelViews,
engagement_count: totalLikes + totalComments,
sample_posts: posts.slice(0, 5).map(p => ({
id: p.post_id,
author: p.author?.username,
likes: p.like_count,
comments: p.comment_count,
caption: p.caption?.slice(0, 100)
}))
};
}
module.exports = { fetchInstagramHashtag };
Twitter Hashtag Collector
// collectors/twitter.js
require('dotenv').config();
const API_BASE = 'https://api.sociavault.com/v1/scrape/twitter';
const API_KEY = process.env.SOCIAVAULT_API_KEY;
async function fetchTwitterHashtag(hashtag) {
const cleanTag = hashtag.replace('#', '');
const response = await fetch(
`${API_BASE}/search?query=${encodeURIComponent('#' + cleanTag)}&count=50`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
if (!response.ok) {
throw new Error(`Twitter API error: ${response.status}`);
}
const data = await response.json();
const tweets = data.data?.tweets || [];
const totalLikes = tweets.reduce((sum, t) => sum + (t.like_count || 0), 0);
const totalRetweets = tweets.reduce((sum, t) => sum + (t.retweet_count || 0), 0);
const totalReplies = tweets.reduce((sum, t) => sum + (t.reply_count || 0), 0);
const totalViews = tweets.reduce((sum, t) => sum + (t.view_count || 0), 0);
return {
platform: 'twitter',
hashtag: cleanTag,
post_count: tweets.length, // Twitter doesn't expose total count
view_count: totalViews,
engagement_count: totalLikes + totalRetweets + totalReplies,
sample_posts: tweets.slice(0, 5).map(t => ({
id: t.tweet_id,
author: t.author?.username,
views: t.view_count,
likes: t.like_count,
text: t.text?.slice(0, 100)
}))
};
}
module.exports = { fetchTwitterHashtag };
Unified Tracker
// tracker.js
const db = require('./db');
const { fetchTikTokHashtag } = require('./collectors/tiktok');
const { fetchInstagramHashtag } = require('./collectors/instagram');
const { fetchTwitterHashtag } = require('./collectors/twitter');
const collectors = {
tiktok: fetchTikTokHashtag,
instagram: fetchInstagramHashtag,
twitter: fetchTwitterHashtag
};
class HashtagTracker {
constructor() {
this.insertHashtag = db.prepare(`
INSERT OR IGNORE INTO hashtags (name) VALUES (?)
`);
this.getHashtagId = db.prepare(`
SELECT id FROM hashtags WHERE name = ?
`);
this.insertMetrics = db.prepare(`
INSERT INTO hashtag_metrics
(hashtag_id, platform, post_count, view_count, engagement_count, sample_posts)
VALUES (?, ?, ?, ?, ?, ?)
`);
this.getLatestMetrics = db.prepare(`
SELECT * FROM hashtag_metrics
WHERE hashtag_id = ? AND platform = ?
ORDER BY recorded_at DESC LIMIT 1
`);
this.getMetricsHistory = db.prepare(`
SELECT * FROM hashtag_metrics
WHERE hashtag_id = ? AND platform = ?
ORDER BY recorded_at DESC LIMIT ?
`);
}
// Add a hashtag to track
addHashtag(name) {
const cleanName = name.replace('#', '').toLowerCase();
this.insertHashtag.run(cleanName);
return this.getHashtagId.get(cleanName);
}
// Fetch metrics from all platforms
async collectMetrics(hashtagName, platforms = ['tiktok', 'instagram', 'twitter']) {
const hashtag = this.addHashtag(hashtagName);
const results = {};
for (const platform of platforms) {
try {
const collector = collectors[platform];
if (!collector) continue;
console.log(`Fetching ${platform} data for #${hashtagName}...`);
const metrics = await collector(hashtagName);
// Save to database
this.insertMetrics.run(
hashtag.id,
platform,
metrics.post_count,
metrics.view_count,
metrics.engagement_count,
JSON.stringify(metrics.sample_posts)
);
results[platform] = metrics;
// Rate limiting
await new Promise(r => setTimeout(r, 500));
} catch (error) {
console.error(`Error fetching ${platform}: ${error.message}`);
results[platform] = { error: error.message };
}
}
return results;
}
// Get cross-platform summary
async getSummary(hashtagName) {
const hashtag = this.getHashtagId.get(hashtagName.replace('#', '').toLowerCase());
if (!hashtag) return null;
const platforms = ['tiktok', 'instagram', 'twitter'];
const summary = {
hashtag: hashtagName,
platforms: {},
totals: {
posts: 0,
views: 0,
engagement: 0
}
};
for (const platform of platforms) {
const latest = this.getLatestMetrics.get(hashtag.id, platform);
if (latest) {
summary.platforms[platform] = {
posts: latest.post_count,
views: latest.view_count,
engagement: latest.engagement_count,
sample_posts: JSON.parse(latest.sample_posts || '[]'),
updated: latest.recorded_at
};
summary.totals.posts += latest.post_count;
summary.totals.views += latest.view_count;
summary.totals.engagement += latest.engagement_count;
}
}
return summary;
}
// Calculate growth rate
async getGrowth(hashtagName, platform, periods = 7) {
const hashtag = this.getHashtagId.get(hashtagName.replace('#', '').toLowerCase());
if (!hashtag) return null;
const history = this.getMetricsHistory.all(hashtag.id, platform, periods);
if (history.length < 2) return null;
const newest = history[0];
const oldest = history[history.length - 1];
const calculateGrowth = (current, previous) => {
if (previous === 0) return current > 0 ? 100 : 0;
return ((current - previous) / previous * 100).toFixed(2);
};
return {
platform,
period: `${history.length} data points`,
posts_growth: calculateGrowth(newest.post_count, oldest.post_count),
views_growth: calculateGrowth(newest.view_count, oldest.view_count),
engagement_growth: calculateGrowth(newest.engagement_count, oldest.engagement_count)
};
}
}
module.exports = HashtagTracker;
Trend Detection
// detector.js
const db = require('./db');
class TrendDetector {
constructor(threshold = 50) {
this.threshold = threshold; // Percentage growth to trigger alert
this.getRecentMetrics = db.prepare(`
SELECT * FROM hashtag_metrics
WHERE hashtag_id = ? AND platform = ?
ORDER BY recorded_at DESC LIMIT 2
`);
this.getAllHashtags = db.prepare(`
SELECT * FROM hashtags
`);
}
// Check if a hashtag is trending
async checkTrending(hashtagId, platform) {
const metrics = this.getRecentMetrics.all(hashtagId, platform);
if (metrics.length < 2) return null;
const [current, previous] = metrics;
const viewGrowth = previous.view_count > 0
? ((current.view_count - previous.view_count) / previous.view_count) * 100
: 0;
const engagementGrowth = previous.engagement_count > 0
? ((current.engagement_count - previous.engagement_count) / previous.engagement_count) * 100
: 0;
const isTrending = viewGrowth > this.threshold || engagementGrowth > this.threshold;
return {
hashtag_id: hashtagId,
platform,
is_trending: isTrending,
view_growth: viewGrowth.toFixed(2),
engagement_growth: engagementGrowth.toFixed(2),
current_views: current.view_count,
current_engagement: current.engagement_count
};
}
// Scan all hashtags for trends
async scanAllTrends() {
const hashtags = this.getAllHashtags.all();
const platforms = ['tiktok', 'instagram', 'twitter'];
const trending = [];
for (const hashtag of hashtags) {
for (const platform of platforms) {
const result = await this.checkTrending(hashtag.id, platform);
if (result?.is_trending) {
trending.push({
hashtag: hashtag.name,
...result
});
}
}
}
return trending.sort((a, b) =>
parseFloat(b.view_growth) - parseFloat(a.view_growth)
);
}
}
module.exports = TrendDetector;
Automated Tracking with Cron
// scheduler.js
const cron = require('node-cron');
const HashtagTracker = require('./tracker');
const TrendDetector = require('./detector');
const tracker = new HashtagTracker();
const detector = new TrendDetector(50); // 50% growth threshold
// Hashtags to track
const TRACKED_HASHTAGS = [
'smallbusiness',
'contentcreator',
'entrepreneur',
'sidehustle',
'techstartup'
];
async function runCollection() {
console.log('Starting hashtag collection:', new Date().toISOString());
for (const hashtag of TRACKED_HASHTAGS) {
try {
await tracker.collectMetrics(hashtag);
console.log(`Collected: #${hashtag}`);
} catch (error) {
console.error(`Failed: #${hashtag} - ${error.message}`);
}
// Wait between hashtags
await new Promise(r => setTimeout(r, 2000));
}
// Check for trends
const trends = await detector.scanAllTrends();
if (trends.length > 0) {
console.log('\n🔥 TRENDING HASHTAGS:');
trends.forEach(t => {
console.log(` #${t.hashtag} on ${t.platform}: +${t.view_growth}% views`);
});
}
console.log('Collection complete:', new Date().toISOString());
}
// Run every 6 hours
cron.schedule('0 */6 * * *', runCollection);
// Run immediately on start
runCollection();
console.log('Hashtag tracker started. Running every 6 hours.');
Python Version
For Python developers:
# tracker.py
import os
import json
import sqlite3
import requests
from datetime import datetime
from typing import Dict, List, Optional
API_KEY = os.getenv('SOCIAVAULT_API_KEY')
API_BASE = 'https://api.sociavault.com/v1/scrape'
class HashtagTracker:
def __init__(self, db_path: str = 'hashtags.db'):
self.conn = sqlite3.connect(db_path)
self.conn.row_factory = sqlite3.Row
self._init_db()
def _init_db(self):
self.conn.executescript('''
CREATE TABLE IF NOT EXISTS hashtags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS hashtag_metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
hashtag_id INTEGER NOT NULL,
platform TEXT NOT NULL,
post_count INTEGER DEFAULT 0,
view_count INTEGER DEFAULT 0,
engagement_count INTEGER DEFAULT 0,
sample_posts TEXT,
recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (hashtag_id) REFERENCES hashtags(id)
);
''')
self.conn.commit()
def _fetch_platform(self, platform: str, hashtag: str) -> Dict:
"""Fetch hashtag data from a specific platform."""
headers = {'Authorization': f'Bearer {API_KEY}'}
clean_tag = hashtag.lstrip('#')
endpoints = {
'tiktok': f'{API_BASE}/tiktok/hashtag?name={clean_tag}&count=30',
'instagram': f'{API_BASE}/instagram/hashtag?name={clean_tag}&count=30',
'twitter': f'{API_BASE}/twitter/search?query=%23{clean_tag}&count=50'
}
response = requests.get(endpoints[platform], headers=headers)
response.raise_for_status()
return response.json()
def collect_metrics(self, hashtag: str, platforms: List[str] = None) -> Dict:
"""Collect metrics from all platforms for a hashtag."""
if platforms is None:
platforms = ['tiktok', 'instagram', 'twitter']
clean_tag = hashtag.lstrip('#').lower()
# Ensure hashtag exists in DB
cursor = self.conn.execute(
'INSERT OR IGNORE INTO hashtags (name) VALUES (?)',
(clean_tag,)
)
self.conn.commit()
# Get hashtag ID
row = self.conn.execute(
'SELECT id FROM hashtags WHERE name = ?',
(clean_tag,)
).fetchone()
hashtag_id = row['id']
results = {}
for platform in platforms:
try:
data = self._fetch_platform(platform, clean_tag)
metrics = self._parse_metrics(platform, data)
# Save to database
self.conn.execute('''
INSERT INTO hashtag_metrics
(hashtag_id, platform, post_count, view_count, engagement_count, sample_posts)
VALUES (?, ?, ?, ?, ?, ?)
''', (
hashtag_id,
platform,
metrics['post_count'],
metrics['view_count'],
metrics['engagement_count'],
json.dumps(metrics['sample_posts'])
))
self.conn.commit()
results[platform] = metrics
except Exception as e:
results[platform] = {'error': str(e)}
return results
def _parse_metrics(self, platform: str, data: Dict) -> Dict:
"""Parse platform-specific response into unified format."""
if platform == 'tiktok':
videos = data.get('data', {}).get('videos', [])
return {
'post_count': data.get('data', {}).get('challenge_info', {}).get('video_count', len(videos)),
'view_count': sum(v.get('play_count', 0) for v in videos),
'engagement_count': sum(
v.get('like_count', 0) + v.get('comment_count', 0) + v.get('share_count', 0)
for v in videos
),
'sample_posts': [
{'id': v.get('video_id'), 'author': v.get('author', {}).get('username')}
for v in videos[:5]
]
}
elif platform == 'instagram':
posts = data.get('data', {}).get('posts', [])
return {
'post_count': data.get('data', {}).get('media_count', len(posts)),
'view_count': sum(p.get('view_count', 0) for p in posts if p.get('media_type') == 'video'),
'engagement_count': sum(
p.get('like_count', 0) + p.get('comment_count', 0)
for p in posts
),
'sample_posts': [
{'id': p.get('post_id'), 'author': p.get('author', {}).get('username')}
for p in posts[:5]
]
}
elif platform == 'twitter':
tweets = data.get('data', {}).get('tweets', [])
return {
'post_count': len(tweets),
'view_count': sum(t.get('view_count', 0) for t in tweets),
'engagement_count': sum(
t.get('like_count', 0) + t.get('retweet_count', 0) + t.get('reply_count', 0)
for t in tweets
),
'sample_posts': [
{'id': t.get('tweet_id'), 'author': t.get('author', {}).get('username')}
for t in tweets[:5]
]
}
return {'post_count': 0, 'view_count': 0, 'engagement_count': 0, 'sample_posts': []}
def get_summary(self, hashtag: str) -> Optional[Dict]:
"""Get cross-platform summary for a hashtag."""
clean_tag = hashtag.lstrip('#').lower()
row = self.conn.execute(
'SELECT id FROM hashtags WHERE name = ?',
(clean_tag,)
).fetchone()
if not row:
return None
hashtag_id = row['id']
summary = {
'hashtag': clean_tag,
'platforms': {},
'totals': {'posts': 0, 'views': 0, 'engagement': 0}
}
for platform in ['tiktok', 'instagram', 'twitter']:
metrics = self.conn.execute('''
SELECT * FROM hashtag_metrics
WHERE hashtag_id = ? AND platform = ?
ORDER BY recorded_at DESC LIMIT 1
''', (hashtag_id, platform)).fetchone()
if metrics:
summary['platforms'][platform] = {
'posts': metrics['post_count'],
'views': metrics['view_count'],
'engagement': metrics['engagement_count'],
'updated': metrics['recorded_at']
}
summary['totals']['posts'] += metrics['post_count']
summary['totals']['views'] += metrics['view_count']
summary['totals']['engagement'] += metrics['engagement_count']
return summary
# Example usage
if __name__ == '__main__':
tracker = HashtagTracker()
# Track some hashtags
hashtags = ['contentcreator', 'smallbusiness', 'entrepreneur']
for tag in hashtags:
print(f'\nCollecting #`{tag}`...')
results = tracker.collect_metrics(tag)
for platform, data in results.items():
if 'error' in data:
print(f' {platform}: Error - {data["error"]}')
else:
print(f' {platform}: {data["post_count"]} posts, {data["view_count"]} views')
# Get summary
print('\n--- Summary for #contentcreator ---')
summary = tracker.get_summary('contentcreator')
if summary:
for platform, data in summary['platforms'].items():
print(f'{platform}: {data["posts"]} posts, {data["views"]} views')
print(f'Total: {summary["totals"]["posts"]} posts, {summary["totals"]["views"]} views')
Building a Dashboard
Want to visualize this data? Here's a quick Express server:
// server.js
const express = require('express');
const HashtagTracker = require('./tracker');
const TrendDetector = require('./detector');
const app = express();
const tracker = new HashtagTracker();
const detector = new TrendDetector(30);
app.get('/api/hashtag/:name', async (req, res) => {
const summary = await tracker.getSummary(req.params.name);
if (!summary) {
return res.status(404).json({ error: 'Hashtag not found' });
}
res.json(summary);
});
app.get('/api/hashtag/:name/collect', async (req, res) => {
const results = await tracker.collectMetrics(req.params.name);
res.json(results);
});
app.get('/api/trends', async (req, res) => {
const trends = await detector.scanAllTrends();
res.json(trends);
});
app.listen(3000, () => {
console.log('Dashboard API running on http://localhost:3000');
});
Real-World Campaign Example
Let's say you're running a brand campaign with hashtag #YourBrandSummer:
const HashtagTracker = require('./tracker');
const tracker = new HashtagTracker();
async function runCampaignReport() {
const campaignTag = 'YourBrandSummer';
// Collect fresh data
await tracker.collectMetrics(campaignTag);
// Get summary
const summary = await tracker.getSummary(campaignTag);
console.log('\n📊 CAMPAIGN REPORT: #YourBrandSummer\n');
console.log('Platform Performance:');
for (const [platform, data] of Object.entries(summary.platforms)) {
console.log(`\n${platform.toUpperCase()}`);
console.log(` Posts: ${data.posts.toLocaleString()}`);
console.log(` Views: ${data.views.toLocaleString()}`);
console.log(` Engagement: ${data.engagement.toLocaleString()}`);
const engagementRate = data.views > 0
? ((data.engagement / data.views) * 100).toFixed(2)
: 0;
console.log(` Engagement Rate: ${engagementRate}%`);
}
console.log('\n📈 TOTALS');
console.log(` Total Posts: ${summary.totals.posts.toLocaleString()}`);
console.log(` Total Views: ${summary.totals.views.toLocaleString()}`);
console.log(` Total Engagement: ${summary.totals.engagement.toLocaleString()}`);
// Check growth
const tiktokGrowth = await tracker.getGrowth(campaignTag, 'tiktok', 7);
if (tiktokGrowth) {
console.log(`\n🔥 TikTok Growth (7 days): +${tiktokGrowth.views_growth}% views`);
}
}
runCampaignReport();
Pro Tips
1. Track Competitor Hashtags Too
const myHashtags = ['mybrand', 'mybrandlaunch'];
const competitorHashtags = ['competitorbrand', 'competitorname'];
const allHashtags = [...myHashtags, ...competitorHashtags];
2. Set Up Alerts
async function checkAndAlert(threshold = 100) {
const trends = await detector.scanAllTrends();
const hotTrends = trends.filter(t =>
parseFloat(t.view_growth) > threshold
);
if (hotTrends.length > 0) {
// Send alert (Slack, email, etc.)
console.log('🚨 HOT TRENDS DETECTED:', hotTrends);
}
}
3. Export Data for Analysis
function exportToCSV(hashtagName) {
const data = db.prepare(`
SELECT h.name, m.platform, m.post_count, m.view_count,
m.engagement_count, m.recorded_at
FROM hashtag_metrics m
JOIN hashtags h ON m.hashtag_id = h.id
WHERE h.name = ?
ORDER BY m.recorded_at
`).all(hashtagName);
const csv = [
'hashtag,platform,posts,views,engagement,date',
...data.map(r =>
`${r.name},${r.platform},${r.post_count},${r.view_count},${r.engagement_count},${r.recorded_at}`
)
].join('\n');
require('fs').writeFileSync(`${hashtagName}_export.csv`, csv);
}
Conclusion
Tracking hashtags across platforms doesn't have to be complicated. With SociaVault's unified API, you can:
- Monitor hashtag performance on TikTok, Instagram, and Twitter
- Track growth over time
- Detect trending hashtags before they peak
- Generate campaign reports automatically
The key insight: What works on one platform often doesn't translate to others. Cross-platform tracking shows you the full picture.
Want to start tracking hashtags?
Get 50 free API credits at sociavault.com and build your own tracker today.
More tutorials:
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.