For AI

How-to guides

How to search Xiaohongshu notes and export them to CSV

Two endpoints: Xiaohongshu note search, paged with its cursor, then Xiaohongshu note detail for the notes whose full text and images you need. The worked example below is 8 calls and costs $0.16; a failed call is not charged.

Updated

The job: you want a spreadsheet of what Xiaohongshu shows for a keyword, the notes, who wrote them and how they did, plus the complete text and pictures of the handful that stand out. Content teams use it to brief writers, product teams to see how people describe a category, analysts to track a topic week by week. Search returns note cards; detail returns the whole note. You end with one CSV: every note from the search pages, and for the top five also the full text and every image URL.

No Xiaohongshu account, cookie or xsec_token is involved.

Step by step

Step 1: search, with sort and type

Call Xiaohongshu note search with query the way a person types it: 露营, 露营 装备清单, 新手露营. Two parameters change what you get:

  • sort: general (the default, Xiaohongshu's own ranking), latest (newest first) or popular (most engagement first). latest is the one for tracking a topic over time; popular for "what works".
  • type: all (the default), image for image notes or video for video notes.

One call returns about 20 notes for $0.02. Each card has id, url, type, title, author (name and ID), published_at, hashtags and metrics: likes, favorites (saves), comments and shares. The text on a search card is only the opening of the note, and images usually holds the cover alone.

curl -G "https://api.okdata.online/v1/xiaohongshu/notes/search" \
  -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'query=露营' \
  --data-urlencode 'sort=latest' \
  --data-urlencode 'type=image'

Step 2: page through the results

For the next page, send page.next_cursor back as cursor, unchanged, with the same query, sort and type. Stop when page.has_more is false, or when you have enough: every page is one call. Results drift further from your keyword the deeper you page, so a few pages of a narrow query (露营 装备清单) usually tell you more than many pages of a broad one (露营).

Step 3: fetch full notes for the ones you keep

Xiaohongshu note detail takes id (or a note link or xhslink share link as url) and returns the full note for $0.02: the whole text, every image in images, hashtags, and fresh metrics. A video note gives its cover image, not the video file.

curl -G "https://api.okdata.online/v1/xiaohongshu/notes/get" \
  -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'id=672a4f1d000000001b03c58e'

Fetch detail only for the notes you will read. Search cards already carry the counts, so a table of 60 notes with likes and saves needs no detail calls at all.

Step 4: the script

The script reads three pages of the latest image notes, picks the five with the most saves, fetches them in full and writes one CSV with a row per note.

import csv
import os
import requests

API = "https://api.okdata.online"
HEADERS = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
SEARCH_PAGES = 3  # each page is one call
FULL_NOTES = 5    # notes to fetch in full; each 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, cursor = [], None
for _ in range(SEARCH_PAGES):
    params = {"query": "露营", "sort": "latest", "type": "image", **({"cursor": cursor} if cursor else {})}
    body = get("/v1/xiaohongshu/notes/search", **params)
    notes += body["data"]["items"]
    if not body["page"]["has_more"]:
        break
    cursor = body["page"]["next_cursor"]

notes = list({n["id"]: n for n in notes}.values())  # drop repeats across pages
top = sorted(notes, key=lambda n: n["metrics"]["favorites"] or 0, reverse=True)[:FULL_NOTES]
full = {n["id"]: get("/v1/xiaohongshu/notes/get", id=n["id"])["data"]["item"] for n in top}

with open("xhs_notes.csv", "w", newline="", encoding="utf-8-sig") as f:
    out = csv.writer(f)
    out.writerow(["id", "title", "author", "published_at", "likes", "saves", "comments", "url", "full_text", "images"])
    for n in notes:
        d = full.get(n["id"])
        m = (d or n)["metrics"]
        out.writerow([n["id"], n["title"], n["author"]["name"], n["published_at"], m["likes"], m["favorites"],
                      m["comments"], n["url"], d["text"] if d else "", " ".join(d["images"] or []) if d else ""])

utf-8-sig lets Excel open the file with the Chinese intact. Ten search pages and 20 full notes would be $0.60.

Good to know

  • No view counts. Xiaohongshu does not show views publicly, so metrics.views is null and meta.unavailable gives platform as the reason. Saves (favorites) are the best signal of a note people want to keep.
  • Times are UTC. published_at is ISO 8601 in UTC; add eight hours for Beijing time.
  • Note links. url is the plain xiaohongshu.com/explore/<id> link. Opened in a browser without a token it may not load; the xsec_token answer explains why and what to do.
  • Deleted is free. A note removed between search and detail returns not_found and is not charged.
  • Retries without paying twice. Send an Idempotency-Key header with each call. The same request with the same key within 24 hours returns the stored answer with meta.replayed: true and no new charge.
  • Images are links. Download the ones you need soon after the run; image links can stop working after a while.

For what a search costs at volume, see the Xiaohongshu note search price. To go from these notes to what readers say under them, read the comments with Xiaohongshu note comments.

What the example costs

Three pages of the latest image notes for 露营 (camping), then full text and images of the 5 notes with the most saves

EndpointCallsPriceSubtotal
Xiaohongshu note search3$0.02$0.06
Xiaohongshu note detail5$0.02$0.10
Total8$0.16

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 the latest image notes about 露营 (camping), three pages. Give me a table of every note with title, author, likes, saves, comments and link, and add the full text and image links for the 5 notes with the most saves.

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 →

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