Trends do not stay on one platform anymore.
A topic can start as a TikTok format, turn into a debate on X, become a bunch of YouTube explainers, and then show up as Instagram reels a few days later. If the tool only searches one platform, it is already missing part of the story.
The annoying part is not even the ranking logic. It is all the API plumbing around it:
- different API vendors
- different auth systems
- different pricing models
- different response shapes
- separate dashboards and subscriptions
MintAPI fits this kind of problem well. It gives me one API layer across multiple public data sources, with one shared credit/payment model.
In this article, I am going to sketch a small trend discovery pipeline that searches across:
The input is just a topic:
ai coding tools
The output is a cross-platform set of signals that can be ranked, summarized, or passed into an LLM to generate content ideas.
Architecture
The first version should be boring on purpose:
User query
|
v
Trend collector
|
+--> X/Twitter search
+--> YouTube search
+--> TikTok search
+--> Instagram search
|
v
Normalize results
|
v
Rank repeated signals
|
v
Generate content ideas
The key detail is that the app talks to one API base URL:
https://api.mintapi.dev
So the collector does not need separate clients for X, YouTube, TikTok, and Instagram. It just calls several MintAPI endpoints.
Endpoints Used
For the first prototype, these are enough:
| Platform | Endpoint | Docs |
|---|---|---|
| X/Twitter | GET /api/twitter/search |
Twitter search |
| X/Twitter | GET /api/twitter/trends |
Twitter trends |
| YouTube | GET /api/youtube/search |
YouTube search |
| YouTube | GET /api/youtube/transcript |
YouTube transcript |
| TikTok | GET /api/tiktok/search-videos |
TikTok search videos |
GET /api/instagram/global-search-by-keyword |
Instagram global search |
That gets us to a useful first report. After that, comments, transcripts, hashtags, related videos, and profile enrichment are natural additions.
Basic MintAPI Request Helper
For a script or backend job, the simplest setup is a dashboard API key.
MintAPI also supports x402 request payments for agent runtimes. I am keeping this version on the API-key flow because it is the fastest way to test the idea locally.
const MINTAPI_BASE_URL = "https://api.mintapi.dev";
async function mintapiGet(path, params) {
const url = new URL(path, MINTAPI_BASE_URL);
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null) {
url.searchParams.set(key, String(value));
}
}
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.MINTAPI_API_KEY}`,
},
});
if (!response.ok) {
const body = await response.text();
throw new Error(`MintAPI request failed: ${response.status} ${body}`);
}
return response.json();
}
That gives every collector the same tiny request primitive.
Collect X/Twitter Signals
I like starting with X because it is good at showing the language people use around a topic. You see the debates, the complaints, the jokes, and the repeated phrases.
For search, use /api/twitter/search:
async function searchTwitter(query) {
return mintapiGet("/api/twitter/search", {
query,
search_type: "Top",
});
}
For a more general view, /api/twitter/trends can add regional trend signals:
async function getTwitterTrends(country = "UnitedStates") {
return mintapiGet("/api/twitter/trends", {
country,
});
}
Collect YouTube Signals
YouTube gives a different kind of signal. It is less about fast conversation and more about explanations, tutorials, Shorts, and audience comments.
Start with /api/youtube/search:
async function searchYouTube(query) {
return mintapiGet("/api/youtube/search", {
query,
type: "video",
sort_by: "relevance",
upload_date: "week",
});
}
For videos that look promising, fetch transcripts with /api/youtube/transcript:
async function getYouTubeTranscript(videoId) {
return mintapiGet("/api/youtube/transcript", {
id: videoId,
});
}
Transcripts are useful because the LLM can work with the actual content, not just a title and description. That makes summaries and content ideas much less shallow.
Collect TikTok Signals
TikTok is where short-form momentum shows up: formats, sounds, hooks, and fast-moving creator patterns.
Use /api/tiktok/search-videos:
async function searchTikTok(query) {
return mintapiGet("/api/tiktok/search-videos", {
keywords: query,
count: 10,
cursor: 0,
region: "US",
publish_time: 7,
sort_type: 0,
});
}
Depending on the topic, TikTok challenge and music endpoints are worth checking too. Sometimes the trend is not the keyword itself, but the sound or hashtag attached to it.
Collect Instagram Signals
Instagram is useful when the trend has a visual side: reels, hashtags, profile discovery, and media around a topic.
Use /api/instagram/global-search-by-keyword:
async function searchInstagram(query) {
return mintapiGet("/api/instagram/global-search-by-keyword", {
keyword: query,
});
}
From there, the app can branch into hashtag search, media-by-hashtag, or profile lookup depending on what the global search returns.
Run All Collectors Together
Each platform request is independent, so there is no reason to run them one by one.
This is a good place for Promise.allSettled instead of Promise.all. If TikTok fails or Instagram rate-limits, a partial report from the other sources is still useful.
async function collectTrendSignals(query) {
const [twitter, youtube, tiktok, instagram] = await Promise.allSettled([
searchTwitter(query),
searchYouTube(query),
searchTikTok(query),
searchInstagram(query),
]);
return {
query,
sources: {
twitter: twitter.status === "fulfilled" ? twitter.value : null,
youtube: youtube.status === "fulfilled" ? youtube.value : null,
tiktok: tiktok.status === "fulfilled" ? tiktok.value : null,
instagram: instagram.status === "fulfilled" ? instagram.value : null,
},
errors: [twitter, youtube, tiktok, instagram]
.filter((result) => result.status === "rejected")
.map((result) => result.reason.message),
};
}
Now we have data from several platforms, but it is still platform-shaped.
Before ranking anything, I want one internal shape.
Normalize Platform Results
Every API has its own response structure. I do not try to hide that too early.
The trick is to isolate the messy parts in adapters and keep the rest of the app working with a small TrendSignal shape:
function normalizeSignal({
platform,
title,
text,
author,
url,
engagement,
publishedAt,
}) {
return {
platform,
title: title ?? "",
text: text ?? "",
author: author ?? "",
url: url ?? "",
engagement: Number(engagement ?? 0),
publishedAt: publishedAt ?? null,
};
}
Then I can create one adapter per platform:
function normalizeTwitter(raw) {
if (!raw) return [];
// Adapt this to the exact response fields you use from the endpoint.
const items = raw.items ?? raw.data ?? raw.results ?? [];
return items.map((item) =>
normalizeSignal({
platform: "twitter",
title: item.text,
text: item.text,
author: item.user?.screen_name ?? item.author?.username,
url: item.url,
engagement:
Number(item.favorite_count ?? 0) + Number(item.retweet_count ?? 0),
publishedAt: item.created_at,
}),
);
}
function normalizeYouTube(raw) {
if (!raw) return [];
const items = raw.items ?? raw.data ?? raw.results ?? [];
return items.map((item) =>
normalizeSignal({
platform: "youtube",
title: item.title,
text: item.description,
author: item.channel_title ?? item.channel?.title,
url: item.url,
engagement:
Number(item.view_count ?? 0) +
Number(item.like_count ?? 0) +
Number(item.comment_count ?? 0),
publishedAt: item.published_at,
}),
);
}
function normalizeTikTok(raw) {
if (!raw) return [];
const items = raw.items ?? raw.data ?? raw.videos ?? [];
return items.map((item) =>
normalizeSignal({
platform: "tiktok",
title: item.desc,
text: item.desc,
author: item.author?.unique_id ?? item.author?.nickname,
url: item.url ?? item.share_url,
engagement:
Number(item.statistics?.digg_count ?? 0) +
Number(item.statistics?.comment_count ?? 0) +
Number(item.statistics?.share_count ?? 0),
publishedAt: item.create_time,
}),
);
}
function normalizeInstagram(raw) {
if (!raw) return [];
const items = raw.items ?? raw.data ?? raw.results ?? [];
return items.map((item) =>
normalizeSignal({
platform: "instagram",
title: item.caption?.text ?? item.name,
text: item.caption?.text ?? item.biography,
author: item.user?.username ?? item.username,
url: item.url,
engagement:
Number(item.like_count ?? 0) + Number(item.comment_count ?? 0),
publishedAt: item.taken_at,
}),
);
}
The rest of the app only needs this:
function normalizeAll(raw) {
return [
...normalizeTwitter(raw.sources.twitter),
...normalizeYouTube(raw.sources.youtube),
...normalizeTikTok(raw.sources.tiktok),
...normalizeInstagram(raw.sources.instagram),
];
}
The field names above are intentionally defensive. Public-data APIs often return nested structures, and the exact fields you use depend on what you show in your UI or report. In production, each adapter should be tightened around the fields the product actually relies on.
Rank Trend Signals
A first version does not need a complex ranking model. Start with:
- score text matches against the query
- add a small engagement score
- boost items that appear across multiple platforms
function tokenize(value) {
return value
.toLowerCase()
.split(/[^a-z0-9]+/)
.filter(Boolean);
}
function scoreSignal(signal, queryTerms) {
const text = `${signal.title} ${signal.text}`.toLowerCase();
const keywordScore = queryTerms.filter((term) => text.includes(term)).length;
const engagementScore = Math.log10(signal.engagement + 1);
return keywordScore * 2 + engagementScore;
}
function rankSignals(signals, query) {
const queryTerms = tokenize(query);
return signals
.map((signal) => ({
...signal,
score: scoreSignal(signal, queryTerms),
}))
.sort((a, b) => b.score - a.score);
}
Once that works, clustering is the next obvious upgrade:
- group repeated phrases
- detect shared hashtags
- detect shared creator names
- compare topics that appear on two or more platforms
- weigh recency more heavily for fast-moving topics
Build a CLI Prototype
For a quick test, wrap the whole thing in a CLI:
const query = process.argv.slice(2).join(" ");
if (!query) {
console.error('Usage: node trend-agent.mjs "ai coding tools"');
process.exit(1);
}
const raw = await collectTrendSignals(query);
const signals = normalizeAll(raw);
const ranked = rankSignals(signals, query).slice(0, 25);
console.log(
JSON.stringify(
{
query,
checkedPlatforms: ["twitter", "youtube", "tiktok", "instagram"],
errors: raw.errors,
signals: ranked,
},
null,
2,
),
);
Run it like this:
MINTAPI_API_KEY="YOUR_API_KEY" node trend-agent.mjs "ai coding tools"
The output shape might look like this:
{
"query": "ai coding tools",
"checkedPlatforms": ["twitter", "youtube", "tiktok", "instagram"],
"errors": [],
"signals": [
{
"platform": "youtube",
"title": "I tried 5 AI coding agents",
"text": "A comparison of Cursor, Claude Code, Codex, and other tools...",
"author": "Example Channel",
"url": "https://youtube.com/watch?v=...",
"engagement": 184200,
"publishedAt": "2026-07-01T12:00:00Z",
"score": 8.26
}
]
}
Turning Signals Into Content Ideas
Once the signals are normalized, they are easy to pass into an LLM.
The prompt does not need to know anything about MintAPI or the source APIs. It only needs the structured signals:
function buildContentIdeaPrompt(query, signals) {
return `
You are analyzing cross-platform trend data for: ${query}
Use the signals below to produce:
1. A short trend summary
2. Repeated themes
3. Audience questions
4. Contrarian angles
5. Five content ideas for developers
Signals:
${JSON.stringify(signals, null, 2)}
`;
}
That separation is important. The collector handles APIs. The normalizer handles shape. The ranker handles signal quality. The LLM handles synthesis.
Why One API Layer Matters
The interesting part of this app is not a single API call. It is the fact that one topic can be checked across several platforms without turning the project into vendor-integration work.
Without a unified layer, this project needs separate integrations for X, YouTube, TikTok, and Instagram. Each one comes with its own subscription, auth model, billing, rate limits, and quirks.
With MintAPI, most of the app can stay focused on the product workflow:
- collect cross-platform signals
- normalize them
- rank them
- summarize them
- generate content ideas
That is the main benefit for this kind of project: the API/vendor complexity sits behind one MintAPI layer.
Where x402 Fits
For this article, I used the normal API-key flow because it is the easiest way to prototype a backend job or CLI.
MintAPI also supports x402 for agent runtimes. In that flow, an autonomous agent can call an endpoint, receive a 402 Payment Required response, create an X-PAYMENT header, and retry the request.
That becomes useful when you want an agent to pay per request only when live external context is worth buying.
For agent-focused integrations, see:
Final Thoughts
Trend discovery is naturally cross-platform.
If you only look at X, you miss video behavior. If you only look at YouTube, you miss fast-moving short-form formats. If you only look at TikTok or Instagram, you miss deeper discussion and search intent.
For me, the value of MintAPI in this workflow is that I can build around the question I actually care about:
What is happening around this topic across the internet?
Instead of spending the whole project integrating several social APIs one by one.
Top comments (0)