100 free credits. No credit card required.Start building
Logo
Back to blog

Xiaohongshu API Example: 6 Calls With Real Responses

·22 min read

Xiaohongshu API example in six GET calls and one key. Search RedNote notes, read comments, creators and the hot board, with real responses and credit costs.

Xiaohongshu API Example: 6 Calls With Real Responses

The Xiaohongshu API on SocialCrawl (RedNote, 小红书, also called Little Red Book) is six GET calls and one x-api-key header: search notes, read one note, read its comments, read a creator, list that creator's notes, and read the hot search board. You need no Xiaohongshu account, cookie or VPN.

This Xiaohongshu API tutorial chains the calls from a keyword to a creator, with real responses captured on 2026-10-02 and the credit cost of each call. The six came to 105 credits at small limits. Steps 1 to 5 are plain curl, so you can see your data before writing a single line of Python, and Step 6 joins them in one requests script. Fortune put the platform at about 300 million monthly active users in December 2024.

Two limits shape the chain. Search rows carry a short summary instead of the note, and a creator profile does not carry the creator's notes. Each gets an extra call.

What do you need to call the Xiaohongshu API?

You need:

  • A SocialCrawl API key, sent as the x-api-key header.
  • curl, plus Python 3 with requests (pip install requests) for Step 6.
  • The base URL https://www.socialcrawl.dev.
  • Nothing from Xiaohongshu itself: no account, no cookie, no VPN.

Every example reads the key from an environment variable:

bash
export SOCIALCRAWL_API_KEY="your-key-here"

Calling Xiaohongshu directly, the way a DIY Xiaohongshu scraper does, means building signed request headers (x-s, x-t, x-s-common) on the client. A dev.to write-up from April 2026, by an author affiliated with a hosted-scraper vendor, says the signing function changes roughly monthly. We did not measure that. We compare the hosted options in scraping APIs compared.

Every endpoint costs 5 credits per returned row, so a limit=3 list call that returns three rows costs 15. A note that does not exist is a 404 at 0 credits.

A magnifying glass over a grid of photo-feed tiles with one tile enlarged beside a taller detail panel, a picture of a Xiaohongshu API keyword search returning note rows

Step 1: How do you search Xiaohongshu notes by keyword?

Xiaohongshu is a search-first app. The platform's own H1 2024 search report, as reported by ZDNet Korea on 14 August 2024, says about 70% of users use search and the average user runs about 6 searches a day. So we start with a keyword a K-beauty marketer might track for Xiaohongshu marketing research, 韩国护肤 (Korean skincare). The notes are in Chinese, so search in Chinese.

bash
curl -G "https://www.socialcrawl.dev/v1/xiaohongshu/search" \
  --data-urlencode "query=韩国护肤" --data-urlencode "limit=3" \
  -H "x-api-key: $SOCIALCRAWL_API_KEY"

Trimmed to the first of three rows and the fields used below:

json
{
  "success": true,
  "platform": "xiaohongshu",
  "endpoint": "/v1/xiaohongshu/search",
  "data": {
    "items": [
      {
        "post": {
          "id": "6aa8b63b00000000140138cb",
          "url": "https://www.xiaohongshu.com/explore/6aa8b63b00000000140138cb",
          "content": {
            "text": "姐妹们问我好不好用的那些产品,绝大多数都是广告推广 姐妹们要是买那个,我就拿你们的钱包去瑞幸喝100杯。 美白产品",
            "media_urls": null,
            "duration_seconds": null
          },
          "engagement": { "views": null, "likes": 1194, "comments": 239, "shares": 0, "saves": 753 },
          "published_at": "2026-09-15T03:06:35.000Z",
          "ext": {
            "author_id": "698f2d0f00000000260024f6",
            "title": "韩国Olive Young虽无必买,但确有不踩雷好物",
            "media_type": "image",
            "text_truncated": true
          }
        },
        "computed": { "engagement_rate": null, "language": "zh", "content_category": "other", "estimated_reach": null }
      }
    ]
  },
  "credits_used": 15,
  "cached": false,
  "pagination": { "next_cursor": "sc.eyJ2Ijoy...", "has_more": true, "page_size": 3 }
}

