SuperAPI AI Directory

xhs-smart-publisher

Marketing & growth

View repository

Updated 10-15 08:08

About this skill

Xiaohongshu Smart Publishing
  • Author: Daniel Li
  • Copyright © Daniel Li. All rights reserved.

⚡ Quick Workflow

触发词 → 填写内容 → 🔍 截图确认 → ⏳ 等待指令 → ✅ 发布/存草稿

Key: The screenshot confirmation step cannot be skipped!

Step Action Blocking?
1 Fill in title, body, hashtags, upload cover ❌
2 Send screenshot to group ⚠️ Required
3 Wait for user confirmation ✅ Blocking
4 Upon receiving "publish" → click publish ❌
4 Upon receiving "save as draft" → click save draft ❌

User instruction:

  • 发布 / 确认发布 → execute publish
  • 存草稿 / 暂存 → save to drafts

Formatting Rules

Item Rule
Title ≤20 characters, emoji + keywords + numbers, formula: audience + keywords + numbers + suspense + emoji
Body 300-1000 characters, double line breaks between paragraphs, each paragraph starts with 1-2 emojis, put the core in the first 3 lines
Hashtags #topic name (no spaces) 3-8, precise ones first, broad topics after
Cover 3:4 vertical (1080×1440), large text + contrasting colors + person/product occupying 60%+
Images 1-18 images, JPG/PNG, ≤20MB each
Best time Weekdays 18:00-22:00, weekends 20:00-23:00

Content Adaptation Template

When converting any content into Xiaohongshu format:

  1. Title: extract the core selling point, apply the formula 人群定位+关键词+数字+悬念词+emoji
    • Example:打工人必看🔥5个效率工具让你准时下班
  2. Body formatting:
    emoji 开头金句/痛点(抓注意力)
    
    emoji 正文第一段(核心信息,≤3行)
    
    emoji 正文第二段(展开论述)
    
    emoji 正文第三段(补充/案例)
    
    emoji 总结/互动引导(提问/投票)
    
    #精准话题1 #精准话题2 #泛话题3 #泛话题4
    
  3. Emoji strategy: 1 at the start of each paragraph, moderately accent next to keywords in the body, no more than 5% of the body
  4. Hashtag strategy: 2 precise topics (high search volume) + 2-4 broad topics (high exposure) + 1-2 long-tail topics

Publishing Process (Browser tool operations)

General process

Step 0: Confirm the publishing content type

  • Video → follow the video publishing process
  • Image-text → follow the image-text publishing process
  • Long-form → follow the long-form publishing process

📷 Image-Text Publishing Process (7 steps)

Step 1: Open the publish page

browser(action="navigate", profile="openclaw", 
       targetUrl="https://creator.xiaohongshu.com/publish/publish?source=official&target=image")

Step 2: Confirm the publishing type

  • Click "Upload Image-Text"

Step 3: Upload cover image

  • Click the upload button or input[type='file'] upload cover image
  • Wait for the image to finish loading

Step 4: Fill in the title

  • ⚠️ Locate the title input box: placeholder="Fill in the title to get more likes"
  • Use JavaScript to fill precisely (to prevent UI misalignment):
// 找到标题输入框并设置值
const titleInput = document.querySelector('input[placeholder*="标题"]');
if(titleInput) {
  titleInput.value = '标题内容(≤20字)';
  titleInput.dispatchEvent(new Event('input', {bubbles: true}));
}

Step 5: Fill in the body (⚠️ the most critical step)

  • First click the body editor to focus it:
    browser(action="act", kind="click", ref="<正文框ref>")
    
  • Wait 500ms let the Tiptap/ProseMirror editor initialize
  • Use the Tiptap/ProseMirror API to fill in the body:
// 将 Markdown 转换为 HTML
const text = `要粘贴的正文内容`;
const paragraphs = text.split('\n').filter(p => p.trim());
const htmlParts = paragraphs.map(p => {
    // 处理 **粗体**
    p = p.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
    return '<p>' + p + '</p>';
});
const html = htmlParts.join('');

