For AI

How-to guides

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.views is null; meta.unavailable says platform. 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 username is what people share. Profile links and share links work as url.
  • Deleted or private is free. A note or account that is gone returns not_found and is not charged. The script raises ApiError with 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_at is ISO 8601 in UTC.
  • Trim what you do not read. fields=id,title,metrics.likes keeps only those fields and view=compact returns 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

EndpointCallsPriceSubtotal
Xiaohongshu note search1$0.02$0.02
Xiaohongshu note detail1$0.02$0.02
Xiaohongshu account profile1$0.02$0.02
Xiaohongshu account notes1$0.02$0.02
Xiaohongshu note comments1$0.02$0.02
Total5$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>"
}

Set up the MCP server →

Sources

  1. 小红书电商开放平台open.xiaohongshu.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