Automated TikTok & Instagram Trend Radar Skill
Overview
This skill builds a fully automated trend monitoring pipeline that:
- Scrapes TikTok and Instagram in real-time using Apify
- Sends trend data into Claude (via OpenClaw) for AI analysis
- Automatically generates content ideas, video scripts, and hashtag explosion alerts
- Produces ready-to-publish short videos via InVideo AI
The result: you know what's trending before everyone else — and you already have the content ready.
🔗 Apify: https://www.apify.com/?fpr=dx06p 🔗 InVideo: https://invideo.sjv.io/TBB
What This Skill Does
- Scrape TikTok hashtags, sounds, and viral posts every few hours via Apify
- Scrape Instagram Reels and trending hashtags in parallel
- Detect hashtag explosions — sudden spikes in post volume or engagement
- Send raw trend data to Claude for instant AI-powered analysis
- Auto-generate content ideas, angles, and hooks based on detected trends
- Write complete video scripts tailored to the trending topic
- Produce the video automatically via InVideo AI
- Alert via webhook, Slack, or email when a trend is breaking
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ TREND RADAR PIPELINE │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │
│ │ Apify │───▶│ Trend │───▶│ Claude / OpenClaw │ │
│ │ Scraper │ │ Detector │ │ AI Analysis Engine │ │
│ │TikTok + │ │(spike │ │ │ │
│ │Instagram │ │detection)│ │ • Content ideas │ │
│ └──────────┘ └──────────┘ │ • Script generation │ │
│ │ • Hashtag insights │ │
│ └──────────┬───────────┘ │
│ │ │
│ ┌───────────────────▼────────────┐ │
│ │ InVideo AI │ │
│ │ Auto Video Production │ │
│ │ (script → MP4 in minutes) │ │
│ └───────────────────┬────────────┘ │
│ │ │
│ ┌───────────────────▼────────────┐ │
│ │ ALERTS & OUTPUT │ │
│ │ Slack / Email / Webhook / CMS │ │
│ └────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Step 1 — Get Your API Keys
Apify
- Sign up at https://www.apify.com/?fpr=dx06p
- Go to Settings → Integrations
- Copy your token:
export APIFY_TOKEN=apify_api_xxxxxxxxxxxxxxxx
InVideo
- Sign up at https://invideo.sjv.io/TBB
- Go to Settings → API / Developer Settings
- Copy your key:
export INVIDEO_API_KEY=iv_api_xxxxxxxxxxxxxxxx
OpenClaw / Claude API
- Get your Claude API key from your OpenClaw or Anthropic account
- Store it:
export CLAUDE_API_KEY=sk-ant-xxxxxxxxxxxxxxxx
Step 2 — Install Dependencies
npm install apify-client axios node-cron
Full Pipeline Implementation
Module 1 — Scrape TikTok & Instagram Trends
import ApifyClient from 'apify-client';
const apify = new ApifyClient({ token: process.env.APIFY_TOKEN });
// Define hashtags to monitor
const WATCHED_HASHTAGS = [
"viral", "trending", "fyp", "lifehack",
"productivity", "ai", "money", "fitness"
];
async function scrapeTikTokTrends() {
const run = await apify.actor("apify/tiktok-hashtag-scraper").call({
hashtags: WATCHED_HASHTAGS,
resultsPerPage: 50,
shouldDownloadVideos: false
});
const { items } = await run.dataset().getData();
return items.map(item => ({
platform: "tiktok",
hashtag: item.hashtag,
postCount: item.viewCount,
likes: item.diggCount,
shares: item.shareCount,
comments: item.commentCount,
description: item.text,
author: item.authorMeta?.name,
createdAt: item.createTime,
url: item.webVideoUrl
}));
}
async function scrapeInstagramTrends() {
const run = await apify.actor("apify/instagram-hashtag-scraper").call({
hashtags: WATCHED_HASHTAGS,
resultsLimit: 50
});
const { items } = await run.dataset().getData();
return items.map(item => ({
platform: "instagram",
hashtag: item.hashtags?.[0] || "unknown",
likes: item.likesCount,
comments: item.commentsCount,
description: item.caption,
author: item.ownerUsername,
createdAt: item.timestamp,
url: item.url
}));
}
async function scrapeAllPlatforms() {
const [tiktok, instagram] = await Promise.all([
scrapeTikTokTrends(),
scrapeInstagramTrends()
]);
return [...tiktok, ...instagram];
}
Module 2 — Hashtag Explosion Detector
// In-memory baseline (use a database like Redis for production)
const baseline = {};
function detectExplosions(currentData) {
const alerts = [];
// Group by hashtag and calculate engagement scores
const grouped = currentData.reduce((acc, post) => {
if (!acc[post.hashtag]) acc[post.hashtag] = { posts: 0, totalLikes: 0, platforms: new Set() };
acc[post.hashtag].posts++;
acc[post.hashtag].totalLikes += post.likes || 0;
acc[post.hashtag].platforms.add(post.platform);
return acc;
}, {});
for (const [hashtag, stats] of Object.entries(grouped)) {
const prev = baseline[hashtag] || { posts: 0, totalLikes: 0 };
const growthRate = prev.posts > 0
? ((stats.posts - prev.posts) / prev.posts) * 100
: 100;
// Alert if posts grew more than 40% since last check
if (growthRate > 40) {
alerts.push({
hashtag,
growthRate: Math.round(growthRate),
currentPosts: stats.posts,
previousPosts: prev.posts,
totalLikes: stats.totalLikes,
platforms: [...stats.platforms],
detectedAt: new Date().toISOString(),
severity: growthRate > 100 ? "EXPLOSIVE" : "RISING"
});
}
// Update baseline
baseline[hashtag] = stats;
}
return alerts.sort((a, b) => b.growthRate - a.growthRate);
}
Module 3 — AI Analysis with Claude (OpenClaw)
import axios from 'axios';
async function analyzeWithClaude(trendData, explosionAlerts) {
const prompt = `
You are a viral content strategist. Analyze these trending social media data and provide actionable output.
## TRENDING DATA (last scrape)
${JSON.stringify(trendData.slice(0, 20), null, 2)}
## EXPLOSION ALERTS
${JSON.stringify(explosionAlerts, null, 2)}
Respond ONLY in this exact JSON format, no preamble:
{
"topTrends": [
{
"hashtag": "#example",
"whyItsTrending": "brief explanation",
"targetAudience": "who this appeals to",
"contentAngle": "unique angle to take on this trend"
}
],
"contentIdeas": [
{
"title": "video title idea",
"hashtag": "#hashtag",
"hook": "first 3 seconds script",
"format": "tutorial | reaction | storytime | list | pov",
"estimatedViralPotential": "high | medium | low",
"reasoning": "why this would perform well"
}
],
"urgentAlerts": [
{
"hashtag": "#hashtag",
"message": "alert message",
"recommendedAction": "what to do right now",
"windowOfOpportunity": "estimated hours before trend peaks"
}
],
"bestTimeToPost": "recommendation based on trend timing"
}
`;
const response = await axios.post(
'https://api.anthropic.com/v1/messages',
{
model: "claude-opus-4-5",
max_tokens: 2000,
messages: [{ role: "user", content: prompt }]
},
{
headers: {
'x-api-key': process.env.CLAUDE_API_KEY,
'anthropic-version': '2023-06-01',
'Content-Type': 'application/json'
}
}
);
const raw = response.data.content[0].text;
const clean = raw.replace(/```json|```/g, '').trim();
return JSON.parse(clean);
}
Module 4 — Auto Script Generation
async function generateVideoScript(contentIdea, trendContext) {
const prompt = `
Write a complete short-form video script for this content idea.
CONTENT IDEA: ${JSON.stringify(contentIdea)}
TREND CONTEXT: ${trendContext}
Respond ONLY in this JSON format:
{
"title": "video title",
"duration": "estimated seconds",
"hook": "opening line — first 3 seconds",
"fullScript": "complete word-for-word script",
"captions": ["caption 1", "caption 2", "..."],
"hashtags": ["#tag1", "#tag2", "#tag3"],
"cta": "call to action at the end",
"thumbnailIdea": "description of ideal thumbnail"
}
Rules:
- Hook must create curiosity or shock in under 4 seconds
- Script must be 120–180 words for a 30–45 second video
- Conversational, energetic tone
- End with a strong CTA (follow, comment, share)
`;
const response = await axios.post(
'https://api.anthropic.com/v1/messages',
{
model: "claude-opus-4-5",
max_tokens: 1000,
messages: [{ role: "user", content: prompt }]
},
{
headers: {
'x-api-key': process.env.CLAUDE_API_KEY,
'anthropic-version': '2023-06-01',
'Content-Type': 'application/json'
}
}
);
const raw = response.data.content[0].text;
return JSON.parse(raw.replace(/```json|```/g, '').trim());
}
Module 5 — Auto Video Production with InVideo
const invideo = axios.create({
baseURL: 'https://api.invideo.io/v1',
headers: { Authorization: `Bearer ${process.env.INVIDEO_API_KEY}` }
});
async function produceVideo(script) {
// Start generation
const { data } = await invideo.post('/videos/generate', {
script: script.fullScript,
format: "9:16",
duration: "short",
style: "dynamic",
voiceover: { enabled: true, voice: "en-US-female-1", speed: 1.1 },
captions: { enabled: true, style: "bold-bottom", highlight: true },
music: { enabled: true, mood: "upbeat", volume: 0.25 },
cta: { enabled: true, text: script.cta, position: "bottom" }
});
const videoId = data.videoId;
// Poll until ready
let exportUrl = null;
while (!exportUrl) {
await new Promise(r => setTimeout(r, 6000));
const status = await invideo.get(`/videos/${videoId}/status`);
if (status.data.state === "completed") exportUrl = status.data.exportUrl;
if (status.data.state === "failed") throw new Error("Video generation failed");
console.log(` Video progress: ${status.data.progress}%`);
}
return { videoId, exportUrl, script };
}
Module 6 — Alerts & Notifications
async function sendAlert(alert, analysis) {
const payload = {
text: `🚨 *TREND ALERT: ${alert.hashtag}* — ${alert.severity}`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: `*📈 ${alert.hashtag}* grew *${alert.growthRate}%* in the last check\n` +
`Platforms: ${alert.platforms.join(', ')}\n` +
`Window: ${analysis.urgentAlerts?.[0]?.windowOfOpportunity || 'Act now'}`
}
},
{
type: "section",
text: {
type: "mrkdwn",
text: `*💡 Recommended action:*\n${analysis.urgentAlerts?.[0]?.recommendedAction || 'Create content immediately'}`
}
}
]
};
// Send to Slack webhook
if (process.env.SLACK_WEBHOOK_URL) {
await axios.post(process.env.SLACK_WEBHOOK_URL, payload);
}
// Or send to any custom webhook
if (process.env.ALERT_WEBHOOK_URL) {
await axios.post(process.env.ALERT_WEBHOOK_URL, {
type: "trend_explosion",
alert,
analysis,
timestamp: new Date().toISOString()
});
}
}
Main Orchestrator — Full Pipeline
import cron from 'node-cron';
async function runTrendRadar() {
console.log(`\n🔍 Trend Radar scan started at ${new Date().toISOString()}`);
try {
// 1 — Scrape all platforms
console.log(" [1/5] Scraping TikTok & Instagram...");
const trendData = await scrapeAllPlatforms();
console.log(` ✅ ${trendData.length} posts collected`);
// 2 — Detect explosions
console.log(" [2/5] Detecting explosions...");
const alerts = detectExplosions(trendData);
console.log(` ✅ ${alerts.length} alerts detected`);
// 3 — AI analysis
console.log(" [3/5] Analyzing with Claude...");
const analysis = await analyzeWithClaude(trendData, alerts);
console.log(` ✅ ${analysis.contentIdeas?.length} content ideas generated`);
// 4 — Auto-generate scripts for top 2 ideas
console.log(" [4/5] Generating video scripts...");
const topIdeas = analysis.contentIdeas?.slice(0, 2) || [];
const scripts = await Promise.all(
topIdeas.map(idea => generateVideoScript(idea, JSON.stringify(analysis.topTrends)))
);
console.log(` ✅ ${scripts.length} scripts written`);
// 5 — Produce videos
console.log(" [5/5] Producing videos with InVideo...");
const videos = await Promise.all(scripts.map(produceVideo));
console.log(` ✅ ${videos.length} videos ready`);
// 6 — Send alerts
if (alerts.length > 0) {
await sendAlert(alerts[0], analysis);
console.log(" ✅ Alerts sent");
}
// Final report
return {
scannedAt: new Date().toISOString(),
postsAnalyzed: trendData.length,
explosionAlerts: alerts,
contentIdeas: analysis.contentIdeas,
videos: videos.map(v => ({ title: v.script.title, url: v.exportUrl })),
bestTimeToPost: analysis.bestTimeToPost
};
} catch (err) {
console.error("Radar error:", err.message);
throw err;
}
}
// Schedule: run every 4 hours automatically
cron.schedule('0 */4 * * *', () => {
runTrendRadar().then(report => {
console.log("\n📊 RADAR REPORT:", JSON.stringify(report, null, 2));
});
});
// Also run immediately on startup
runTrendRadar();
Environment Variables
# .env
APIFY_TOKEN=apify_api_xxxxxxxxxxxxxxxx
INVIDEO_API_KEY=iv_api_xxxxxxxxxxxxxxxx
CLAUDE_API_KEY=sk-ant-xxxxxxxxxxxxxxxx
# Optional alerts
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxx
ALERT_WEBHOOK_URL=https://your-app.com/webhooks/trends
Normalized Radar Report Schema
{
"scannedAt": "2025-02-25T10:00:00Z",
"postsAnalyzed": 400,
"explosionAlerts": [
{
"hashtag": "#aitools",
"severity": "EXPLOSIVE",
"growthRate": 187,
"platforms": ["tiktok", "instagram"],
"windowOfOpportunity": "4–8 hours"
}
],
"contentIdeas": [
{
"title": "5 AI tools that replaced my entire team",
"hashtag": "#aitools",
"hook": "I fired my team. Here's what I replaced them with.",
"format": "list",
"estimatedViralPotential": "high"
}
],
"videos": [
{
"title": "5 AI tools that replaced my entire team",
"url": "https://cdn.invideo.io/exports/iv_xxx.mp4"
}
],
"bestTimeToPost": "Post within the next 3 hours while the trend is rising"
}
Best Practices
- Run the radar every 2–4 hours — trends peak fast and fade within 24–48h
- Monitor 8–15 hashtags max per run to stay within Apify free tier
- Always produce content within the rising phase — never wait for the peak
- Use
node-cronfor local scheduling or Apify Schedules for cloud automation - Store baseline data in Redis or a database for accurate spike detection in production
- Pipe the video URLs directly into your social media scheduler (Buffer, Later, etc.)
Requirements
- Apify account → https://www.apify.com/?fpr=dx06p
- InVideo account → https://invideo.sjv.io/TBB
- Claude / OpenClaw API key
- Node.js 18+
- Optional: Slack workspace for real-time alerts
- Optional: Social media scheduler (Buffer, Later) for auto-publishing