// 写入编辑器
const editor = document.querySelector('.tiptap.ProseMirror');
if (editor) {
    editor.focus();
    editor.innerHTML = html;
    editor.dispatchEvent(new Event('input', {bubbles: true}));
}
  • Verify: The body text box word count should display X/1000(X>0); if it still displays 0/1000, try solutions B/C/D (see "UI issues and solutions")
  • ⚠️ If using browser evaluate, fn cannot contain await; wrap it with setTimeout:new Promise(r=>setTimeout(r,500)).then(()=>{...})

Step 6: Check layout

  • ⚠️ You must first verify that the body text has been written: the body text box word count should be > 0
  • Take a screenshot to confirm the formatting
  • Confirm the title box contains only the title (≤20 characters), word count X/20
  • Confirm the body text box contains the complete body text, word count X/1000
  • If body text is 0/1000 → body text was not written → go back to Step 5 and try other solutions
  • If there are layout issues, adjust manually

Step 7: 🔍 Screenshot confirmation (required step)

  • ⚠️ Before clicking publish/save draft, this step must be performed
  • Use browser to take a screenshot of the current page content:
    browser(action="screenshot", target="host")
    
  • Send the screenshot to the group to report:
    message(action="send", channel="telegram", target="-1003890797239", 
           message="📝 小红书内容已填写完毕,请确认后回复'发布'或'存草稿'",
           accountId="xiaocode")
    
  • You must wait for user confirmation before continuing(do not publish automatically)

Step 8: ⏳ Wait for user confirmation

  • The user replies with one of the following commands:
    • 发布 / 确认发布 → execute publish
    • 存草稿 / 暂存 → save to drafts
    • 修改 / 取消 → stop the process and wait for retriggering
  • ⚠️ This step is blocking; do not perform any operation before receiving an explicit command

Step 9: ✅ Execute publish/save draft

Choose based on user confirmation:

Publish mode:

  • Click the "Publish" button
  • Wait for the publish success prompt
  • Take a screenshot to confirm the publish result
  • Send a completion notification to the group

Draft mode:

  • Click the "Save and leave" button
  • Confirm the draft was saved successfully
  • Send a completion notification to the group

📝 Long-form publishing process (6 steps)

Compared with image-text posts, the step of uploading an image cover is omitted

Step 1: Open the publishing page

  • URL: https://creator.xiaohongshu.com/publish/publish?source=official

Step 2: Confirm publishing type

  • Click "Write long-form"

Step 3: Fill in the title

  • Same as image-text Step 4

Step 4: Fill in the body text

  • Same as image-text Step 5

Step 5: 🔍 Screenshot confirmation (required step)

  • Same as image-text Step 7: you must first take a screenshot and send it to the group to wait for confirmation

Step 6: ⏳ Wait for user confirmation

  • Same as image-text Step 8: wait for the user to reply "publish" or "save draft"

Step 7: ✅ Execute publish/save draft

  • Same as image-text Step 9

🎬 Video publishing process (3 steps)

Step 1: Upload video

  • Click "Upload video"
  • Select the video file to upload

Step 2: 🔍 Screenshot confirmation (required step)

  • After filling in the title, description, and other content
  • Execute browser(action="screenshot", target="host") screenshot
  • Send to the group and wait for confirmation
  • ⚠️ You must wait for user confirmation before publishing

Step 3: ⏳ Wait for user confirmation

  • Same as image-text Step 8

Step 4: ✅ Execute publish

  • After user confirmation, click "Publish"

Automation script usage

python scripts/xhs_publish.py \
  --title "标题文字" \
  --content "正文内容" \
  --tags "话题1,话题2,话题3" \
  --image "/path/to/cover.jpg" \
  --mode draft \
  --auto-login

Parameter description:

  • --auto-login: Automatically connect to openclaw browser to obtain login state
  • --mode draft: Save to drafts (default)
  • --mode publish: Publish directly

Browser Automation Notes

Logged-in State Acquisition

