Answers

What should a social media monitoring job cost per month?

Short answer

A typical brand watch on okdata, 10 keywords checked twice a day with one page each on Weibo, Xiaohongshu, Douyin and X, is 2,400 calls a month and costs $28.80. Adding the Weibo hot search list every hour costs another $1.44. There is no monthly fee: the bill is the number of calls times each endpoint's price.

Picture a consumer brand that wants to know, by lunchtime, what people said overnight about its name, two product lines and seven competitor terms. That is 10 keywords, checked morning and evening, on four platforms. Here is what a month of it costs and which dials change the total.

The base plan

10 keywords × 2 checks a day × 30 days = 600 calls per platform, one page per check.

Platform Endpoint Per call Calls a month Month
Weibo Weibo post search $0.002 600 $1.20
Xiaohongshu Xiaohongshu note search $0.02 600 $12.00
Douyin Douyin video search $0.02 600 $12.00
X X post search $0.006 600 $3.60
Weibo hot search, hourly Weibo hot search $0.002 720 $1.44

A leaner start, five keywords once a day on Weibo and Xiaohongshu only, is {{cost:weibo.posts.search150+xiaohongshu.notes.search150}} a month.

The dials, in order of effect

  1. Platforms. Prices per call differ by platform, so dropping or adding one changes the total more than anything else.
  2. Frequency. Twice a day to hourly multiplies calls by 12. Most brands only need hourly checks during a launch or a crisis.
  3. Pages per check. A quiet keyword fits in one page. A busy one can produce more posts between checks than one page holds, and those are missed unless you page further.
  4. Keywords. Linear: 20 keywords cost twice what 10 do.

Stop paging at what you have seen

import os, requests

URL = "https://api.okdata.online/v1/weibo/posts/search"
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}

def new_posts(keyword, seen_ids, max_pages=3):
    fresh, cursor = [], None
    for _ in range(max_pages):
        params = {"query": keyword, "sort": "latest", **({"cursor": cursor} if cursor else {})}
        body = requests.get(URL, headers=H, params=params, timeout=60).json()
        if body["code"] != "ok":
            raise RuntimeError(f"{body['code']}: {body['message']}")
        items = body["data"]["items"]
        fresh += [p for p in items if p["id"] not in seen_ids]
        if any(p["id"] in seen_ids for p in items) or not body["page"]["has_more"]:
            break                            # reached last check's posts: stop paying
        cursor = body["page"]["next_cursor"]
    return fresh

Compared with the alternatives

Subscription listening tools bundle dashboards, alerts and sentiment, and they are the better buy when nobody on the team will write a script. Self-hosting with open-source scrapers costs little in fees, but a thread on monitoring 1,400 X accounts with twscrape shows how much account and rate-limit juggling that takes. For turning the posts into a weekly read, see word-of-mouth research; current prices are on the pricing page.

Updated