The response uses the same post, engagement and computed shape the SocialCrawl API returns for its other social platforms. The note title reads roughly "Korea's Olive Young has no must-buys, but it does have reliable picks" (our translation). Four details about these rows:

  • Rows hold a short summary of the note. post.ext.text_truncated is true, and the summaries in our call ran 57, 56 and 46 characters. Step 2 fetches the full text.
  • engagement.shares is 0 on all three rows. The same note shows 173 shares in Step 2, so a 0 in search means the number was not supplied. Read shares from the note call.
  • views is null on every row, which leaves computed.engagement_rate and computed.estimated_reach null too. Likes, comments and saves are real.
  • content.media_urls was null on the image note and a single URL string on the two video notes, never a list.

The cursor for the next page sits at pagination.next_cursor (prefixed sc.) and goes back in as the cursor parameter. The body also holds a data.next_cursor, a different, unprefixed value, so use the one under pagination. We did not follow a cursor in this capture.

The other parameters: sort takes relevance, latest, most_liked, most_commented or most_collected; type takes all, image or video; published takes all, day, week or half_year; limit runs from 1 to 20 and defaults to 10. There is no hashtag endpoint, so topic discovery is keyword search.

Step 2: How do you get the full note behind a search row?

Pass the search row's URL to /post. The endpoint accepts the note URL or the bare 24-character note id.

bash
curl "https://www.socialcrawl.dev/v1/xiaohongshu/post?url=https://www.xiaohongshu.com/explore/6aa8b63b00000000140138cb" \
  -H "x-api-key: $SOCIALCRAWL_API_KEY"
json
{
  "success": true,
  "platform": "xiaohongshu",
  "endpoint": "/v1/xiaohongshu/post",
  "data": {
    "post": {
      "id": "6aa8b63b00000000140138cb",
      "content": {
        "text": "姐妹们问我好不好用的那些产品,绝大多数都是广告推广\n\t\n姐妹们要是买那个,我就拿你们的钱包去瑞幸喝100杯。\n\t\n美白产品 -> 韩国皮肤科专家都在电视上良心告白了:... (626 characters in total)",
        "media_urls": ["https://sns-na-i4.xhscdn.com/oss-sg/notes_pre_post/1040g3mo...", "... 10 image URLs in total"],
        "duration_seconds": null
      },
      "engagement": { "views": null, "likes": 1194, "comments": 241, "shares": 173, "saves": 753 },
      "published_at": "2026-09-15T03:06:35.000Z",
      "ext": {
        "author_id": "698f2d0f00000000260024f6",
        "media_type": "image",
        "text_truncated": false,
        "ip_location": "韩国"
      }
    },
    "computed": { "engagement_rate": null, "language": "zh", "content_category": "other", "estimated_reach": null }
  },
  "credits_used": 5,
  "cached": false
}

The listing is trimmed to the fields used here, and the text is cut for space. The API returned all 626 characters. The same note through both calls:

FieldSearch rowNote call
Text length57 characters626 characters
ext.text_truncatedtruefalse
engagement.shares0173
engagement.comments239241
content.media_urlsnull (image note)array of 10 image URLs
author.usernamepopulatednull

The comment count moved by two between the calls, which is ordinary for a live note. author.username (the RedNote id) is null on the note call, so take the creator's id from post.ext.author_id. post.ext.ip_location was a country (韩国, South Korea) here; the province lives on comments in Step 3. On a video note, media_urls is a single URL string on the note call too, so check its type before counting it.

A note that does not exist returns this for a full URL and for a bare id, at no charge:

json
{
  "success": false,
  "error": {
    "type": "RESOURCE_NOT_FOUND",
    "message": "The requested resource was not found on the platform.",
    "status": 404,
    "doc_url": "https://www.socialcrawl.dev/docs/errors#resource-not-found",
    "retryable": false
  },
  "credits_used": 0
}

Step 3: How do you read RedNote comments?

Comments take the same note URL.