Use openclaw browser profile="openclaw", connect via CDP (http://127.0.0.1:18800) to automatically reuse the login state.

UI Issues and Solutions

❌ Issue 1: The body text box 0/1000 cannot be written into (confirmed 2026-03-20)

Symptom: The title is correct (8 characters), but the body text box shows 0/1000, and neither fill nor type of browser can write content.

Root cause: The Xiaohongshu creator platform has migrated from Quill.js to Tiptap/ProseMirror(class=tiptap.ProseMirror). Ordinary DOM operations (setting innerText/value) do not trigger React state updates, resulting in:

  • Although the content appears visually, the internal state of Tiptap is empty
  • The word count does not change (0/1000)
  • The body text is lost after saving the draft

✅ Solution (recommended solution):

Option A: Direct write via Tiptap/ProseMirror API (recommended)

// 将 Markdown 转换为 HTML 段落
const text = '要粘贴的正文内容\n第二段内容';
const paragraphs = text.split('\n').filter(p => p.trim());
const htmlParts = paragraphs.map(p => {
    // 处理 **粗体**
    p = p.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
    return '<p>' + p + '</p>';
});
const html = htmlParts.join('');

// 写入 Tiptap 编辑器
const editor = document.querySelector('.tiptap.ProseMirror');
if (editor) {
    editor.focus();
    editor.innerHTML = html;
    editor.dispatchEvent(new Event('input', {bubbles: true}));
}

Option B: Simulate paste via Clipboard API (alternative)

// 先点击正文编辑器获取焦点
document.querySelector('.tiptap.ProseMirror')?.click();
// 等待 300ms 让编辑器初始化
await new Promise(r => setTimeout(r, 300));
// 使用 Clipboard API 粘贴
const text = '要粘贴的正文内容';
const clipboardData = new DataTransfer();
clipboardData.setData('text/plain', text);
const pasteEvent = new ClipboardEvent('paste', {
  clipboardData: clipboardData,
  bubbles: true,
  cancelable: true
});
document.querySelector('.tiptap.ProseMirror')?.dispatchEvent(pasteEvent);

Option C: executeCommand (compatible solution)

document.querySelector('.tiptap.ProseMirror')?.focus();
document.execCommand('selectAll');
document.execCommand('insertText', false, '正文内容');

Verification criterion: After writing, the body text box word count should display X/1000(X>0)。


❌ Issue 2: Title and body content are mixed up

Symptom: The title input box displays a character count such as "510/20", and the content was pasted into the title position.

Root cause: Incorrect positioning of the contenteditable field of the editor UI.

Solution:

  1. Fill in the title first: Use input[placeholder*="标题"] to locate
  2. Then click the body text box: After clicking .ql-editor , wait 500ms
  3. Finally fill in the body text: Use Option A to paste
  4. Verify that the title box word count ≤ 20 and the body text box word count > 0

Manual Correction Process (final fallback)

  1. Open the drafts
  2. Click "Edit" to enter the article
  3. Manually copy the body text to the correct position and correct the title
  4. Click publish

Error Handling

Error Handling
Login expired Prompt the user to scan the QR code again and save the new cookie
Slider verification Pause and wait for manual completion, set --headless false
Title too long Automatically truncate to 20 characters and warn
Image upload failed Retry 3 times with a 5-second interval each time
Network timeout Retry 3 times with exponential backoff (5s/15s/45s)
Publishing rate limit Wait 60 seconds and retry
Content mixed into the title Manually correct after saving the draft

Pre-publish Checklist

  • Title ≤ 20 characters, including emoji and keywords
  • Body text ≥ 100 characters (required by new rules)
  • 3-8 tags, # format
  • Cover image in 3:4 vertical format
  • No watermarks from other platforms
  • Not AI-reposted content (originality requirement)

File Structure

xhs-smart-publisher/
├── SKILL.md
├── scripts/
│   └── xhs_publish.py        # Playwright 自动发布脚本
├── references/
│   └── platform-rules.md     # 完整平台规则(从调研文档提取)
└── templates/
    └── content-template.md   # 排版模板示例