Does Xiaohongshu (RedNote) have an API? Get notes and comments with Python

Xiaohongshu (RedNote) has no self-serve API for notes or comments. Search notes, read one and page through its comments with Python, then save a CSV.

Xiaohongshu (RedNote)Updated

Xiaohongshu (小红书), known outside China as RedNote, is where Chinese consumers review products, restaurants and travel spots. If you want that data in a spreadsheet, a dashboard or an AI agent, the first question is whether there is an API.

Is there an official Xiaohongshu API?

Not for notes or comments. Xiaohongshu's open platform mainly serves merchants and partners. It does not give developers public notes, comments or search results. That leaves two options:

  • Scrape it yourself: accounts, cookies, request signing and proxies to maintain, and they break whenever the app changes.
  • Use a data API: send an HTTPS request with an API key and get JSON back.

This guide takes the second route with Qovia's Xiaohongshu endpoints. You pay only for calls that return data.

What you need

  • Python 3.8 or later and the requests package: pip install requests.
  • A Qovia API key: create one in the console and put it in an environment variable, so it never ends up in your code.
Shell
export QOVIA_KEY="sk-qovia-..."

Step 1: a small helper

Every endpoint is a GET request under https://api.qovia.ai/v1/raw/xiaohongshu/. The key goes in the Authorization header. A successful call answers 200 with the result in data. An empty result (a deleted note, a search with no hits) is also a 200, with data empty or null, and is not charged.

Python
import os
import requests

API = "https://api.qovia.ai/v1/raw/xiaohongshu"
HEADERS = {"Authorization": f"Bearer {os.environ['QOVIA_KEY']}"}


def call(endpoint, **params):
    resp = requests.get(f"{API}/{endpoint}", headers=HEADERS, params=params, timeout=60)
    if not resp.ok:
        # The body says why, e.g. {"error": {"code": "invalid_params", "message": "..."}}
        raise RuntimeError(f"{endpoint}: HTTP {resp.status_code} {resp.text[:300]}")
    return resp.json()["data"] or {}

Note search returns 20 notes a page. You can sort by latest, most_liked, most_commented or most_saved, and filter by note type and publish time. Search in Chinese, the way users write.

Python
page = call("search", keyword="咖啡", sort="most_liked")  # 咖啡 = coffee
for note in page.get("items", []):
    extra = note["extra"]
    print(extra["source_id"], note["metrics"]["likes"], extra["title"])

Each result has the note's ID in extra.source_id, its link in extra.url, and like, comment, save and share counts in metrics. Ask for the next page with page=2, page=3 and so on, and stop when has_more is false.

Step 3: read one note

The note ID is the 24-character string in a note link: xiaohongshu.com/explore/<note ID>. Note detail returns the full text, exact counts, topics, publish time, IP location, images and, for video notes, the video link.

Python
note = call("note", note_id="6a14846d000000000702d0d4")
print(note["extra"]["title"])
print(note["text"][:200])
print(note["metrics"])  # likes, comments, saves, shares

Step 4: page through the comments

Note comments come a page at a time. Pass each page's cursor back to get the next one, and stop when has_more is false. sort="latest" gives newest first. Leave it out for Xiaohongshu's own order, with pinned and popular comments first. max_pages caps how much one run can fetch.

Python
def all_comments(note_id, max_pages=20):
    comments, cursor = [], None
    for _ in range(max_pages):
        params = {"note_id": note_id, "sort": "latest"}
        if cursor:
            params["cursor"] = cursor
        page = call("comments", **params)
        comments += page.get("items", [])
        if not page.get("has_more"):
            break
        cursor = page["cursor"]
    return comments

Each comment has cid, text, likes, reply_count, ip_location, created_at and the author's nickname. The replies under a comment come from comment replies, paged the same way.

Step 5: save a CSV

Write the file as utf-8-sig, so Excel shows the Chinese text correctly when you double-click it.

Python
import csv

rows = all_comments("6a14846d000000000702d0d4")
with open("comments.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["cid", "created_at", "likes", "replies", "ip_location", "nickname", "text"])
    for c in rows:
        writer.writerow([c["cid"], c["created_at"], c["likes"], c["reply_count"], c["ip_location"], c["author"]["nickname"], c["text"]])
print(len(rows), "comments saved")

Costs and limits

  • Each call that returns data is charged once at the endpoint's price (see pricing). Empty results, errors and timeouts are not charged.
  • Every response tells you what the call cost (meta.charged_usd) and your balance after it (meta.balance_usd).
  • If you send too many requests in a minute, the API answers 429 with a Retry-After header. Wait that many seconds and try again.
  • Need help with an error? Branch on error.code; the codes are listed in the API reference.

Next

Endpoints in this guide

More guides

Your agent only knows what you give it

Give it Douyin, Xiaohongshu (RedNote), WeChat and product reviews: structured, per call, nothing charged for failures.