bash
curl "https://www.socialcrawl.dev/v1/xiaohongshu/post/comments?url=https://www.xiaohongshu.com/explore/6aa8b63b00000000140138cb&limit=3" \
  -H "x-api-key: $SOCIALCRAWL_API_KEY"

First of three rows, trimmed, with the commenter's details left out:

json
{
  "success": true,
  "platform": "xiaohongshu",
  "endpoint": "/v1/xiaohongshu/post/comments",
  "data": {
    "items": [
      {
        "comment": {
          "parent_id": null,
          "post_id": "6aa8b63b00000000140138cb",
          "text": "宝宝这是我让代购买的产品你帮我看一下有没有踩雷的,趁她现在还没飞往韩国可以去掉",
          "engagement": { "likes": 32, "replies": 25 },
          "published_at": "2026-09-15T10:49:42.000Z",
          "ext": { "ip_location": "安徽" }
        },
        "computed": { "language": "zh" }
      }
    ]
  },
  "credits_used": 15,
  "cached": false,
  "pagination": { "next_cursor": "sc.eyJ2Ijoy...", "has_more": true, "page_size": 3 }
}

This call returns top-level comments only, and parent_id was null on all three rows. engagement.replies is a count, and the reply threads are not on this call. The commenter's IP province is comment.ext.ip_location; our three rows returned 安徽, 山西 and 北京. sort takes relevance (the default), latest or most_liked, and the cursor is pagination.next_cursor again.

Step 4: How do you get a creator's profile and their notes?

To find a creator on Xiaohongshu, use the id from a note's post.ext.author_id, or the profile URL. The profile call returns the numbers you need when vetting Xiaohongshu influencers: followers, following, posts and total likes.

bash
curl "https://www.socialcrawl.dev/v1/xiaohongshu/profile?id=698f2d0f00000000260024f6" \
  -H "x-api-key: $SOCIALCRAWL_API_KEY"

We dropped the RedNote id, bio, avatar and display name below because they describe a private individual, along with a few null fields:

json
{
  "success": true,
  "platform": "xiaohongshu",
  "endpoint": "/v1/xiaohongshu/profile",
  "data": {
    "author": {
      "id": "698f2d0f00000000260024f6",
      "followers": 14034,
      "following": 13,
      "posts_count": 14,
      "likes_count": 48859,
      "url": "https://www.xiaohongshu.com/user/profile/698f2d0f00000000260024f6",
      "ext": { "country": "韩国", "collects_received": 13897 }
    },
    "computed": { "engagement_rate": null, "language": "ko", "content_category": "other", "estimated_reach": null },
    "_warnings": [
      "computed.engagement_rate: author ratio exceeded 1.0 (raw: 3.481474); returned null. A lifetime likes/followers ratio is not a real engagement rate"
    ]
  },
  "credits_used": 5,
  "cached": false
}

There is no notes array anywhere in that response. computed.engagement_rate is null for the reason _warnings gives. Lifetime likes divided by followers came to 3.48, which is not an engagement rate, so the API withholds it.

The notes come from a second call with the same id:

bash
curl "https://www.socialcrawl.dev/v1/xiaohongshu/profile/posts?id=698f2d0f00000000260024f6&limit=3" \
  -H "x-api-key: $SOCIALCRAWL_API_KEY"
Publishedflags.pinnedLikesCommentsSharesSavesSummary length
2026-09-17true4,01357393485100 chars
2026-09-06true32,8074,9303,49510,108100 chars
2026-09-26false280811610198 chars

Pinned notes lead, then newest first, which is why the 26 September row sits last. Every row still has text_truncated: true; these summaries ran 98 to 100 characters, longer than search summaries. views is null again. For the full text of any row, call /post with its URL.

Check has_more before assuming another page exists. This 3-row call returned false with no cursor, while the creator in Step 6 returned true with one. We followed neither, so we make no claim about how creator-note paging behaves.

The id here is the author_user_id. The RedNote id (小红书号) is not a lookup key. Passed as id, this creator's RedNote id came back as a 502 UPSTREAM_ERROR marked retryable, at 0 credits, while the author_user_id returned the profile. A 502 on a profile call can mean the wrong kind of id, not an outage.

