DEV Community

Olamide Olaniyan
Olamide Olaniyan

Posted on

Build a Competitor Content Spy That Tracks What's Working

Your competitors post daily. Some content flops. Some goes viral.

What's their secret? What formats work? What hooks grab attention? What posting schedule do they follow?

You could manually check their profiles every day. Or...

In this tutorial, we'll build a Competitor Content Spy that:

  1. Tracks competitor posting patterns and performance
  2. Identifies their top-performing content themes
  3. Reverse-engineers their content strategy

Know exactly what's working for competitors. Then do it better.

Why Competitive Intelligence Matters

Brands that analyze competitors are:

  • 2.5x more likely to outperform their industry
  • 40% faster at identifying trending content formats
  • First to adopt winning strategies

What you can learn:

  • Posting frequency and timing
  • Content pillars that resonate
  • Engagement benchmarks for your niche
  • Hooks and formats that work
  • Hashtag strategies

The Stack

  • Node.js: Runtime
  • SociaVault API: Fetch competitor content
  • OpenAI API: Analyze patterns and extract insights

Step 1: Setup

mkdir competitor-spy
cd competitor-spy
npm init -y
npm install axios openai dotenv
Enter fullscreen mode Exit fullscreen mode

Create .env:

SOCIAVAULT_API_KEY=your_sociavault_key
OPENAI_API_KEY=your_openai_key
Enter fullscreen mode Exit fullscreen mode

Step 2: Track Competitor Accounts

Create index.js:

require('dotenv').config();
const axios = require('axios');
const OpenAI = require('openai');
const fs = require('fs');

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const SOCIAVAULT_BASE = 'https://api.sociavault.com';
const headers = { 'Authorization': `Bearer ${process.env.SOCIAVAULT_API_KEY}` };

async function fetchTikTokCompetitor(handle) {
  console.log(`πŸ“± Fetching TikTok data for @${handle}...`);

  try {
    // Get profile
    const profileRes = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/tiktok/profile`, {
      params: { handle },
      headers
    });

    const profile = profileRes.data.data;

    // Get videos
    const videosRes = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/tiktok/videos`, {
      params: { handle, limit: 50 },
      headers
    });

    const videos = (videosRes.data.data || []).map(video => ({
      id: video.id,
      description: video.desc || video.description,
      views: video.playCount || video.stats?.playCount || 0,
      likes: video.diggCount || video.stats?.diggCount || 0,
      comments: video.commentCount || video.stats?.commentCount || 0,
      shares: video.shareCount || video.stats?.shareCount || 0,
      saves: video.collectCount || video.stats?.collectCount || 0,
      duration: video.duration || video.videoMeta?.duration || 0,
      posted: new Date(video.createTime * 1000),
      music: video.music?.title || 'Original Sound',
      hashtags: extractHashtags(video.desc || ''),
      url: `https://tiktok.com/@${handle}/video/${video.id}`
    }));

    return {
      platform: 'tiktok',
      handle,
      name: profile.nickname || profile.name,
      followers: profile.followerCount || profile.fans || 0,
      following: profile.followingCount || 0,
      totalLikes: profile.heartCount || profile.heart || 0,
      totalVideos: profile.videoCount || videos.length,
      bio: profile.signature || profile.bio,
      verified: profile.verified || false,
      videos
    };
  } catch (error) {
    console.error(`TikTok error for @${handle}:`, error.message);
    return null;
  }
}

