SocialCrawl

Competitor tracking

Snapshot a competitor's follower counts, engagement rates, and latest posts across TikTok, Instagram, YouTube, and X in one parallel sweep — 8 credits per competitor.

Competitor tracking

Build a competitive dashboard that snapshots every competitor's social footprint on a schedule — follower counts, engagement rates, and what they posted this week — so growth spikes and campaign launches show up in your data, not in your boss's Slack message.

How do you track a competitor's social media accounts?

Fetch the competitor's profile and latest posts from each platform's standard endpoints — /v1/tiktok/profile + /v1/tiktok/profile/videos, /v1/instagram/profile + /v1/instagram/profile/posts, /v1/youtube/channel + /v1/youtube/channel/videos, /v1/twitter/profile + /v1/twitter/user/tweets — in one Promise.all. Store each snapshot and diff against the previous run to detect growth and new posts.

The problem

Competitors announce nothing. Their follower spike, their sudden posting streak, the video that's doing 10x their normal numbers — that's the real signal, and it's spread across four platforms with four different APIs, none of which you want to integrate and maintain individually.

The solution

Eight standard-tier endpoints (1 credit each), all behind one key and one envelope:

PlatformProfileLatest posts
TikTokGET /v1/tiktok/profile (param: handle)GET /v1/tiktok/profile/videos (param: handle)
InstagramGET /v1/instagram/profile (param: handle)GET /v1/instagram/profile/posts (param: handle)
YouTubeGET /v1/youtube/channel (param: handle)GET /v1/youtube/channel/videos (param: handle)
XGET /v1/twitter/profile (param: handle)GET /v1/twitter/user/tweets (param: handle)

B2B competitor? Add GET /v1/linkedin/company and GET /v1/linkedin/company/posts (both take the company page url, 1 credit each).

Every profile response carries the same computed.engagement_rate field, so cross-platform comparisons need no per-platform math.

// recipe-competitor-tracking.ts
// Snapshots one competitor across 4 platforms; diff snapshots between runs.
// Run with: SOCIALCRAWL_KEY=sc_... npx tsx recipe-competitor-tracking.ts

const KEY = process.env.SOCIALCRAWL_KEY;
if (!KEY) throw new Error("Set SOCIALCRAWL_KEY");

const BASE = "https://www.socialcrawl.dev/v1";
const competitor = "duolingo"; // same handle on all four platforms here

async function get(path: string, params: Record<string, string>) {
  const url = new URL(`${BASE}/${path}`);
  for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
  const res = await fetch(url, { headers: { "x-api-key": KEY! } });
  return (await res.json()) as {
    success: boolean;
    platform: string;
    data?: {
      author?: { username: string | null; followers: number | null };
      computed?: { engagement_rate: number | null };
      items?: Array<{
        post?: {
          text?: string | null;
          created_at?: string | null;
          engagement?: { views?: number | null; likes?: number | null };
        };
      }>;
    };
  };
}

// ── Step 1: 8 calls in parallel — 4 profiles + 4 post lists ───────────────
const [ttProfile, igProfile, ytProfile, twProfile, ttPosts, igPosts, ytPosts, twPosts] =
  await Promise.all([
    get("tiktok/profile", { handle: competitor }),
    get("instagram/profile", { handle: competitor }),
    get("youtube/channel", { handle: competitor }),
    get("twitter/profile", { handle: competitor }),
    get("tiktok/profile/videos", { handle: competitor }),
    get("instagram/profile/posts", { handle: competitor }),
    get("youtube/channel/videos", { handle: competitor }),
    get("twitter/user/tweets", { handle: competitor }),
  ]);

// ── Step 2: Build today's snapshot ─────────────────────────────────────────
const posts = [ttPosts, igPosts, ytPosts, twPosts];
const snapshot = {
  date: new Date().toISOString().slice(0, 10),
  handle: competitor,
  platforms: [ttProfile, igProfile, ytProfile, twProfile]
    .filter((p) => p.success && p.data)
    .map((p, i) => ({
      platform: p.platform,
      followers: p.data!.author?.followers ?? null,
      engagement_rate: p.data!.computed?.engagement_rate ?? null,
      posts_fetched: posts[i]?.data?.items?.length ?? 0,
      latest_post: posts[i]?.data?.items?.[0]?.post?.text?.slice(0, 80) ?? null,
    })),
};

console.table(snapshot.platforms);

// ── Step 3: Diff against your stored snapshot from the previous run ───────
// Persist `snapshot` to a DB table keyed by (handle, date), then:
//   follower_delta   = today.followers - yesterday.followers
//   new_posts        = posts with created_at > yesterday's run time
//   engagement_jump  = today.engagement_rate / trailing 7-day average
// Alert when any delta crosses your threshold.

What you get back

// console.table(snapshot.platforms):
// ┌─────────┬─────────────┬───────────┬─────────────────┬───────────────┬──────────────────────────────┐
// │ (index) │  platform   │ followers │ engagement_rate │ posts_fetched │         latest_post          │
// ├─────────┼─────────────┼───────────┼─────────────────┼───────────────┼──────────────────────────────┤
// │    0    │ "tiktok"    │  17800000 │     0.1124      │      20       │ "the owl has no chill..."    │
// │    1    │ "instagram" │   4900000 │     0.0381      │      12       │ "new feature drop 🦉"        │
// │    2    │ "youtube"   │   8120000 │     0.0512      │      30       │ "How Duo learned Spanish"    │
// │    3    │ "twitter"   │  16200000 │      null       │      100      │ "spanish or vanish"          │
// └─────────┴─────────────┴───────────┴─────────────────┴───────────────┴──────────────────────────────┘

Credits cost

Cost per run: 8 credits per competitor (4 profiles + 4 post lists × 1 credit). Tracking 10 competitors daily costs 2,400 credits/month. Adding LinkedIn company + posts brings it to 10 credits per competitor.

Take it further

How to Track Competitor Social Media Accounts with an API | Socialcrawl