How to export Xiaohongshu comments for a keyword
Two endpoints: Xiaohongshu note search, then Xiaohongshu note comments for each note you keep. The worked example below is 7 calls and costs $0.14; a failed call is not charged.
Updated
The job: you are about to launch a product, or you sell against one, and you want to know what Xiaohongshu users actually say about the category. Notes show what creators want you to think; the comments under them show what readers ask, doubt and compare. So you search a keyword, keep the notes that drew the most discussion, and read their comment sections a page at a time. You end with one CSV: note title, comment text, commenter, likes, reply count, time and the IP region Xiaohongshu shows next to each comment.
No Xiaohongshu account, cookie or xsec_token is involved. Each call is an HTTPS request with your key.
Step by step
Step 1: find the notes worth reading
Call Xiaohongshu note search with query, written the way people type it into the app: 防晒霜, 防晒霜 油皮, 敏感肌 防晒. Two parameters matter here:
sort:general(the default, Xiaohongshu's own mix),latestorpopular. For comment mining,popularsurfaces the notes with the most engagement, which are usually the ones with real discussion.type:all(the default),videoorimage. Leave it atallunless you only care about one format.
One call returns about 20 notes for $0.02. Each has id (24 hex characters), title, the start of the text, author, published_at and metrics with likes, favorites (saves) and comments. Sort on metrics.comments to pick the notes to open.
curl -G "https://api.okdata.online/v1/xiaohongshu/notes/search" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query=防晒霜' \
--data-urlencode 'sort=popular' \
--data-urlencode 'fields=id,title,metrics.comments,metrics.likes,published_at'
fields keeps the response short without changing the price.
Step 2: page through the comments
Pass a note's id to Xiaohongshu note comments. One call returns about 10 top-level comments for $0.02. Each has text, author (name and ID), likes, replies (how many replies sit under it), published_at and ip_location. parent_id is null because these are top-level comments. For the next page, send page.next_cursor back as cursor, unchanged; stop when page.has_more is false.
curl -G "https://api.okdata.online/v1/xiaohongshu/notes/comments/list" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'id=672a4f1d000000001b03c58e'
Comment pages are small on Xiaohongshu, so budget by pages, not by notes: 1,000 comments take about 100 calls.
Step 3: put it together in Python
The script searches once, keeps the 3 notes with the most comments, reads up to MAX_PAGES pages under each and writes one CSV.
import csv
import os
import requests
API = "https://api.okdata.online"
HEADERS = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
NOTES = 3 # notes to open
MAX_PAGES = 2 # comment pages per note; each page is one call
def get(path, **params):
body = requests.get(API + path, headers=HEADERS, params=params, timeout=60).json()
if body["code"] != "ok":
raise RuntimeError(f"{body['code']}: {body['message']} (charged: {body['charged']})")
return body
notes = get("/v1/xiaohongshu/notes/search", query="防晒霜", sort="popular")["data"]["items"]
notes = sorted(notes, key=lambda n: n["metrics"]["comments"] or 0, reverse=True)[:NOTES]
with open("xhs_comments.csv", "w", newline="", encoding="utf-8-sig") as f:
out = csv.writer(f)
out.writerow(["note_id", "note_title", "comment", "user", "likes", "replies", "ip_location", "published_at"])
for n in notes:
cursor = None
for _ in range(MAX_PAGES):
params = {"id": n["id"], **({"cursor": cursor} if cursor else {})}
body = get("/v1/xiaohongshu/notes/comments/list", **params)
for c in body["data"]["items"]:
out.writerow([n["id"], n["title"], c["text"], c["author"]["name"], c["likes"],
c["replies"], c["ip_location"], c["published_at"]])
if not body["page"]["has_more"]:
break
cursor = body["page"]["next_cursor"]
Raise NOTES and MAX_PAGES to go wider and deeper. Ten notes at five pages each is 50 comment calls, $1.00 on top of the search. Per 1,000 comments the bill comes to about $2.00.
Good to know
- Counts will not match the note. The comment count on a note includes replies. This endpoint lists top-level comments and gives each one's reply count in
replies, not the reply text, so you collect fewer rows thanmetrics.comments. - Order. Comments come in Xiaohongshu's default order; there is no sort parameter, and no newest-first option.
- IP region.
ip_locationis the province or country label Xiaohongshu prints next to a comment. It is null when Xiaohongshu shows none. - No token juggling. You pass the note ID only. Why that matters on Xiaohongshu is in the xsec_token answer.
- Deleted notes are free. A note that is gone or private returns
not_foundand costs nothing; skip it. - Retries without paying twice. Send an
Idempotency-Keyheader with each call. The same request with the same key within 24 hours returns the stored answer withmeta.replayed: trueand no new charge.
To export every comment under one note you already have, see how to export a Xiaohongshu note's comments. For turning comments into a list of complaints and questions, see finding pain points in Douyin and Xiaohongshu comments with an LLM.
What the example costs
One page of the most popular notes for 防晒霜 (sunscreen), then two pages of comments under each of the 3 notes with the most comments
| Endpoint | Calls | Price | Subtotal |
|---|---|---|---|
| Xiaohongshu note search | 1 | $0.02 | $0.02 |
| Xiaohongshu note comments | 6 | $0.02 | $0.12 |
| Total | 7 | $0.14 |
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, take the 3 notes with the most comments, read two pages of comments under each and give me one table: note title, comment, likes, replies, IP location, time.
What the agent sends to the call tool first
{
"endpoint": "xiaohongshu.notes.search",
"params": {
"query": "防晒霜 推荐"
},
"idempotency_key": "<a new UUID>"
}