async function fetchInstagramCompetitor(handle) {
  console.log(`πŸ“Έ Fetching Instagram data for @${handle}...`);

  try {
    const profileRes = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/instagram/profile`, {
      params: { handle },
      headers
    });

    const profile = profileRes.data.data;

    const postsRes = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/instagram/posts`, {
      params: { handle, limit: 50 },
      headers
    });

    const posts = (postsRes.data.data || []).map(post => ({
      id: post.id || post.pk,
      description: post.caption || '',
      views: post.play_count || post.video_view_count || 0,
      likes: post.like_count || post.likes || 0,
      comments: post.comment_count || post.comments || 0,
      type: post.media_type === 2 ? 'video' : post.media_type === 8 ? 'carousel' : 'image',
      posted: new Date(post.taken_at * 1000),
      hashtags: extractHashtags(post.caption || ''),
      url: `https://instagram.com/p/${post.code || post.shortcode}`
    }));

    return {
      platform: 'instagram',
      handle,
      name: profile.full_name || profile.name,
      followers: profile.follower_count || profile.followers || 0,
      following: profile.following_count || profile.following || 0,
      totalPosts: profile.media_count || posts.length,
      bio: profile.biography || profile.bio,
      verified: profile.is_verified || false,
      category: profile.category_name,
      posts
    };
  } catch (error) {
    console.error(`Instagram error for @${handle}:`, error.message);
    return null;
  }
}

async function fetchTwitterCompetitor(handle) {
  console.log(`🐦 Fetching Twitter data for @${handle}...`);

  try {
    const profileRes = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/twitter/profile`, {
      params: { handle },
      headers
    });

    const profile = profileRes.data.data;

    const tweetsRes = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/twitter/user-tweets`, {
      params: { handle, limit: 50 },
      headers
    });

    const tweets = (tweetsRes.data.data || []).map(tweet => ({
      id: tweet.id || tweet.rest_id,
      text: tweet.full_text || tweet.text,
      views: tweet.views_count || tweet.views || 0,
      likes: tweet.favorite_count || tweet.likes || 0,
      retweets: tweet.retweet_count || 0,
      replies: tweet.reply_count || 0,
      quotes: tweet.quote_count || 0,
      posted: new Date(tweet.created_at),
      hashtags: extractHashtags(tweet.full_text || tweet.text || ''),
      hasMedia: !!(tweet.media || tweet.extended_entities?.media?.length),
      url: `https://twitter.com/${handle}/status/${tweet.id}`
    }));

    return {
      platform: 'twitter',
      handle,
      name: profile.name,
      followers: profile.followers_count || profile.followers || 0,
      following: profile.friends_count || profile.following || 0,
      totalTweets: profile.statuses_count,
      bio: profile.description,
      verified: profile.verified || false,
      tweets
    };
  } catch (error) {
    console.error(`Twitter error for @${handle}:`, error.message);
    return null;
  }
}

