Back to Blog
Tutorial

Track Hashtag Performance Across TikTok, Instagram & Twitter in Real-Time

January 18, 2026
14 min read
S
By SociaVault Team
Hashtag TrackingTikTokInstagramTwitterSocial Media Analytics

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:

PlatformHashtag LifespanPeak SpeedBest For
TikTok2-7 daysVery fastViral challenges, trends
Instagram3-14 daysMediumBrand campaigns, niches
TwitterHours-2 daysInstantNews, 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.