Xiaohongshu API in Python: notes, profiles and comments (2026)
Xiaohongshu's official open platform is built for shops, not for reading public notes, so this guide calls five okdata endpoints from plain requests: note search, note detail, account profile, account notes and note comments. The worked example is 5 calls and costs $0.10; a failed call is not charged.
Updated
Is there an official Xiaohongshu API for this? Xiaohongshu runs an open platform, but it is the e-commerce open platform: tool apps that a shop authorises (ERP, order printing, listing products, inventory) and apps a shop builds for its own systems. PGY and the ad tools serve advertisers with their own campaigns. None of them offers an endpoint for searching everyone's notes or reading the comments under them; Xiaohongshu's official API options goes through each channel.
Then there is the token. Xiaohongshu's own web API attaches an xsec_token to each note it shows you and checks it when the note is opened, so a script holding only note IDs gets refused. The xsec_token answer explains the mechanism. With the endpoints below you pass IDs or links and never handle a token, a cookie or a signature.
You end with a small Python client: one helper that handles errors and retries, a pager with a page cap, five endpoints and a JSON report.
Step by step
Step 1: set up
Python 3.9 or newer, requests and your key in an environment variable. There is no SDK to install.
pip install requests
export OKDATA_API_KEY=okd_...
Each call is a GET to https://api.okdata.online plus the endpoint path, with the key as a bearer token. A success has "code": "ok" and the data under data (data.items and a page for lists, data.item for single objects). An error has code, message, request_id and a retry hint: yes means try again later, after retry_after_seconds when it is set.
Step 2: search notes
Xiaohongshu note search takes query, sort (general, latest or popular) and type (all, video or image). One call returns about 20 notes for $0.02, each with id, title, the opening of text, author, published_at, hashtags and metrics (likes, favorites, comments, shares).
curl -G "https://api.okdata.online/v1/xiaohongshu/notes/search" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query=防晒霜' \
--data-urlencode 'sort=popular'
Step 3: one note in full
Xiaohongshu note detail takes id (24 hex characters) or url (a note link or an xhslink share link) and returns the full text, every image (a video note gives its cover), hashtags and current counts for $0.02. With view=full, ext.xsec_token carries the token Xiaohongshu attached to the note, handy for building a link a person can open.
curl -G "https://api.okdata.online/v1/xiaohongshu/notes/get" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'url=https://www.xiaohongshu.com/explore/672a4f1d000000001b03c58e'
Step 4: the author's profile
Xiaohongshu account profile takes the user ID as id (the note's author.id) or a profile link as url, for $0.02. It returns followers, following, posts (notes published), likes (likes and saves together, as the profile shows them), bio, verified and username, the Xiaohongshu number. With view=full, ext.ip_location is the region on the profile.
Step 5: the author's notes
Xiaohongshu account notes needs the user ID as id and returns about 20 notes per call, newest first, for $0.02. The author block on these items carries only the ID, since you asked for that account.
Step 6: comments under a note
Xiaohongshu note comments needs the note id and returns about 10 top-level comments per call for $0.02, each with text, author, likes, replies, published_at and ip_location.
curl -G "https://api.okdata.online/v1/xiaohongshu/notes/comments/list" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'id=672a4f1d000000001b03c58e'
Step 7: the whole script
The script runs the worked example and writes xhs_report.json. call reuses one Idempotency-Key across retries of the same request, so a retry after a dropped connection is never charged twice. pages caps how many pages any list may read, which caps the spend too.
import json
import os
import time
import uuid
import requests
API = "https://api.okdata.online"
SESSION = requests.Session()
SESSION.headers["Authorization"] = f"Bearer {os.environ['OKDATA_API_KEY']}"
COMMENT_PAGES = 1 # each page is one call
AUTHOR_PAGES = 1
class ApiError(Exception):
def __init__(self, body):
super().__init__(f"{body['code']}: {body['message']} (request {body['request_id']})")
self.code = body["code"]
def call(path, **params):
key = str(uuid.uuid4()) # same key on every retry: a replay is not charged again
for attempt in range(3):
body = SESSION.get(API + path, params=params, headers={"Idempotency-Key": key}, timeout=60).json()
if body["code"] == "ok":
return body
if body.get("retry") == "yes" and attempt < 2:
time.sleep(body.get("retry_after_seconds") or 5)
continue
raise ApiError(body)
def pages(path, max_pages, **params):
"""Yield items page by page; stop at max_pages or when has_more is false."""
cursor = None
for _ in range(max_pages):
body = call(path, **params, **({"cursor": cursor} if cursor else {}))
yield from body["data"]["items"]
if not body["page"]["has_more"]:
return
cursor = body["page"]["next_cursor"]
found = call("/v1/xiaohongshu/notes/search", query="防晒霜", sort="popular")["data"]["items"]
if not found:
raise SystemExit("no notes for that query")
top = max(found, key=lambda n: n["metrics"]["likes"] or 0)
note = call("/v1/xiaohongshu/notes/get", id=top["id"])["data"]["item"]
author = call("/v1/xiaohongshu/users/get", id=note["author"]["id"])["data"]["item"]
recent = list(pages("/v1/xiaohongshu/users/notes/list", AUTHOR_PAGES, id=author["id"]))
comments = list(pages("/v1/xiaohongshu/notes/comments/list", COMMENT_PAGES, id=note["id"]))
report = {
"note": {"id": note["id"], "title": note["title"], "text": note["text"], "images": note["images"],
"likes": note["metrics"]["likes"], "saves": note["metrics"]["favorites"],
"comments": note["metrics"]["comments"], "published_at": note["published_at"]},
"author": {"id": author["id"], "name": author["name"], "followers": author["followers"],
"notes": author["posts"], "likes_and_saves": author["likes"]},
"recent_notes": [{"id": n["id"], "title": n["title"], "published_at": n["published_at"],
"likes": n["metrics"]["likes"]} for n in recent],
"comments": [{"text": c["text"], "likes": c["likes"], "replies": c["replies"],
"ip_location": c["ip_location"]} for c in comments],
}
with open("xhs_report.json", "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
Scale it by raising the caps and looping over more notes. Twenty notes in full with three comment pages each is $1.60.
Good to know
- No view counts. Xiaohongshu hides views on public notes, so
metrics.viewsis null;meta.unavailablesaysplatform. Saves (favorites) and comments are the signals to rank by. - Two IDs per person. The user ID (24 hex characters) is what the account endpoints take; the Xiaohongshu number in
usernameis what people share. Profile links and share links work asurl. - Deleted or private is free. A note or account that is gone returns
not_foundand is not charged. The script raisesApiErrorwith that code; catch it in batch jobs and move on. - Counts differ. A note's comment count includes replies; the comments endpoint lists top-level comments with each one's reply count.
- Times are UTC. Every
published_atis ISO 8601 in UTC. - Trim what you do not read.
fields=id,title,metrics.likeskeeps only those fields andview=compactreturns fewer fields per object; neither changes the price, both make responses shorter for a model.
For a keyword-wide comment export, the step-by-step Xiaohongshu note comments guide goes from one search to a CSV. For the price of search at volume, see the note search price.
What the example costs
One search for 防晒霜 (sunscreen), the most-liked note in full, its author's profile and latest notes, and the first page of comments under the note
| Endpoint | Calls | Price | Subtotal |
|---|---|---|---|
| Xiaohongshu note search | 1 | $0.02 | $0.02 |
| Xiaohongshu note detail | 1 | $0.02 | $0.02 |
| Xiaohongshu account profile | 1 | $0.02 | $0.02 |
| Xiaohongshu account notes | 1 | $0.02 | $0.02 |
| Xiaohongshu note comments | 1 | $0.02 | $0.02 |
| Total | 5 | $0.10 |
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.
SaySearch Xiaohongshu for 防晒霜 (sunscreen), most popular first, open the most-liked note in full, look up its author's profile and latest notes, and read the first page of comments under the note. Tell me what the comments ask about.
What the agent sends to the call tool first
{
"endpoint": "xiaohongshu.notes.search",
"params": {
"query": "防晒霜 推荐"
},
"idempotency_key": "<a new UUID>"
}