function extractHashtags(text) {
  const matches = text.match(/#[\w\u4e00-\u9fa5]+/g) || [];
  return matches.map(tag => tag.toLowerCase());
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Analyze Content Performance

function analyzePerformance(competitor) {
  const content = competitor.videos || competitor.posts || competitor.tweets || [];

  if (content.length === 0) return null;

  // Basic stats
  const totalViews = content.reduce((sum, c) => sum + (c.views || 0), 0);
  const totalLikes = content.reduce((sum, c) => sum + (c.likes || 0), 0);
  const totalComments = content.reduce((sum, c) => sum + (c.comments || 0), 0);

  const avgViews = totalViews / content.length;
  const avgLikes = totalLikes / content.length;
  const avgComments = totalComments / content.length;

  // Engagement rate
  const avgEngagement = competitor.followers > 0 
    ? ((avgLikes + avgComments) / competitor.followers) * 100 
    : 0;

  // Top performers (above average)
  const topContent = content
    .filter(c => (c.views || c.likes) > (avgViews || avgLikes) * 1.5)
    .sort((a, b) => (b.views || b.likes) - (a.views || a.likes))
    .slice(0, 10);

  // Worst performers
  const worstContent = content
    .filter(c => (c.views || c.likes) < (avgViews || avgLikes) * 0.5)
    .slice(0, 5);

  // Posting frequency
  const postingAnalysis = analyzePostingPatterns(content);

  // Hashtag analysis
  const hashtagAnalysis = analyzeHashtags(content);

  // Content type analysis (if available)
  const contentTypes = analyzeContentTypes(content);

  return {
    overview: {
      postsAnalyzed: content.length,
      totalViews,
      totalLikes,
      totalComments,
      avgViews: Math.round(avgViews),
      avgLikes: Math.round(avgLikes),
      avgComments: Math.round(avgComments),
      engagementRate: avgEngagement.toFixed(2)
    },
    topContent,
    worstContent,
    postingPatterns: postingAnalysis,
    hashtags: hashtagAnalysis,
    contentTypes
  };
}

function analyzePostingPatterns(content) {
  const postsByHour = new Array(24).fill(0);
  const postsByDay = new Array(7).fill(0);
  const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

  const engagementByHour = new Array(24).fill(null).map(() => ({ total: 0, count: 0 }));
  const engagementByDay = new Array(7).fill(null).map(() => ({ total: 0, count: 0 }));

  content.forEach(post => {
    const date = new Date(post.posted);
    const hour = date.getHours();
    const day = date.getDay();
    const engagement = (post.likes || 0) + (post.comments || 0);

    postsByHour[hour]++;
    postsByDay[day]++;

    engagementByHour[hour].total += engagement;
    engagementByHour[hour].count++;

    engagementByDay[day].total += engagement;
    engagementByDay[day].count++;
  });

  // Find most common posting times
  const peakHours = postsByHour
    .map((count, hour) => ({ hour, count, avgEngagement: engagementByHour[hour].count > 0 ? engagementByHour[hour].total / engagementByHour[hour].count : 0 }))
    .filter(h => h.count > 0)
    .sort((a, b) => b.count - a.count)
    .slice(0, 3);

  const peakDays = postsByDay
    .map((count, day) => ({ day: dayNames[day], count, avgEngagement: engagementByDay[day].count > 0 ? engagementByDay[day].total / engagementByDay[day].count : 0 }))
    .filter(d => d.count > 0)
    .sort((a, b) => b.count - a.count)
    .slice(0, 3);

  // Calculate posting frequency
  const dates = content.map(c => new Date(c.posted)).sort((a, b) => a - b);
  let avgDaysBetweenPosts = 0;

  if (dates.length > 1) {
    const daysDiff = (dates[dates.length - 1] - dates[0]) / (1000 * 60 * 60 * 24);
    avgDaysBetweenPosts = daysDiff / (dates.length - 1);
  }

  return {
    postsPerWeek: avgDaysBetweenPosts > 0 ? Math.round(7 / avgDaysBetweenPosts * 10) / 10 : 0,
    avgDaysBetweenPosts: Math.round(avgDaysBetweenPosts * 10) / 10,
    peakHours: peakHours.map(h => ({
      time: formatHour(h.hour),
      posts: h.count,
      avgEngagement: Math.round(h.avgEngagement)
    })),
    peakDays: peakDays.map(d => ({
      day: d.day,
      posts: d.count,
      avgEngagement: Math.round(d.avgEngagement)
    }))
  };
}

function analyzeHashtags(content) {
  const hashtagPerformance = {};

  content.forEach(post => {
    const engagement = (post.likes || 0) + (post.comments || 0);

    (post.hashtags || []).forEach(tag => {
      if (!hashtagPerformance[tag]) {
        hashtagPerformance[tag] = { count: 0, totalEngagement: 0 };
      }
      hashtagPerformance[tag].count++;
      hashtagPerformance[tag].totalEngagement += engagement;
    });
  });

  // Most used hashtags
  const mostUsed = Object.entries(hashtagPerformance)
    .map(([tag, data]) => ({
      tag,
      uses: data.count,
      avgEngagement: Math.round(data.totalEngagement / data.count)
    }))
    .sort((a, b) => b.uses - a.uses)
    .slice(0, 10);

  // Best performing hashtags
  const bestPerforming = Object.entries(hashtagPerformance)
    .filter(([_, data]) => data.count >= 2) // Need at least 2 uses
    .map(([tag, data]) => ({
      tag,
      uses: data.count,
      avgEngagement: Math.round(data.totalEngagement / data.count)
    }))
    .sort((a, b) => b.avgEngagement - a.avgEngagement)
    .slice(0, 10);

  return {
    uniqueHashtags: Object.keys(hashtagPerformance).length,
    avgHashtagsPerPost: content.length > 0 
      ? Math.round((content.reduce((sum, c) => sum + (c.hashtags?.length || 0), 0) / content.length) * 10) / 10
      : 0,
    mostUsed,
    bestPerforming
  };
}

function analyzeContentTypes(content) {
  const types = {};

  content.forEach(post => {
    const type = post.type || (post.duration > 60 ? 'long-form' : 'short-form');

    if (!types[type]) {
      types[type] = { count: 0, totalEngagement: 0, totalViews: 0 };
    }

    types[type].count++;
    types[type].totalEngagement += (post.likes || 0) + (post.comments || 0);
    types[type].totalViews += post.views || 0;
  });

  return Object.entries(types).map(([type, data]) => ({
    type,
    count: data.count,
    percentage: Math.round((data.count / content.length) * 100),
    avgEngagement: Math.round(data.totalEngagement / data.count),
    avgViews: Math.round(data.totalViews / data.count)
  }));
}

function formatHour(hour) {
  if (hour === 0) return '12 AM';
  if (hour === 12) return '12 PM';
  return hour < 12 ? `${hour} AM` : `${hour - 12} PM`;
}
Enter fullscreen mode Exit fullscreen mode

Step 4: AI Content Analysis

async function analyzeContentStrategy(competitor, performance) {
  const topContent = performance.topContent.slice(0, 5);

  const prompt = `Analyze this competitor's content strategy based on their top-performing posts.

COMPETITOR: @${competitor.handle} on ${competitor.platform}
Followers: ${competitor.followers?.toLocaleString()}
Engagement Rate: ${performance.overview.engagementRate}%

TOP PERFORMING POSTS:
${topContent.map((post, i) => `
[${i + 1}] ${post.views?.toLocaleString() || post.likes?.toLocaleString()} ${post.views ? 'views' : 'likes'}
Caption: "${(post.description || post.text || '').substring(0, 300)}"
Hashtags: ${post.hashtags?.join(', ') || 'None'}
`).join('\n')}

POSTING PATTERNS:
- Posts per week: ${performance.postingPatterns.postsPerWeek}
- Peak posting times: ${performance.postingPatterns.peakHours.map(h => h.time).join(', ')}
- Peak posting days: ${performance.postingPatterns.peakDays.map(d => d.day).join(', ')}

HASHTAG STRATEGY:
- Avg hashtags per post: ${performance.hashtags.avgHashtagsPerPost}
- Top hashtags: ${performance.hashtags.mostUsed.slice(0, 5).map(h => h.tag).join(', ')}

Analyze and provide:
1. CONTENT PILLARS: What 3-5 themes/topics do they focus on?
2. HOOK PATTERNS: What hooks or opening techniques do their viral posts use?
3. FORMAT PATTERNS: What content formats work best for them?
4. ENGAGEMENT TACTICS: How do they drive engagement?
5. GAPS/WEAKNESSES: What opportunities are they missing?
6. KEY TAKEAWAYS: 5 actionable insights to apply to your own strategy

Return as JSON with keys: pillars, hooks, formats, engagement_tactics, gaps, takeaways`;

  try {
    const response = await openai.chat.completions.create({
      model: 'gpt-4o-mini',
      messages: [{ role: 'user', content: prompt }],
      response_format: { type: 'json_object' }
    });

    return JSON.parse(response.choices[0].message.content);
  } catch (error) {
    console.error('AI analysis error:', error.message);
    return null;
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Generate Competitive Report

function displayReport(competitor, performance, aiAnalysis) {
  console.log('\n═══════════════════════════════════════════════════════════════════');
  console.log(`πŸ•΅οΈ COMPETITOR INTELLIGENCE REPORT: @${competitor.handle}`);
  console.log('═══════════════════════════════════════════════════════════════════\n');

  // Profile overview
  console.log('πŸ‘€ PROFILE OVERVIEW');
  console.log('───────────────────────────────────────────────────────────────────');
  console.log(`Platform: ${competitor.platform.toUpperCase()}`);
  console.log(`Name: ${competitor.name}`);
  console.log(`Followers: ${competitor.followers?.toLocaleString()}`);
  console.log(`Bio: ${competitor.bio?.substring(0, 100)}...`);
  console.log(`Verified: ${competitor.verified ? 'βœ“ Yes' : 'No'}\n`);

  // Performance metrics
  console.log('πŸ“Š PERFORMANCE METRICS');
  console.log('───────────────────────────────────────────────────────────────────');
  console.log(`Posts Analyzed: ${performance.overview.postsAnalyzed}`);
  console.log(`Average Views: ${performance.overview.avgViews?.toLocaleString() || 'N/A'}`);
  console.log(`Average Likes: ${performance.overview.avgLikes?.toLocaleString()}`);
  console.log(`Average Comments: ${performance.overview.avgComments?.toLocaleString()}`);
  console.log(`Engagement Rate: ${performance.overview.engagementRate}%\n`);

  // Posting patterns
  console.log('πŸ“… POSTING SCHEDULE');
  console.log('───────────────────────────────────────────────────────────────────');
  console.log(`Posts per week: ~${performance.postingPatterns.postsPerWeek}`);
  console.log(`Avg days between posts: ${performance.postingPatterns.avgDaysBetweenPosts}`);
  console.log('\nPeak posting times:');
  performance.postingPatterns.peakHours.forEach(h => {
    console.log(`  β€’ ${h.time} (${h.posts} posts, ${h.avgEngagement.toLocaleString()} avg engagement)`);
  });
  console.log('\nPeak posting days:');
  performance.postingPatterns.peakDays.forEach(d => {
    console.log(`  β€’ ${d.day} (${d.posts} posts, ${d.avgEngagement.toLocaleString()} avg engagement)`);
  });
  console.log('');

  // Top content
  console.log('πŸ† TOP PERFORMING CONTENT');
  console.log('───────────────────────────────────────────────────────────────────');
  performance.topContent.slice(0, 5).forEach((post, i) => {
    const metric = post.views ? `${post.views.toLocaleString()} views` : `${post.likes.toLocaleString()} likes`;
    console.log(`\n${i + 1}. ${metric}`);
    console.log(`   "${(post.description || post.text || '').substring(0, 100)}..."`);
    console.log(`   URL: ${post.url}`);
  });
  console.log('');

  // Hashtag analysis
  console.log('\n#️⃣ HASHTAG STRATEGY');
  console.log('───────────────────────────────────────────────────────────────────');
  console.log(`Unique hashtags used: ${performance.hashtags.uniqueHashtags}`);
  console.log(`Avg hashtags per post: ${performance.hashtags.avgHashtagsPerPost}`);
  console.log('\nMost used hashtags:');
  performance.hashtags.mostUsed.slice(0, 5).forEach(h => {
    console.log(`  ${h.tag} (${h.uses} uses)`);
  });
  console.log('\nBest performing hashtags:');
  performance.hashtags.bestPerforming.slice(0, 5).forEach(h => {
    console.log(`  ${h.tag} (${h.avgEngagement.toLocaleString()} avg engagement)`);
  });

  // AI Analysis
  if (aiAnalysis) {
    console.log('\n\nπŸ€– AI STRATEGY ANALYSIS');
    console.log('═══════════════════════════════════════════════════════════════════');

    console.log('\nπŸ“Œ CONTENT PILLARS');
    console.log('───────────────────────────────────────────────────────────────────');
    aiAnalysis.pillars?.forEach((pillar, i) => {
      console.log(`${i + 1}. ${pillar}`);
    });

    console.log('\n🎣 HOOK PATTERNS');
    console.log('───────────────────────────────────────────────────────────────────');
    aiAnalysis.hooks?.forEach((hook, i) => {
      console.log(`${i + 1}. ${hook}`);
    });

    console.log('\nπŸ“ FORMAT PATTERNS');
    console.log('───────────────────────────────────────────────────────────────────');
    aiAnalysis.formats?.forEach((format, i) => {
      console.log(`${i + 1}. ${format}`);
    });

    console.log('\n🎯 ENGAGEMENT TACTICS');
    console.log('───────────────────────────────────────────────────────────────────');
    aiAnalysis.engagement_tactics?.forEach((tactic, i) => {
      console.log(`${i + 1}. ${tactic}`);
    });

    console.log('\n⚠️ GAPS & OPPORTUNITIES');
    console.log('───────────────────────────────────────────────────────────────────');
    aiAnalysis.gaps?.forEach((gap, i) => {
      console.log(`${i + 1}. ${gap}`);
    });

    console.log('\nπŸ’‘ KEY TAKEAWAYS');
    console.log('───────────────────────────────────────────────────────────────────');
    aiAnalysis.takeaways?.forEach((takeaway, i) => {
      console.log(`${i + 1}. ${takeaway}`);
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Run It

async function spyOnCompetitor(handle, platform = 'tiktok') {
  console.log(`\nπŸ•΅οΈ Starting competitive analysis for @${handle}...\n`);

  // Fetch competitor data
  let competitor;
  switch (platform) {
    case 'tiktok':
      competitor = await fetchTikTokCompetitor(handle);
      break;
    case 'instagram':
      competitor = await fetchInstagramCompetitor(handle);
      break;
    case 'twitter':
      competitor = await fetchTwitterCompetitor(handle);
      break;
    default:
      console.log('Unsupported platform');
      return;
  }

  if (!competitor) {
    console.log('Could not fetch competitor data.');
    return;
  }

  console.log(`βœ… Fetched ${(competitor.videos || competitor.posts || competitor.tweets || []).length} posts\n`);

  // Analyze performance
  console.log('πŸ“Š Analyzing performance metrics...\n');
  const performance = analyzePerformance(competitor);

  // AI analysis
  console.log('πŸ€– Running AI analysis...\n');
  const aiAnalysis = await analyzeContentStrategy(competitor, performance);

  // Display report
  displayReport(competitor, performance, aiAnalysis);

  // Save report
  const report = {
    timestamp: new Date().toISOString(),
    competitor,
    performance,
    aiAnalysis
  };

  fs.writeFileSync(
    `report_${handle}_${Date.now()}.json`,
    JSON.stringify(report, null, 2)
  );

  console.log(`\nπŸ“ Full report saved to report_${handle}_${Date.now()}.json`);

  return report;
}

// Compare multiple competitors
async function compareCompetitors(handles, platform = 'tiktok') {
  console.log('\n═══════════════════════════════════════════════════════════════════');
  console.log('πŸ† COMPETITIVE COMPARISON');
  console.log('═══════════════════════════════════════════════════════════════════\n');

  const reports = [];

  for (const handle of handles) {
    const report = await spyOnCompetitor(handle, platform);
    if (report) reports.push(report);
    await new Promise(r => setTimeout(r, 1000)); // Rate limiting
  }

  // Comparison table
  console.log('\nπŸ“Š SIDE-BY-SIDE COMPARISON');
  console.log('═══════════════════════════════════════════════════════════════════\n');

  console.log('| Metric | ' + handles.map(h => `@${h}`).join(' | ') + ' |');
  console.log('|--------|' + handles.map(() => '------').join('|') + '|');

  const metrics = [
    { key: 'followers', label: 'Followers' },
    { key: 'engagementRate', label: 'Eng. Rate' },
    { key: 'avgViews', label: 'Avg Views' },
    { key: 'postsPerWeek', label: 'Posts/Week' }
  ];

  metrics.forEach(metric => {
    const values = reports.map(r => {
      if (metric.key === 'followers') return r.competitor.followers?.toLocaleString();
      if (metric.key === 'engagementRate') return r.performance.overview.engagementRate + '%';
      if (metric.key === 'avgViews') return r.performance.overview.avgViews?.toLocaleString() || 'N/A';
      if (metric.key === 'postsPerWeek') return r.performance.postingPatterns.postsPerWeek;
      return 'N/A';
    });

    console.log(`| ${metric.label} | ${values.join(' | ')} |`);
  });

  return reports;
}

// Main
const handle = process.argv[2] || 'competitor_handle';
const platform = process.argv[3] || 'tiktok';

spyOnCompetitor(handle, platform);
Enter fullscreen mode Exit fullscreen mode

Run with:

node index.js khaby.lame tiktok
node index.js garyvee instagram
node index.js elonmusk twitter
Enter fullscreen mode Exit fullscreen mode

Sample Output

πŸ•΅οΈ Starting competitive analysis for @khaby.lame...

πŸ“± Fetching TikTok data for @khaby.lame...
βœ… Fetched 50 posts

πŸ“Š Analyzing performance metrics...
πŸ€– Running AI analysis...

═══════════════════════════════════════════════════════════════════
πŸ•΅οΈ COMPETITOR INTELLIGENCE REPORT: @khaby.lame
═══════════════════════════════════════════════════════════════════

πŸ‘€ PROFILE OVERVIEW
───────────────────────────────────────────────────────────────────
Platform: TIKTOK
Name: Khabane lame
Followers: 162,400,000
Verified: βœ“ Yes

πŸ“Š PERFORMANCE METRICS
───────────────────────────────────────────────────────────────────
Posts Analyzed: 50
Average Views: 89,450,000
Average Likes: 8,230,000
Average Comments: 45,600
Engagement Rate: 5.1%

πŸ“… POSTING SCHEDULE
───────────────────────────────────────────────────────────────────
Posts per week: ~3.2
Avg days between posts: 2.2

Peak posting times:
  β€’ 6 PM (12 posts, 95M avg engagement)
  β€’ 3 PM (8 posts, 78M avg engagement)

Peak posting days:
  β€’ Thursday (14 posts, 92M avg engagement)
  β€’ Saturday (11 posts, 88M avg engagement)

πŸ€– AI STRATEGY ANALYSIS
═══════════════════════════════════════════════════════════════════

πŸ“Œ CONTENT PILLARS
───────────────────────────────────────────────────────────────────
1. Life hack debunking - showing simpler solutions
2. Silent comedy with exaggerated reactions
3. POV scenarios with relatable situations
4. Collaboration content with other creators

🎣 HOOK PATTERNS
───────────────────────────────────────────────────────────────────
1. Shows ridiculous "hack" video first to set up the joke
2. Uses split-screen format for immediate comparison
3. No words - relies entirely on visual storytelling
4. Signature hand gesture creates instant recognition

πŸ“ FORMAT PATTERNS
───────────────────────────────────────────────────────────────────
1. Under 30 seconds - average 15 seconds
2. Split-screen duet format
3. Simple setup β†’ punchline structure
4. End on signature gesture

⚠️ GAPS & OPPORTUNITIES
───────────────────────────────────────────────────────────────────
1. No educational content - opportunity for "why this works" explanations
2. Limited text/caption engagement - could add story context
3. No carousel/photo content mixed in

πŸ’‘ KEY TAKEAWAYS
───────────────────────────────────────────────────────────────────
1. Simplicity wins - no talking, no complex editing
2. Consistent format creates brand recognition
3. React to trending content rather than creating from scratch
4. Post 3-4 times per week, not daily
5. Evening posting (5-7 PM) drives highest engagement
Enter fullscreen mode Exit fullscreen mode

What You Just Built

Competitive intelligence tools are expensive:

  • Sprout Social: $249+/month
  • Rival IQ: $239+/month
  • Socialbakers: $200+/month

Your version provides deep insights for cents per analysis.

Get Started

  1. Get your SociaVault API Key
  2. Run it on your top 3 competitors
  3. Apply their winning strategies

Know thy competitor. Then outperform them.


Success leaves clues. Find them.

Top comments (0)