# Xiaohongshu API Example: 6 Calls With Real Responses (https://www.socialcrawl.dev/blog/xiaohongshu-api) > 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. The [Xiaohongshu](https://en.wikipedia.org/wiki/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](https://fortune.com/asia/2024/12/12/china-xiaohongshu-crosses-one-billion-in-profit-instagram-style) 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 ``` 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](https://dev.to/sami_8858131362756585e4f4/how-to-scrape-rednote-xiaohongshu-with-python-in-2026-the-authsigning-problem-and-how-to-3f9e), 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](/blog/best-social-media-scraping-apis-2026). 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](https://zdnet.co.kr/view/?no=20240814181012), 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: | Field | Search row | Note call | |---|---|---| | Text length | 57 characters | 626 characters | | `ext.text_truncated` | true | false | | `engagement.shares` | 0 | 173 | | `engagement.comments` | 239 | 241 | | `content.media_urls` | null (image note) | array of 10 image URLs | | `author.username` | populated | null | 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" ``` | Published | `flags.pinned` | Likes | Comments | Shares | Saves | Summary length | |---|---|---|---|---|---|---| | 2026-09-17 | true | 4,013 | 573 | 93 | 485 | 100 chars | | 2026-09-06 | true | 32,807 | 4,930 | 3,495 | 10,108 | 100 chars | | 2026-09-26 | false | 280 | 81 | 16 | 101 | 98 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): | `rank` | `title` | Our gloss | `hot_value` | |---|---|---|---| | 1 | 用万能旅行拍照姿势美美出片 | Travel photo poses that work anywhere | 9475000 | | 2 | 耗时三年拍下古诗词里的中国 | Three years photographing the China of classical poems | 9348000 | | 3 | 我拍到了海鸥雨 | I caught a "seagull rain" on camera | 9032000 | | 4 | 超日常美食教程速来get | An everyday food tutorial, come and get it | 8860000 | | 5 | 定格这一刻的日照金山 | Freezing this moment of sunlit golden peaks | 8711000 | 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](/blog/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. """ 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): | Call | Rows | Credits | |---|---|---| | Search `韩国护肤`, limit 3 | 3 | 15 | | Hot search board, limit 10 | 10 | 50 | | One note | 1 | 5 | | Comments, limit 3 | 3 | 15 | | Creator profile | 1 | 5 | | Creator notes, limit 3 | 3 | 15 | | Missing note (404) | 0 | 0 | | Total | | 105 | 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](/blog/social-media-api-pricing) has the plan details. For scale, [Rnote](https://rnote.dev/en/) and [TikHub](https://tikhub.io/xiaohongshu-api) 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](https://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](https://pgy.xiaohongshu.com) (蒲公英) 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](https://news.qq.com/rain/a/20250427A05HPL00) 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](/blog/social-media-scraping-legal-technical-guide) 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](/platforms/xiaohongshu). The TikTok side of the same call pattern is in the [TikTok video search API](/blog/tiktok-video-search-api) walkthrough, [Naver crawling](/blog/naver-crawling) is the closest Asian-platform analogue, and [social search](/blog/social-search-engine) 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.