WeChat Channels API in Python: videos and comments (2026)
Five endpoints cover it from Python: WeChat Channels video search, video detail, account search, account videos and video comments, each a plain HTTPS GET with an API key and no WeChat login. The worked example below is 6 calls and costs $0.11; a failed call is not charged.
Updated
Does WeChat Channels (视频号) have an official API for other people's videos? No. The Channels section of WeChat's developer docs covers the Channels shop (视频号小店), local-services deals (本地生活) and the 视频号助手 API, and that last one reads your own account's data: its live-stream records, showcase products, lead forms, live dashboards and e-commerce figures. Mini programs can open or embed a Channels video, using IDs or tokens copied by hand from 视频号助手 or the app, and that plays the video rather than returning data. Nothing in the official docs returns another account's videos, their counts or their comments.
So most Python projects for Channels data end up driving a logged-in WeChat session: scan a QR code with a phone, keep the session alive, and accept that the WeChat account doing the reading carries the risk if WeChat objects to the traffic. This guide takes the other route. Each call is an HTTPS GET with an API key in the header. No WeChat account, cookie, QR login or signature code is involved, and the only library you need is requests.
Step by step
Set your key once in the shell: export OKDATA_API_KEY=okd_.... Every endpoint answers with the same envelope: code is "ok" on success, list endpoints put results in data.items with a page for the next cursor, and single-object endpoints put the result in data.item.
Step 1: search videos by keyword
WeChat Channels video search takes query, an optional sort (relevance by default, latest or popular) and an optional published_within (day, week or half_year). One call returns up to about 10 videos for $0.02: description, time posted, account name and avatar, likes and a cover image. The id of each hit is an encrypted export/… ID that expires, so resolve the ones you want in the same run.
curl -G "https://api.okdata.online/v1/wechat_channels/videos/search" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query=露营装备' --data-urlencode 'sort=popular' --data-urlencode 'published_within=week'
Step 2: resolve a video
WeChat Channels video detail accepts the numeric video ID, a search result's export/… ID, or a share link as url. For $0.02 it returns the numeric id, the account ID in author.id, metrics.likes, metrics.comments, metrics.shares, metrics.favorites and, with view=full, the location and length under ext.
curl -G "https://api.okdata.online/v1/wechat_channels/videos/get" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'url=https://weixin.qq.com/sph/AqR7tLm2Kd'
Step 3: find an account by name
WeChat Channels account search takes the account name as query and, through WeChat Search, usually returns the single best match for $0.02. Its id is the account ID, v2_…@finder. The sph… ID that the app displays is a different thing and the endpoints do not take it.
curl -G "https://api.okdata.online/v1/wechat_channels/users/search" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query=三联生活周刊'
Step 4: list the account's videos
WeChat Channels account videos takes the v2_…@finder ID as id and returns videos newest first, about 15 a page, for $0.02 per page, each with likes, comments, shares and saves. A video's url is its encrypted file (the key is ext.decode_key with view=full), since Channels videos have no web page.
curl -G "https://api.okdata.online/v1/wechat_channels/users/videos/list" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'id=v2_060000231003b20faec8c353a18ebca650858991e19fab55aa5e12f6d5010f5e0eeaaafc3520@finder'
Step 5: read the comments
WeChat Channels video comments takes the numeric video ID (not the export/… one) and returns about 25 top-level comments a page, hottest first, for $0.015: text, author.name, likes, replies, published_at and ip_location. Page with cursor set to the last page.next_cursor.
curl -G "https://api.okdata.online/v1/wechat_channels/videos/comments/list" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'id=14987320651142873906'
Step 6: the whole thing in Python
The script wraps every call in one function that checks body["code"], skips deleted items, and retries rate limits and busy upstreams with the same Idempotency-Key, so a retry is never charged twice. Paging goes through one generator with a page cap. The results land in channels.json.
import json
import os
import time
import uuid
import requests
API = "https://api.okdata.online"
KEY = os.environ["OKDATA_API_KEY"]
COMMENT_PAGES = 2 # each page is one call
VIDEO_PAGES = 1 # each page is one call, about 15 videos
class NotFound(Exception):
pass
def call(path, **params):
headers = {"Authorization": f"Bearer {KEY}", "Idempotency-Key": str(uuid.uuid4())}
for attempt in range(4):
body = requests.get(API + path, headers=headers, params=params, timeout=60).json()
if body["code"] == "ok":
return body
if body["code"] == "not_found":
raise NotFound(body["message"]) # deleted or private: not charged
if body.get("retry") in ("yes", "same_key"):
time.sleep(body.get("retry_after_seconds") or 2 ** attempt)
continue
raise RuntimeError(f"{body['code']}: {body['message']} (request {body['request_id']})")
raise RuntimeError(f"{path}: still failing after 4 tries")
def paged(path, max_pages, **params):
cursor = None
for _ in range(max_pages):
body = call(path, **params, **({"cursor": cursor} if cursor else {}))
yield from body["data"]["items"]
if not body["data"]["items"] or not body["page"]["has_more"]:
return
cursor = body["page"]["next_cursor"]
def keyword_report(query):
hits = call("/v1/wechat_channels/videos/search", query=query, sort="popular",
published_within="week")["data"]["items"]
if not hits:
return None
video = call("/v1/wechat_channels/videos/get", id=hits[0]["id"])["data"]["item"]
comments = list(paged("/v1/wechat_channels/videos/comments/list", COMMENT_PAGES, id=video["id"]))
return {"hits": hits, "video": video, "comments": comments}
def account_report(name):
found = call("/v1/wechat_channels/users/search", query=name)["data"]["items"]
if not found:
return None
account = found[0]
videos = list(paged("/v1/wechat_channels/users/videos/list", VIDEO_PAGES, id=account["id"]))
return {"account": account, "videos": videos}
if __name__ == "__main__":
report = {}
try:
report["keyword"] = keyword_report("露营装备")
except NotFound:
report["keyword"] = None # the top video was deleted between search and detail
report["account"] = account_report("三联生活周刊")
with open("channels.json", "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print("videos found:", len((report["keyword"] or {}).get("hits", [])),
"| comments:", len((report["keyword"] or {}).get("comments", [])),
"| account videos:", len((report["account"] or {}).get("videos", [])))
That run is the worked example: 6 calls. To go deeper, raise the two page caps; ten pages of an account's videos are $0.20.
Good to know
- Which ID goes where. Search gives
export/…IDs that expire. Detail turns them into numeric IDs, which comments and replies need. Accounts arev2_…@findereverywhere. - What is null. Search hits have no comment, share or save counts and no account ID; detail fills them in. Plays (
metrics.views) are never available, because WeChat does not show them. Follower counts are null on accounts that hide them.meta.unavailablenames every null field and why. - Trim the output.
fields=id,text,metrics.likeskeeps only the fields you name, andview=compactreturns fewer fields per object. Neither changes the price. - Replies. The comment threads under a comment come from WeChat Channels comment replies, which takes the comment ID plus the numeric video ID.
- Free cases. Deleted videos and unknown accounts answer
not_foundand cost nothing; so do rate limits, busy upstreams and every other error.
To run the same calls from Claude or another agent instead of Python, connect the MCP server. The quickstart covers getting a key and the trial credit.
What the example costs
One search for 露营装备, the detail of the top video, one account looked up by name with its newest page of videos, and two pages of comments under the top video
| Endpoint | Calls | Price | Subtotal |
|---|---|---|---|
| WeChat Channels video search | 1 | $0.02 | $0.02 |
| WeChat Channels video detail | 1 | $0.02 | $0.02 |
| WeChat Channels account search | 1 | $0.02 | $0.02 |
| WeChat Channels account videos | 1 | $0.02 | $0.02 |
| WeChat Channels video comments | 2 | $0.015 | $0.03 |
| Total | 6 | $0.11 |
Prices in force when this page was built. A failed call costs nothing.
In your AI (MCP)
Connect the MCP server once, then say what you want. The agent finds these endpoints, reads their prices and calls them on your balance.
SayOn WeChat Channels, search 露营装备 from the last week, open the most popular video and give me its counts and two pages of comments. Then find the account 三联生活周刊 and list its newest videos.
What the agent sends to the call tool first
{
"endpoint": "wechat_channels.videos.search",
"params": {
"query": "露营装备推荐"
},
"idempotency_key": "<a new UUID>"
}