Scenario
Use the Content Explorer to find trending content in your niche — articles with high social shares, referring domains, and estimated traffic. Filter for content published in the last 90 days to catch emerging trends, then create personas representing the audiences engaging with that content and validate content angles through a focus group before investing in production.Architecture
Code
import os, requests, time
from datetime import datetime, timedelta
AH = os.environ["AHREFS_API_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
MB, TOPIC = "https://app.mavera.io/api/v1", "AI content marketing"
AH_H = {"Authorization": f"Bearer {AH}", "Accept": "application/json"}
MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
cutoff = (datetime.utcnow() - timedelta(days=90)).strftime("%Y-%m-%d")
resp = requests.get("https://api.ahrefs.com/v3/content-explorer/search", headers=AH_H, params={
"query": TOPIC, "mode": "title", "limit": 100,
"order_by": "referring_domains:desc",
"select": "title,url,published_at,organic_traffic,referring_domains,facebook_shares",
})
resp.raise_for_status()
articles = resp.json().get("articles", [])
trending = sorted(
[a for a in articles if a.get("published_at", "") >= cutoff
and (a.get("referring_domains", 0) >= 5 or a.get("facebook_shares", 0) >= 50)],
key=lambda a: a.get("referring_domains", 0), reverse=True)
print(f"Found {len(trending)} trending articles for '{TOPIC}'\n")
personas = []
for seg in ["B2B SaaS content manager", "freelance SEO consultant", "VP Marketing"]:
p = requests.post(f"{MB}/personas", headers=MH, json={
"name": f"Reader: {seg}",
"description": f"Searches '{TOPIC}'. Engages with high-share content. Role: {seg}.",
}).json()
personas.append(p["id"])
time.sleep(0.3)
concepts = [f"'{a['title']}' — {a.get('referring_domains', 0)} sites linked"
for a in trending[:5]]
fg = requests.post(f"{MB}/focus-groups", headers=MH, json={
"name": f"Trending: {TOPIC}", "persona_ids": personas,
"questions": [
"Which angle first?\n" + "\n".join(f"{i+1}. {c}" for i, c in enumerate(concepts)),
"What's missing from current coverage of this topic?",
"Would you share this with your team? Why or why not?",
], "responses_per_persona": 2,
}).json()
for _ in range(30):
time.sleep(5)
data = requests.get(f"{MB}/focus-groups/{fg['id']}", headers=MH).json()
if data.get("status") == "completed": break
for r in data.get("responses", [])[:9]:
print(f"[{r.get('persona_id', '?')}] {r.get('answer', '')[:300]}\n")
const AH = process.env.AHREFS_API_TOKEN, MV = process.env.MAVERA_API_KEY;
const MB = "https://app.mavera.io/api/v1", TOPIC = "AI content marketing";
const AH_H = { Authorization: `Bearer ${AH}`, Accept: "application/json" };
const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };
const cutoff = new Date(Date.now() - 90 * 86400000).toISOString().slice(0, 10);
const params = new URLSearchParams({
query: TOPIC, mode: "title", limit: "100", order_by: "referring_domains:desc",
select: "title,url,published_at,organic_traffic,referring_domains,facebook_shares",
});
const resp = await fetch(
`https://api.ahrefs.com/v3/content-explorer/search?${params}`, { headers: AH_H });
const articles = (await resp.json()).articles || [];
const trending = articles
.filter((a) => (a.published_at || "") >= cutoff
&& (a.referring_domains >= 5 || a.facebook_shares >= 50))
.sort((a, b) => b.referring_domains - a.referring_domains);
console.log(`Found ${trending.length} trending articles for '${TOPIC}'\n`);
const segments = ["B2B SaaS content manager", "freelance SEO consultant", "VP Marketing"];
const pids = [];
for (const seg of segments) {
const p = await fetch(`${MB}/personas`, { method: "POST", headers: MH,
body: JSON.stringify({ name: `Reader: ${seg}`,
description: `Searches '${TOPIC}'. High-share content. Role: ${seg}.` }),
}).then((r) => r.json());
pids.push(p.id);
await new Promise((r) => setTimeout(r, 300));
}
const concepts = trending.slice(0, 5).map((a) =>
`'${a.title}' — ${a.referring_domains} sites linked`);
const fg = await fetch(`${MB}/focus-groups`, { method: "POST", headers: MH,
body: JSON.stringify({
name: `Trending: ${TOPIC}`, persona_ids: pids,
questions: ["Which angle first?\n" + concepts.map((c, i) => `${i+1}. ${c}`).join("\n"),
"What's missing from current coverage?", "Would you share this with your team? Why?"],
responses_per_persona: 2,
}),
}).then((r) => r.json());
let data;
for (let i = 0; i < 30; i++) {
await new Promise((r) => setTimeout(r, 5000));
data = await fetch(`${MB}/focus-groups/${fg.id}`, { headers: MH }).then((r) => r.json());
if (data.status === "completed") break;
}
for (const r of (data.responses || []).slice(0, 9))
console.log(`[${r.persona_id}] ${(r.answer || "").slice(0, 300)}\n`);
Example Output
{
"trending_articles_found": 34,
"top_article": {
"title": "How AI Is Replacing Traditional Content Calendars",
"referring_domains": 47, "facebook_shares": 892, "organic_traffic": 3200
},
"focus_group_highlights": [
{ "persona": "B2B SaaS content manager", "preferred_angle": "#2 — AI replacing calendars" },
{ "persona": "VP Marketing", "preferred_angle": "#4 — ROI measurement for AI content" }
]
}
Error Handling
Empty results for niche topics
Empty results for niche topics
Content Explorer indexes broadly but may miss very niche topics. Broaden your query or remove the
mode: title filter to search full text instead.Social share counts lagging
Social share counts lagging
Facebook and Twitter share counts update asynchronously and may lag by 24-48 hours. Use referring domains as the primary engagement signal for recent content.