InsightSocial API
Recipes

Brand mention monitoring

Run a daily brand-mention sweep across the search endpoints of six platforms in parallel, drop off-topic rows for free, dedupe against earlier runs and alert on what is new. From 120 credits per sweep.

This recipe is the daily job at the heart of social listening. Once a day it searches six platforms for your brand name, drops rows that turn out to be about something else, skips anything it has seen before, and sends what remains to Slack, email or a dashboard.

Cost per run

At least 120 credits per sweep: six search calls whose price starts at 20 each. All six are metered, so each call holds its ceiling when it starts (840 on TikTok, 680 on Reddit and Threads, 380 on YouTube, 180 on X and Instagram) and is charged what it used. Keep at least 2,940 credits available while a sweep runs. A daily sweep costs at least 3,600 credits a month.

How do you track brand mentions with an API?

Call each platform's keyword search with your brand name, in parallel, limited to the last day. Every post search scores each row's relevance to your query for free, and relevance=filter drops the rows that are not about what you meant, still at no extra cost. You supply the dedupe layer, because "new since the last run" is your state.

What you need

EndpointPlatformDate windowCredits
GET /v1/reddit/searchRedditmax_age_days20–680
GET /v1/tiktok/searchTikTokmax_age_days20–840
GET /v1/youtube/searchYouTubemax_age_days20–380
GET /v1/twitter/search/tweetsXsince: operator in query, or max_age_days20–180
GET /v1/threads/searchThreadsstart_date / end_date20–680
GET /v1/instagram/search/reelsInstagrammax_age_days20–180

All six take query. max_age_days keeps only rows published inside the window. It filters after each page is fetched, so the page is billed as usual, and a day with nothing new returns an empty list.

The code

Python
# brand_mentions.py
# Daily brand-mention sweep with dedupe. Keep `seen` somewhere durable between runs.
# Run with: INSIGHTSOCIAL_API_KEY=isk_live_... python brand_mentions.py
import json
import os
from concurrent.futures import ThreadPoolExecutor
from datetime import date, timedelta
from pathlib import Path

import requests

KEY = os.environ["INSIGHTSOCIAL_API_KEY"]
BASE = "https://api.insightsocial.app/v1"
BRAND = "notion"
MEANING = "Notion, the note-taking and workspace app"  # disambiguates a common word
SEEN_FILE = Path("seen-mentions.json")
YESTERDAY = (date.today() - timedelta(days=1)).isoformat()

SEARCHES = {
    "reddit":    ("reddit/search",          {"max_age_days": 1}),
    "tiktok":    ("tiktok/search",          {"max_age_days": 1}),
    "youtube":   ("youtube/search",         {"max_age_days": 1}),
    "twitter":   ("twitter/search/tweets",  {"max_age_days": 1}),
    "threads":   ("threads/search",         {"start_date": YESTERDAY}),
    "instagram": ("instagram/search/reels", {"max_age_days": 1}),
}

def get(path, **params):
    res = requests.get(f"{BASE}/{path}", params=params,
                       headers={"x-api-key": KEY}, timeout=120)
    return res.json()

def search(platform):
    path, extra = SEARCHES[platform]
    return platform, get(path, query=BRAND, relevance="filter",
                         relevant_to=MEANING, **extra)

# Step 1: six searches in parallel.
with ThreadPoolExecutor(max_workers=6) as pool:
    results = dict(pool.map(search, SEARCHES))

# Step 2: dedupe against earlier runs by post URL.
seen = set(json.loads(SEEN_FILE.read_text())) if SEEN_FILE.exists() else set()
fresh, spent = [], 0
for platform, body in results.items():
    spent += body.get("credits_used", 0)
    if not body["success"]:
        print(f"{platform}: {body['error']['type']}")
        continue
    for item in body["data"].get("items", []):
        post = item.get("post") or {}
        url = post.get("url")
        if url and url not in seen:
            seen.add(url)
            fresh.append((platform, post))
SEEN_FILE.write_text(json.dumps(sorted(seen)))

# Step 3: alert on what is new.
print(f"{len(fresh)} new mentions of {BRAND!r} ({spent} credits)")
for platform, post in fresh:
    print(f"[{platform}] {(post.get('text') or post.get('title') or '')[:120]}")
    print(f"  {post['url']}")
    # Replace print with a Slack webhook, an email or a database insert.

Run it once a day. The one-day window plus the URL set means each mention surfaces once.

Threads takes dates, not max_age_days

/v1/threads/search bounds the period with start_date and end_date (YYYY-MM-DD). The code sets start_date to yesterday's date. On X, you can also put the window in the query itself, for example query=notion since:2026-09-22.

What you get back

Example output
14 new mentions of 'notion' (160 credits)
[reddit] Switched our team wiki from Confluence to Notion, here is what broke
  https://www.reddit.com/r/productivity/comments/...
[youtube] My 2026 Notion setup for university
  https://www.youtube.com/watch?v=...
[twitter] notion's new offline mode finally shipped
  https://x.com/.../status/...
...

The figures are illustrative. With relevance=filter, rows judged off-topic are removed and their ids listed in data.relevance.dropped_ids, so a post about "a notion of fairness" does not reach your alert channel.

What to change

  • BRAND and MEANING. Swap in a competitor, a product or a person. relevant_to matters most when the name is also an ordinary word.
  • The window. Match max_age_days to how often the job runs, so windows neither overlap nor leave gaps.
  • Fewer platforms, lower price. Drop the searches you do not need. Each one removed saves at least 20 credits and lowers the hold.
  • Judge the brand, not just the topic. On the post searches, label=mention&brand=... adds whether each post is about the brand, how it feels toward it and which aspect it discusses. This label is metered and adds credits. Check the price first with dry_run=1, which is never charged.
  • Persist seen properly. A JSON file is fine on one machine. Move it to a database table before you run on more than one worker.

On this page