A leaderboard of glowing bars with a flame on the tallest one, a picture of the RedNote hot search board of trending topics

Step 5: What is on the Xiaohongshu hot search board?

The Xiaohongshu trending call returns the hot search board, a ranked list of topics with a heat score.

bash
curl "https://www.socialcrawl.dev/v1/xiaohongshu/trending?limit=10" \
  -H "x-api-key: $SOCIALCRAWL_API_KEY"

The first five of ten rows, captured at 16:34 GMT on 1 October 2026, which was just after midnight on 2 October in Beijing (English glosses are ours, not the API's):

ranktitleOur glosshot_value
1用万能旅行拍照姿势美美出片Travel photo poses that work anywhere9475000
2耗时三年拍下古诗词里的中国Three years photographing the China of classical poems9348000
3我拍到了海鸥雨I caught a "seagull rain" on camera9032000
4超日常美食教程速来getAn everyday food tutorial, come and get it8860000
5定格这一刻的日照金山Freezing this moment of sunlit golden peaks8711000

Each item has rank, title and hot_value, and there is no topic field. data.total is 20, the size of the board. The board does not page, and a lower limit returns the top of the same board. At that moment it was travel, food and crafts, with no skincare in the top ten. Feed any title into Step 1 as the query and you have a trend-to-notes pipeline.

The whole 20-topic board would cost 100 credits, which is arithmetic at 5 credits per row, not a measured call.

Step 6: How do you chain the calls in Python, and what does a run cost?

This script chains five of the six calls (search, note, comments, profile, creator notes) and skips the hot board. It counts media_urls by type (a list on image notes, one URL string on video notes), prints the paging fields without following them, and stops with the credits spent so far if a step returns a 404. Python social media crawling covers longer crawls.

python
"""Chain five Xiaohongshu calls: search -> note -> comments -> profile -> creator notes.

Needs: pip install requests, and SOCIALCRAWL_API_KEY in the environment.
Every list row costs 5 credits, so the limits below are the cost dial.
"""
import os
import sys

import requests

BASE = "https://www.socialcrawl.dev/v1/xiaohongshu"
KEYWORD = "防晒"  # sunscreen
SEARCH_LIMIT = 3  # 3 rows x 5 = 15 credits
SMALL_LIMIT = 2   # comments and creator notes, 2 rows x 5 = 10 credits each

key = os.environ.get("SOCIALCRAWL_API_KEY")
if not key:
    sys.exit("Set SOCIALCRAWL_API_KEY first.")

total = 0


def call(path, **params):
    """GET one endpoint. Returns the JSON body, or None on a 404 (0 credits)."""
    global total
    r = requests.get(f"{BASE}/{path}", params=params, headers={"x-api-key": key}, timeout=60)
    if r.status_code == 404:
        body = r.json()
        total += body.get("credits_used", 0)
        print(f"{path}: 404 not found, credits_used={body.get('credits_used')}")
        return None
    r.raise_for_status()
    body = r.json()
    total += body.get("credits_used", 0)
    return body


def need(body, step):
    """Stop the chain cleanly if a step came back empty, reporting what the calls so far cost."""
    if not body:
        sys.exit(f"Stopped at {step}. total credits_used: {total}")
    return body


def page_info(body):
    p = body.get("pagination", {})
    return f"has_more={p.get('has_more')} next_cursor={'yes' if p.get('next_cursor') else 'none'}"


# 1. Search: rows carry a short summary, not the full note.
search = need(call("search", query=KEYWORD, limit=SEARCH_LIMIT), "search")
rows = need(search["data"]["items"], "search (no rows)")
first = rows[0]["post"]
print(f"search: {len(rows)} rows, credits_used={search['credits_used']}, {page_info(search)}")
print(f"  first row: id={first['id']} text_chars={len(first['content']['text'])} "
      f"text_truncated={first['ext']['text_truncated']} views={first['engagement']['views']}")

# 2. The full note, from the first row's URL.
note = need(call("post", url=first["url"]), "note")
post = note["data"]["post"]
author_id = post["ext"]["author_id"]
media = post["content"]["media_urls"]  # a list on image notes, one URL string on video notes
media_count = len(media) if isinstance(media, list) else (1 if media else 0)
print(f"note: credits_used={note['credits_used']} text_chars={len(post['content']['text'])} "
      f"text_truncated={post['ext']['text_truncated']} media_type={post['ext']['media_type']} "
      f"media_urls={type(media).__name__}({media_count}) "
      f"likes={post['engagement']['likes']} shares={post['engagement']['shares']}")

# 3. Top-level comments on that note.
comments = need(call("post/comments", url=first["url"], limit=SMALL_LIMIT), "comments")
print(f"comments: {len(comments['data']['items'])} rows, credits_used={comments['credits_used']}, "
      f"{page_info(comments)}")
for row in comments["data"]["items"]:
    c = row["comment"]
    print(f"  likes={c['engagement']['likes']} replies={c['engagement']['replies']} "
          f"ip_location={c['ext']['ip_location']}")

# 4. The creator, by the author id carried on the note.
profile = need(call("profile", id=author_id), "profile")
a = profile["data"]["author"]
print(f"profile: credits_used={profile['credits_used']} followers={a['followers']} "
      f"posts_count={a['posts_count']} likes_count={a['likes_count']} has_notes_array={'posts' in a}")

# 5. The creator's notes (the profile call does not carry them).
notes = need(call("profile/posts", id=author_id, limit=SMALL_LIMIT), "creator notes")
print(f"creator notes: {len(notes['data']['items'])} rows, credits_used={notes['credits_used']}, "
      f"{page_info(notes)}")
for row in notes["data"]["items"]:
    n = row["post"]
    print(f"  {n['published_at'][:10]} pinned={n['flags']['pinned']} likes={n['engagement']['likes']}")

print(f"total credits_used: {total}")

We ran it once against production on 2026-10-02 with a new keyword, 防晒 (sunscreen), so the notes differ from Steps 1 to 5, and a rerun will not match the output below either. The limits (search 3, comments 2, creator notes 2) cost 15 + 5 + 10 + 5 + 10 = 45 credits. Set SMALL_LIMIT = 3 and the run costs up to 55, since you pay only for rows returned. Output of the billed run:

text
search: 3 rows, credits_used=15, has_more=True next_cursor=yes
  first row: id=6a5230a30000000021020908 text_chars=60 text_truncated=True views=None
note: credits_used=5 text_chars=500 text_truncated=False media_type=image media_urls=list(7) likes=2383 shares=147
comments: 2 rows, credits_used=10, has_more=True next_cursor=yes
  likes=78 replies=19 ip_location=四川
  likes=0 replies=2 ip_location=河南
profile: credits_used=5 followers=238 posts_count=28 likes_count=15578 has_notes_array=False
creator notes: 2 rows, credits_used=10, has_more=True next_cursor=yes
  2023-09-16 pinned=True likes=9415
  2026-09-01 pinned=False likes=10
total credits_used: 45

The note was an image note, so media_urls came back as a list of 7 URLs. On a video note the same line prints media_urls=str(1). The creator notes lead with a pinned note again, this one from 2023.

A repeat call inside the cache window costs 0 credits. An earlier run of the same chain with 韩国护肤, repeated a few minutes later, came back at 0 credits on every call. The windows are 120 seconds for search and the hot board, 600 for a note, 300 for comments, and 900 for a profile and for creator notes.

What each call cost in the first capture (2026-10-02):

CallRowsCredits
Search 韩国护肤, limit 3315
Hot search board, limit 101050
One note15
Comments, limit 3315
Creator profile15
Creator notes, limit 3315
Missing note (404)00
Total105

For a heavier job, a keyword search at the maximum limit of 20 costs 100 credits, the full note for each of the 20 rows costs another 100, and one profile adds 5, so 205 credits. That is a calculation at 5 credits per row, not a measured run. How credits and pricing work has the plan details. For scale, Rnote and TikHub list $0.01 per call, while SocialCrawl bills per returned row, so a 20-note job is not the same unit on both.

Is there an official RedNote API?

Yes, but it is seller infrastructure, and we found nothing in it for public notes. Xiaohongshu runs an official open platform at open.xiaohongshu.com, headed 电商开放平台 (E-commerce Open Platform). The interfaces in the docs we opened cover products, orders, after-sales, inventory, finance and logistics, for ERP, label-printing and listing tools that act on shops that have authorised the app. Authorisation is OAuth2 per shop, and the self-build route needs a shop that is not an individual or sole-trader type. We searched 23 documentation pages for notes, search, hot lists and creator profiles and found no endpoint for any of them. We could not open the per-method catalogue, so "none found" is the accurate summary, checked on 2026-10-02.

Pugongying (蒲公英) is the platform for brand and creator collaboration. Its creator and note data sits inside a login-gated console for brands, and we found no public API on it.

What could go wrong with Xiaohongshu API data?

  • Views are null on every row of search, note and creator-notes responses. A missing count is null, not zero, except search shares, which reads 0 (Step 1).
  • A short summary where you expected the post is text_truncated: true. Fetch the note.
  • The profile has no notes. Call profile/posts with the same id.
  • Creator-note paging is unconfirmed, so read has_more each time.
  • Comments are top level only, and the hot board never pages and caps at 20 topics.
  • A missing note is a 404 at 0 credits, so check the URL or id. A RedNote id on the profile call came back as a retryable 502 at 0 credits in our test, so use post.ext.author_id.
  • The scope is one day, two keywords and two or three rows per list call (ten on the hot board). The shapes are real and the rankings are a snapshot.

This API serves public data. Run your own compliance review for your use case, because this is not legal advice. A final Hangzhou Intermediate People's Court judgment reported on 27 April 2025 found a software company liable for unfair competition after it scraped Xiaohongshu while rotating user IDs and IP addresses to bypass technical protections, and the court said data interconnectivity does not justify unrestrained data acquisition. Our legal and technical guide to scraping goes deeper.

Where is the full Xiaohongshu API reference?

The parameters and response schemas for all six Xiaohongshu API calls are in the Xiaohongshu endpoint reference. The TikTok side of the same call pattern is in the TikTok video search API walkthrough, Naver crawling is the closest Asian-platform analogue, and social search covers one query across several networks.

Frequently asked questions

Is Xiaohongshu the same as RedNote?

Yes. Xiaohongshu (小红书) is the app's Chinese name and RedNote is its English brand name. It is also called Little Red Book. A Xiaohongshu API, a RedNote API and a Little Red Book API all refer to the same platform.

Can I look up a Xiaohongshu creator by RedNote ID?

No. The profile call takes the profile URL or the author_user_id, which is the author_id on a note. The RedNote id comes back as author.username on search, comment and profile rows, and it is null on the note call, but it is not a lookup key.

Do I need a Xiaohongshu account or a VPN?

No. You need only an API key, so you can run a Xiaohongshu search without login, cookie or VPN.

Is RedNote the same as Douyin or TikTok?

No. Xiaohongshu, Douyin and TikTok are separate networks. Each has its own accounts, posts and trend lists, so each needs its own calls.

Why are view counts missing?

These calls return no view count. Views were null on every row from the search, note and creator-notes calls in our captures, so computed engagement rate and estimated reach are null as well. Likes, comments and saves are real. Read shares from the note call, because search rows report 0 shares.

How much does the Xiaohongshu API cost?

5 credits per returned row on every endpoint. In our capture, 3 search rows cost 15 credits, 10 hot-board topics cost 50 and one note cost 5. A note that does not exist is a 404 and costs 0 credits.

Is there a Xiaohongshu API on GitHub?

Yes, repositories exist, but we did not audit them, and a repository name is not proof that Xiaohongshu maintains it. Check the maintainer, the licence and the last commit date before you depend on one.

Topics
#xiaohongshu-api#rednote-api#xiaohongshu-search#xiaohongshu-marketing#creator-xiaohongshu#xiaohongshu-scraper#little-red-book-api#xiaohongshu-trending#xiaohongshu-api-github

Related posts

🤖 AI agent or LLM? Read this page as markdown