XHS Data APIOpen in RapidAPI
All guides

Pagination tutorial

Paginate comments without duplicates

Continue a short-lived, resource-bound cursor chain without skipping pages after temporary failures.

Request the first page

Start without a cursor. The complete note URL and its current token remain unchanged for the entire chain.

import os
import requests

base_url = "https://xhs-data-api.p.rapidapi.com"
headers = {
    "X-RapidAPI-Key": os.environ["X_RAPIDAPI_KEY"],
    "X-RapidAPI-Host": "xhs-data-api.p.rapidapi.com",
}
note_url = os.environ["XHS_NOTE_URL"]

response = requests.get(
    f"{base_url}/note/comments_from_url",
    headers=headers,
    params={"url": note_url, "count": 10, "raw": "false"},
    timeout=45,
)
response.raise_for_status()
page = response.json()["data"]

page["count"] equals len(page["items"]). Continue only when has_more is true and next_cursor is present.

Continue and deduplicate

cursor = None
seen = set()

while True:
    params = {"url": note_url, "count": 10, "raw": "false"}
    if cursor:
        params["cursor"] = cursor

    response = requests.get(
        f"{base_url}/note/comments_from_url",
        headers=headers,
        params=params,
        timeout=45,
    )
    response.raise_for_status()
    page = response.json()["data"]

    for comment in page["items"]:
        if comment["comment_id"] not in seen:
            seen.add(comment["comment_id"])
            print(comment["comment_id"], comment.get("content"))

    if not page["has_more"]:
        break
    cursor = page["next_cursor"]

Do not edit a cursor or reuse it with another note. If a page returns 503 REQUEST_TIMEOUT, do not advance; honor Retry-After and retry the same URL and cursor.

Normalized like_count and sub_comment_count are integers when supplied upstream. Comment status is an upstream integer code, not one fixed enum.