xhs-sync
Writes each collected Xiaohongshu note as a page into a Notion database, automatically creating any missing columns (XHS ID, Category, Tags, Summary, Likes, etc.) and upserting only when note content changes.
Writes each collected Xiaohongshu note as a Markdown file with YAML frontmatter into an Obsidian vault, organized by category and month, downloading images for offline use and preserving the user's own manual edits.
Pulls notes saved on Xiaohongshu (收藏/赞过/own posts) using the user's logged-in browser session, extracting titles, bodies, images, authors, hashtags, and engagement counts. Provides tools to trigger a sync, add/sync a single note by URL, and search through the synced notes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@xhs-syncsync my saved Xiaohongshu notes to Notion"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
xhs-sync — 小红书 → Notion / Obsidian
Pulls the notes you've saved on Xiaohongshu (小红书) into Notion, Obsidian, or both, sorts them into categories automatically, and keeps them in sync. Run it by hand, put it on a schedule, or drive it from an AI assistant over MCP.
小红书 收藏/点赞/笔记
│
▼
collect ──► categorize ──► Notion (one page per note)
(browser) (rules + Claude) Obsidian (one Markdown file per note)
│ │
└────────── state.db ◄────────┘
(dedupe — re-runs are cheap)What you get
Your saved notes, in your own tools. Title, full body, images, author, hashtags, like/save counts and a link back to the original.
Automatic categories. Every note lands in one of 15 categories (美食, 旅行, 穿搭, 美妆, 家居, 健身健康, 学习成长, 职场, 数码科技, 理财, 育儿, 摄影, 宠物, 兴趣手作, 其他) plus a subcategory, searchable tags, and a one-line summary. Fully editable — see Categories.
Idempotent syncs. A note is only rewritten when its content actually changed. Your own edits in Obsidian are preserved.
Works offline-ish. Without an Anthropic API key it falls back to keyword rules, which are free and surprisingly decent.
Related MCP server: Enhanced Obsidian MCP Server
Install
git clone <this repo> xhs-sync && cd xhs-sync
python3 -m venv .venv && source .venv/bin/activate
pip install -e '.[all]'
playwright install chromium # one-time browser downloadThen set up your config and credentials:
xhs-sync init # writes config/config.yaml
cp .env.example .env # then fill in your tokensSet up the destinations
You need at least one. Both is fine.
Obsidian
Just point at your vault — nothing else to install:
# in .env
OBSIDIAN_VAULT=/Users/you/Documents/MyVaultNotes are written to <vault>/小红书/<Category>/<YYYY-MM>/<title>-<id>.md with YAML
frontmatter (category, tags, url, likes, …), so Dataview and the graph view pick
them up immediately. Images are downloaded into the vault by default so the notes work
offline.
Notion
Create an integration at https://www.notion.so/my-integrations and copy the secret.
Create (or pick) a database, open it, and connect your integration:
···→ Connections → your integration.Copy the database id from its URL — the 32-character chunk in
notion.so/<workspace>/<DATABASE_ID>?v=….
# in .env
NOTION_TOKEN=secret_xxxxxxxx
NOTION_DATABASE_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThe database can be empty — on first run the missing columns (XHS ID, Category,
Tags, Summary, Likes, …) are created for you.
Set up categorization
Add an Anthropic API key and ambiguous notes get classified by Claude:
# in .env
ANTHROPIC_API_KEY=sk-ant-xxxxLeave it out and everything falls back to keyword rules. See How categorization works for the tradeoff.
Use it
xhs-sync login # opens a browser — scan the QR code once
xhs-sync doctor # checks everything is wired up
xhs-sync sync --dry-run # see what it would do
xhs-sync sync # do itlogin stores the session in a persistent browser profile under ~/.xhs-sync/, so you
only do it once (until Xiaohongshu expires it — re-run login when a sync says you're
logged out).
Everyday commands
Command | What it does |
| Sync your 收藏 tab (newest first) |
| Sync 赞过 instead ( |
| Only look at the 50 most recent |
| Write to one destination this run |
| Show categories, write nothing |
| Sync one specific note |
| Re-run categorization over everything (after editing the taxonomy) |
| What's in the local database, by category |
| Diagnose setup problems |
Run it on a schedule
scripts/ has ready-made units — edit the paths inside first.
# macOS
cp scripts/com.xhs-sync.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.xhs-sync.plist
# Linux
cp scripts/xhs-sync.{service,timer} ~/.config/systemd/user/
systemctl --user enable --now xhs-sync.timer
# or plain cron — daily at 09:00
0 9 * * * PROJECT_DIR=$HOME/xhs-sync /bin/bash $HOME/xhs-sync/scripts/sync.shScheduled runs need a valid login. When the session expires the run logs it and exits non-zero rather than failing silently.
Categories
Categories live in config/taxonomy.yaml. Adding one is three
lines:
- name: 咖啡 Coffee
description: Espresso gear, bean reviews, brewing methods, cafe hopping.
color: brown
keywords: [咖啡, 手冲, espresso, v60, latte art]
subcategories:
- name: 器具 Gear
keywords: [磨豆机, 手冲壶, grinder, portafilter]Both the keyword matcher and Claude read that file, so a new category is picked up by
both. After editing, xhs-sync recategorize re-sorts everything you've already synced.
How categorization works
Three modes, set by categorize.mode in config.yaml (or --mode):
Mode | Behaviour | Cost |
| Keyword scoring only | Free, offline |
| Every note goes to Claude | ~1 request per 8 notes |
| Keywords when they're confident, Claude otherwise | Usually a handful of requests |
In hybrid mode a note skips the API when its top keyword score clears
rules_confident_at and beats the runner-up by rules_margin — i.e. when the answer
is obvious ("空气炸锅鸡翅做法" is 美食, no model needed). Everything vague goes to Claude,
which also writes the summary and the searchable tags. Notes are batched, and the
taxonomy prompt is cached, so a 200-note first sync is a few cents.
Claude's answer is constrained to a JSON schema and mapped back onto a real category from your taxonomy, so it can't invent one. Note text is passed as data, never as instructions.
If you fix a category by hand — edit the Category in Notion, or use
xhs-sync recategorize after editing the taxonomy — a manual category is never silently
overwritten by the rules on a later run.
MCP server
The repo also exposes the sync as an MCP server, so an assistant can run it:
xhs-sync serve-mcp # speaks MCP over stdioRegister it with Claude Code:
claude mcp add xhs-sync -- /absolute/path/to/.venv/bin/xhs-sync serve-mcpOr add it to any MCP client's config:
{
"mcpServers": {
"xhs-sync": {
"command": "/absolute/path/to/.venv/bin/xhs-sync",
"args": ["serve-mcp"]
}
}
}Tools: xhs_sync_now, xhs_add_note, xhs_search_notes, xhs_list_categories,
xhs_recategorize — so you can ask things like "sync my latest saves" or "what travel
notes have I saved about Kyoto?"
How collection works
Xiaohongshu has no public API, and its web endpoints are signed in JavaScript that changes regularly. Reimplementing that signing means re-reimplementing it every few months.
Instead this drives a real Chromium with your logged-in session, scrolls your own tab, and reads the JSON the page fetches for itself. Two consequences worth knowing:
It only ever reads your own account's data — the same notes you see when you open the app.
It degrades rather than breaks. The extractor walks whatever JSON arrives looking for note-shaped objects instead of pinning to endpoint paths and field names, and falls back to reading the DOM, then to the page's embedded state. When Xiaohongshu reshuffles things, you'll usually get fewer fields rather than a crash.
Be reasonable with it: sync on a timer, not in a loop. It's your own saved notes, at human speed.
To use an existing Chrome instead of Playwright's Chromium:
export XHS_BROWSER_EXECUTABLE="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"What lives where
src/xhs_sync/
collect/extract.py tolerant JSON → Note (the bit that survives site changes)
collect/browser.py Playwright session, scrolling, XHR capture
categorize/rules.py offline keyword scoring
categorize/llm.py Claude classifier (schema-constrained, batched, cached)
categorize/engine.py hybrid decision logic
sinks/obsidian.py Markdown + frontmatter, preserves your edits
sinks/notion.py database upsert, creates missing columns
pipeline.py collect → categorize → write → record
state.py sqlite dedupe + sync state
mcp_server.py MCP over stdio
cli.py the xhs-sync command
config/taxonomy.yaml your categoriesDevelopment
pip install -e '.[dev]'
pytest -q # 62 tests, no network or browser needed
pytest -q --live-browser # also launch a real ChromiumThe tests cover the extractor against realistic payload shapes, keyword scoring, both sinks' output, dedupe behaviour, the pipeline, and the MCP protocol layer.
Try it without a Xiaohongshu account at all — xhs-sync import takes a JSON file of raw
note payloads and runs the whole pipeline on it:
xhs-sync import path/to/notes.json --dry-runNotes and limits
Private to you. Everything runs locally. The only things leaving your machine are the writes to your Notion database and, in
hybrid/llmmode, note text sent to the Anthropic API for categorization. Use--mode rulesto send nothing anywhere.Your login can expire. Re-run
xhs-sync loginwhen a sync reports it.Videos are linked, not downloaded. Images are downloaded into the Obsidian vault; Notion embeds them by URL (Xiaohongshu's CDN links can expire, so the vault copy is the durable one).
Notion API version is pinned to
2022-06-28.
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect AI to your flomo notes. Search, create, edit notes and manage tags via MCP.
搜索笔记、浏览首页推荐、查看笔记内容与评论,并发表你的评论。直接在工作流中与小红书内容互动,高效跟进话题。
Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.
- aNotepadOAuthcom.anotepad
AI access to your aNotepad online notes: read, search, write, and organize via 22 tools.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to interact with Obsidian vaults, providing tools for reading, creating, editing and managing notes and tags.2,778 npm733MIT
- AlicenseBqualityFmaintenanceEnables seamless integration between AI models and Obsidian knowledge bases with 25 advanced tools for note management, intelligent search, AI-powered content analysis, auto-linking, tag management, template systems, and knowledge graph generation.2521 npm26MIT
- AlicenseBqualityDmaintenanceEnables AI assistants to create, read, update, and manage SiYuan notes, supporting notebook management, document operations, block editing, database attribute views, search, file operations, and export.1114 npm1MIT
- AlicenseBqualityDmaintenanceEnables AI assistants to search, create, and manage notes in an Obsidian vault via 40+ local tools.526 npmMIT