For AI

How-to guides

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 are v2_…@finder everywhere.
  • 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.unavailable names every null field and why.
  • Trim the output. fields=id,text,metrics.likes keeps only the fields you name, and view=compact returns 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_found and 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

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>"
}

Set up the MCP server →

Sources

  1. WeChat Open Docs: Channels (视频号) introduction and API indexdevelopers.weixin.qq.com · read
  2. WeChat Open Docs: opening Channels videos from a mini programdevelopers.weixin.qq.com · read

Connect once, then just ask.

Every new key comes with $0.10 to try it. One sentence connects your agent.

Start free
Connect your AI

Paste this into your agent

Read https://okdata.online/agents.md and set up okdata for me; my key is in the OKDATA_API_KEY environment variable.

Claude Code, Cursor, Codex and other agents that can open a link set themselves up from it.

MCP serverhttps://api.okdata.online/mcp