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.
You will build a competitive dashboard that snapshots every competitor's social footprint on a schedule: follower counts, engagement rates, and what they posted this week. Growth spikes and campaign launches then show up in your data instead of in someone else's Slack message.
Cost per run: 8 credits per competitor (4 profiles + 4 post lists, 1 credit each). Tracking 10 competitors daily is 2,400 credits per month.
How do you track a competitor's social media accounts?
Fetch the competitor's profile and latest posts from each platform's standard endpoints in one Promise.all, then store each snapshot and diff it against the previous run to detect growth and new posts. Eight calls cover the four platforms that matter for most consumer brands.
What you need
Eight standard-tier endpoints (1 credit each), all behind one key and one envelope:
| Platform | Profile | Latest posts |
|---|---|---|
| TikTok | GET /v1/tiktok/profile (param: handle) | GET /v1/tiktok/profile/videos (param: handle) |
GET /v1/instagram/profile (param: handle) | GET /v1/instagram/profile/posts (param: handle) | |
| YouTube | GET /v1/youtube/channel (param: handle) | GET /v1/youtube/channel/videos (param: handle) |
| X | GET /v1/twitter/profile (param: handle) | GET /v1/twitter/user/tweets (param: handle) |
When an endpoint supports engagement_rate and the required source inputs are present, read the optional computed?.engagement_rate value. Populated values use the canonical calculation, so cross-platform comparisons need no per-platform math. Keep null when the value is unavailable.
Tracking a B2B competitor? Add GET /v1/linkedin/company (5 credits) and GET /v1/linkedin/company/posts (5 credits). They take different identifiers:
company accepts the company page URL, but company/posts needs the numeric
company_id, which is not in that URL. Resolve it from the company response
first, then cache it. Every LinkedIn content endpoint is advanced tier or
above; the platform has no 1-credit profile or post surface.
The code
// 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" │
// └─────────┴─────────────┴───────────┴─────────────────┴───────────────┴──────────────────────────────┘What to change
competitor: handles differ per platform in reality. Keep a{ tiktok, instagram, youtube, twitter }handle map per competitor instead of one string.- Which platforms: drop a pair to save 2 credits per run, or add the LinkedIn pair to reach 18 credits per competitor (8 + 5 for
company+ 5 forcompany/posts). - Where snapshots go: the script prints a table. Write it to a table keyed by
(handle, date)so Step 3 has something to diff against. - Your alert thresholds: the three deltas in Step 3 are the ones worth watching. Pick the multiples that mean something for your category.
Related
Creator engagement scoring
Rank every competitor with comparable engagement rates.
Brand mention monitoring
Catch what people say about them, not just what they post.
Ad library aggregation
See their paid side across Meta, Google, and LinkedIn.
Computed fields
When engagement_rate is populated and when it is honestly null.
Quickstart
New here? Get a key and make your first request.
