Xiaohongshu Auto-Posting (XHS Auto-Posting)
End-to-end Xiaohongshu content operation: topic discovery → style reference → writing → publishing → performance tracking.
Language
All process output to user (progress updates, questions, status notifications) follows the user's language.
Objective
Automate a complete Xiaohongshu content operation cycle for a configured product: discover high-engagement pain-point topics via search, collect writing style references, generate platform-native content aligned with the style fingerprint, publish with user approval, and track post-publish performance metrics.
Prerequisites
- Xiaohongshu creator center (
creator.xiaohongshu.com) already logged in on a configured stealth browser (browser ID stored insession_state.json) workspaces/xhs-posting/workspace (auto-created on first run)
Pre-execution Checks
1. Tool Readiness
If browser-act has been confirmed available in the current session → skip this step.
Invoke browser-act via Skill tool to load usage. If installation or configuration issues arise, follow its guidance to resolve then retry.
2. Login Verification
Covered in Phase 0.5 — login check is deferred until session state is loaded (Phase 0.2) and the browser is opened. If the user triggers Phase 6 directly (standalone tracking mode), still complete Phase 0.2 and Phase 0.5 first.
3. Session Lifecycle
Each execution generates a unique session name (xhs-<YYYYMMDD>-<HHMM>) to avoid cross-conversation conflicts. The session is opened once in Phase 0.5 and closed at the end of the workflow. All commands in this Skill reference the session via $SESSION — the actual name is determined at runtime.
Runtime Workspace
All runtime files (config, drafts, publish records, screenshots) are written to the user's working directory (CWD) under workspaces/xhs-posting/. This directory is auto-created on first run.
workspaces/xhs-posting/ ← relative to user CWD
├── session_state.json # account & product config
├── config/
│ └── keywords.json # keyword pool
├── tracking/
│ └── published.json # published note records
├── reports/ # performance reports
└── <YYYY-MM-DD>/ # per-run date directory
├── topics/
├── selected_topics.json
├── style_fingerprint.json
├── drafts/
└── replies/
Quick Start
/xiaohongshu-auto-posting
Standalone triggers (jump directly to the corresponding phase, skipping Phase 0–4):
"track performance"/"see data"/"data collection"→ Phase 6 performance tracking"settings"/"switch account"/"update keywords"→ Phase 0 configuration wizard
Operational Rules
Three rules that apply to every browser-act session. Violating any one causes silent failures or long hangs. Full details in references/phase5-publish.md §0.
Rule 1 — Never pipe browser-act output directly
Redirect state output to a temp file, then grep the file. Piping may background the command when output contains multi-byte characters, making the result unavailable synchronously.
# WRONG
browser-act --session $SESSION state | grep "Publish"
# CORRECT
browser-act --session $SESSION state > /tmp/s.txt 2>&1 && grep "Publish" /tmp/s.txt
Rule 2 — Escape all non-ASCII content before passing to eval --stdin
Non-ASCII literals (Chinese, emoji) in JS source cause encoding errors in the subprocess pipeline. Escape to \uXXXX first:
def to_ascii_js(s):
return ''.join(r'\u{:04x}'.format(ord(c)) if ord(c) > 127 else c for c in s)
js = to_ascii_js(open('tmp/script.js', encoding='utf-8').read())
subprocess.run([..., 'eval', '--stdin'], input=js.encode('ascii'), ...)
Rule 3 — Use click, not eval, for actions that trigger navigation
eval hangs (~30 s timeout) when the callback causes a page redirect. Always use browser-act --session $SESSION click <index> for the publish button, then verify the URL immediately after.
Phase 0 — Initialization
0.1 Tool Check
Run browser-act browser list:
- Command not found → run
uv tool upgrade browser-act-cli || uv tool install browser-act-cli --python 3.12, then continue - Returns normally → continue
0.2 Session State Load
Read workspaces/xhs-posting/session_state.json:
- File does not exist, or
browser_idis empty → proceed to 0.3 First-time Configuration Wizard - File exists and
browser_idis non-empty → load and display current config, ask user to confirm or modify
session_state.json structure:
{
"browser_id": "",
"account": {
"nickname": "",
"profile": ""
},
"product": {
"name": "",
"tagline": "",
"url": "",
"install_cmd": ""
},
"keywords_file": "workspaces/xhs-posting/config/keywords.json",
"posting": {
"daily_limit": 1,
"min_interval_hours": 6,
"last_posted_at": null
}
}
0.3 First-time Configuration Wizard (when file does not exist or browser_id is empty)
Step 1: Browser Selection
Run browser-act browser list, then:
When existing browsers are present: display all browsers (id / name / type / desc / proxy), ask the user which one to use for posting:
Existing browsers:
#1 id=xxx name="xxx" type=stealth desc="xxx" proxy=XX
#2 id=xxx name="xxx" type=chrome desc="xxx"
Select a browser number to use for posting, or enter "new" to create one:
>
When no browsers exist, or user enters "new":
- Load advanced guide:
browser-act get-skills advanced - Ask the user:
- Browser name (custom, e.g. "xhs-poster")
- Proxy requirements (needed? region or custom URL?)
- Create the browser following the advanced guide's Confirmation Gate protocol
- Record the new browser ID, continue to Step 2
Step 2: Product & Keyword Configuration
Ask the user:
- Product name (brand keyword, used in tags and body)
- Product tagline (one-sentence description)
- Product URL (website / GitHub / App Store, etc.)
- Install / usage command (optional; for SaaS products, enter the core operation path)
- Initial keywords (1–5, comma-separated, used for topic search)
Write to workspaces/xhs-posting/session_state.json and workspaces/xhs-posting/config/keywords.json, then continue to Phase 0.4.
0.4 Account Safety Check
- Read
posting.last_posted_atfromsession_state.json - If less than
min_interval_hourshave passed since the last post, notify the user and ask whether to force continue - If today's post count ≥
daily_limit, notify the user
0.5 Browser Launch & Login Verification
Generate a unique session name for this execution:
$SESSION = "xhs-<YYYYMMDD>-<HHMM>" # e.g., xhs-20260611-1430
Open the browser using the stored browser_id:
browser-act --session $SESSION browser open <browser_id> https://creator.xiaohongshu.com/new/home
browser-act --session $SESSION wait stable
Verify login: check that the current URL stays on creator.xiaohongshu.com (not redirected to the login page) and that a user avatar / nickname element is present in state.
- Not logged in → instruct the user to scan the QR code in
--headedmode:
Wait for the user to confirm login, then continue.browser-act --session $SESSION browser open <browser_id> https://creator.xiaohongshu.com/new/home --headed
Phase 1 — Pain-Point Topic Collection
Full execution parameters: references/phase1-topic-collection.md.
Overview:
- Keyword rotation: read the next keyword from
config/keywords.json(sequential mode) - XHS search: search the keyword, sort by hottest, collect metadata for the top 10–15 notes
- Listing Pass: extract shallow fields directly from search results (title, likes, collects, comments, snippet)
- Engagement scoring:
score = likes + collects × 2 + comments × 1.5 - Top 5 Deep: click into the top 5 notes and extract deep fields (key quote, pain description, topic tags)
- Generate report: output
workspaces/xhs-posting/<date>/topics/TOPICS_<kw-slug>.md - Display Top 5 and wait for user selection
Phase 2 — Top Case Collection (Style Reference)
Full execution parameters: references/phase2-case-collection.md.
Overview:
- Use the same search results as Phase 1; no additional request needed
- Collect full text from the top 3 high-engagement notes (title + body + tags)
- Analyze writing style: opening type, paragraph rhythm, emoji density, topic tag strategy
- Generate Style Fingerprint
- Write style fingerprint to
workspaces/xhs-posting/<date>/style_fingerprint.json
Phase 2 runs in parallel with Phase 1 (shared search results, different analysis angle).
Phase 3 — Topic Selection
After displaying the Phase 1 Top 5, ask the user:
Here are the Top 5 topics. Which ones do you want to write?
(enter numbers like "1 3"; "all" for all; "skip" to pass today)
>
On receiving the reply:
- Write the selected topic list to
workspaces/xhs-posting/<date>/selected_topics.json - For each selected topic, confirm the publish strategy (publish now / save as draft)
If the user enters "skip" → end this run without advancing last_index.
Phase 4 — Content Writing
Full writing guidelines: references/phase4-writing.md.
Write one draft per selected topic, show a preview after each draft and wait for user approval before moving to the next.
Writing framework: Pain resonance → Struggle / attempts → Product discovery → Concrete proof → Call to action
Hard requirements:
- Title ≤ 20 characters (must use native setter when writing; see
references/phase5-publish.md §5) - Body ≤ 1000 characters, clear paragraphs
- Topic tags: 3–5, covering keyword + product brand + scene term
- Must include a closing CTA (comment / save / follow)
Pre-Write Gate (confirm all items before writing begins):
key_quoteextracted from Phase 1 deep passpain_descriptionconfirmed from Phase 1tools_triedconfirmed from Phase 1- Product info (name, install command) read from
session_state.json - Style fingerprint (
style_fingerprint.json) read
After writing, generate an HTML preview (see references/phase4-writing.md §7), display it in the conversation, then ask:
Preview above. Ready to publish?
- "ok" / "publish" — proceed to Phase 5 publishing
- "edit: <instruction>" — revise per instruction and re-preview
- "draft" — save as draft, do not publish
Phase 5 — Publishing
Full execution parameters: references/phase5-publish.md.
Overview:
- Image generation: use XHS Creator Center's built-in "Text-to-Image" feature to auto-generate a cover (recommended), or read a user-provided local image
- Image upload (external image): two-step upload —
GET permit → PUT file— to obtainfile_id - Content Verification Gate: title ≤ 20 characters, body non-empty, topic tags present
- Fill Creator Center: navigate → paste content → add topics → set cover
- Publish: click the "Publish" button
- Capture publish URL: extract
note_idfrom the redirect URL or page - Write record: update
workspaces/xhs-posting/<date>/published.json, updateposting.last_posted_atinsession_state.json
Gate: publish only executes after user approval of the content; auto-publishing unapproved content is not allowed.
Phase 6 — Performance Tracking
Full execution parameters: references/phase6-tracking.md.
Standalone trigger: when the user says "track performance" / "see data" / similar trigger words, jump directly to this phase.
Sub-actions:
| Sub-action | Trigger | Description |
|---|---|---|
| 6.1 Single post 24h tracking | Auto-scheduled after Phase 5 publish | Revisit note_id 24h later, update initial metrics |
| 6.2 Batch data collection | User trigger / weekly | Pull latest data for all published notes from recent N days |
| 6.3 View comments | User trigger | View new comments, draft replies, reply after user approval |
| 6.4 Generate report | User trigger | Aggregate data, output table report |
Data stored locally in workspaces/xhs-posting/tracking/.
Account Safety Rules
- Posting frequency: ≤ 1 post per account per day, ≥ 6 hours between posts
- Content originality: before each publish, check title similarity against historical posts (simple character-level check to avoid exact duplicates)
- Avoid sensitive terms: body and title must not contain WeChat IDs, Weibo handles, contact info, or external links
- No artificial engagement: do not simulate batch likes / collects / comments
- Topic tags: use existing platform topics only; do not create new ones
- Image compliance: use XHS built-in generated images or self-owned copyright images; do not use screenshots from others
Success Criteria
- Phase 1:
candidates >= 10,deep-extracted notes = 5, report file exists - Phase 2:
style_fingerprint.jsonwritten,sample_notes count >= 1 - Phase 4: user explicitly approves draft content
- Phase 5: redirect URL contains
published=true,note_idcaptured and written topublished.json - Phase 6: all tracked note metrics updated without error
Session Cleanup
After completing the workflow (any phase exit — normal completion, user abort, or error), close the session to release resources:
browser-act session close $SESSION
Do not close if the user explicitly requests to keep the session open for manual inspection.
Known Limitations
- Max 1 post per account per day; minimum 6-hour interval enforced
window.__INITIAL_STATE__hydration timing is inconsistent — retry once after 2 s if emptysearch/notesXHR may not appear in all browser fingerprints; fall back toget markdownif missing- Topic chip insertion silently fails after
execCommandbody injection — always embed hashtags directly in body text (seereferences/phase5-publish.md §4.3) note_idmay not be auto-capturable when note is under review; record aspending_reviewand fill in manually later
Experience Notes
Path: {working-directory}/browser-act-skill-forge-memories/xiaohongshu-auto-posting-xhs-post.memory.md
Before execution: if the file exists, read it first — it records unexpected situations encountered during past executions (e.g., a strategy has become ineffective); adjust strategy accordingly.
After execution: if an unexpected situation is encountered (strategy became ineffective, page redesigned, anti-scraping upgraded, better path discovered), append a line:
{YYYY-MM-DD}: {what happened} → {conclusion}
Normal execution does not write to the file. Do not record which keywords were used or how many results were returned — those are task outputs, not experience.