How to Build a WeChat Chatbot from Scratch with Wechaty: Auto-Reply & Group Management

6 views 0 likes 0 comments 24 minutesOriginalTutorial

A step-by-step practical guide to building a deployable WeChat bot using Wechaty. Covers QR login, message listening, auto-replies, group automation, and common pitfalls with complete production-ready code.

#Wechaty #Chatbot #Node.js #TypeScript #WeChat Bot #Automation #RPA #Practical Tutorial
How to Build a WeChat Chatbot from Scratch with Wechaty: Auto-Reply & Group Management

How to Build a WeChat Chatbot from Scratch with Wechaty: Auto-Reply & Group Management

As a backend developer, you've likely encountered scenarios like these: business groups are flooded with hundreds of repetitive questions daily ("How do I use feature X?", "Why is X throwing an error?"), leaving your support team exhausted from manual replies. Or maybe you want to build a scheduled notification assistant, but WeChat lacks an official Bot API, and reverse-engineering protocols risks account bans. When I led a team building internal tools, we faced the exact same headaches—until we discovered Wechaty. It turns out that "writing a WeChat bot" can be as simple as writing just 6 lines of code.

Wechaty is an open-source Conversational RPA SDK that abstracts away the low-level protocol details for platforms like WeChat and WhatsApp. You don't need to worry about protocol reverse-engineering; you just focus on business logic. It supports TypeScript/JavaScript and runs seamlessly on Node.js or Docker. In this guide, I'll walk you through building a fully functional chatbot from scratch with auto-reply and group management capabilities.

By the end of this tutorial, you will:

  • Set up a local development environment and run your first bot
  • Understand Wechaty's event-driven architecture (QR login, message listening, group events, etc.)
  • Write a complete "auto-reply + group welcome + keyword trigger" bot
  • Learn deployment best practices and avoid common pitfalls

Prerequisites

Before starting, ensure your environment meets these requirements:

Dependency Minimum Version Why It's Needed
Node.js 16+ Wechaty relies on modern ES Module features
npm 7+ Package management and dependency resolution
TypeScript (Optional) 4.4+ Required if you plan to develop using TypeScript

If you haven't installed Node.js 16+ yet, I highly recommend using nvm (Node Version Manager) to manage versions cleanly:

bash 复制代码
## After installing nvm
nvm install 16
nvm use 16
node -v  # Verify v16.x.x or higher

Why the version matters: Wechaty heavily uses modern ES Module syntax. Running it on Node 14 or older will trigger import/export parsing errors. Learn this the hard way, or just use nvm.


Quick Start: Run Your First Bot in 6 Lines

Wechaty officially claims to have "the world's shortest chatbot code." Let's verify that.

Step 1: Initialize the Project

bash 复制代码
mkdir my-wechaty-bot && cd my-wechaty-bot
npm init -y
npm install wechaty

npm init -y generates a default package.json, and npm install wechaty pulls in the SDK and its dependencies. Why use an isolated directory? Wechaty's dependency chain is quite long. Placing it in an existing project may cause version conflicts. A clean folder makes debugging much easier.

Step 2: Create the Bot Entry File

In the project root, create bot.js and add the following:

javascript 复制代码
import { WechatyBuilder } from 'wechaty'

const wechaty = WechatyBuilder.build()

wechaty
  .on('scan', (qrcode, status) => {
    const url = `https://wechaty.js.org/qrcode/${encodeURIComponent(qrcode)}`
    console.log(`Please scan the QR code to log in! Status: ${status}\nQR Link: ${url}`)
  })
  .on('login', (user) => console.log(`✅ Login successful. Welcome back: ${user}`))
  .on('message', (msg) => console.log(`📨 Message received: ${msg}`))

wechaty.start()

This demonstrates Wechaty's core event model:

  • scan: Triggered when the bot starts and generates a QR code. You scan it with WeChat on your phone. The qrcode payload is raw data; appending it to Wechaty's official URL renders it in a browser. QR codes expire quickly, so you'll need to re-scan if disconnected.
  • login: Fires after successful QR confirmation. The user object contains your logged-in WeChat account info.
  • message: Triggered for every incoming message (both private chats and group messages).
  • start(): Initializes the Puppet (underlying protocol layer) and begins listening.

Step 3: Run It

bash 复制代码
node bot.js

The terminal will print a QR code link. Open it in your browser and scan it with WeChat. Once confirmed, you'll see ✅ Login successful. Any subsequent messages sent to your account or groups will be logged in the terminal.

Note: By default, this uses the Puppeteer protocol (based on WeChat Web). Due to WeChat's official policies, the Web protocol has restrictions on certain accounts. If login fails, I'll show you how to switch protocols later.


Practical Example: A Complete "Smart Customer Service + Group Manager" Bot

Logging messages is fine, but let's build something that actually works in production. This bot will:

  • Auto-reply to common private chat inquiries (keyword matching)
  • Send a welcome message when new members join a group
  • Reply with a feature list when "help" is mentioned in a group

Full Code

Create smart-bot.js:

javascript 复制代码
import { WechatyBuilder } from 'wechaty'

// 1. Define auto-reply rules (In production, replace this with a DB lookup or LLM API call)
const FAQ = {
  'Pricing': 'Our services come in Basic (Free) and Pro ($99/month). Visit our website for details.',
  'Refund': 'We support a 7-day no-questions-asked refund policy. Please submit a request via your order page.',
  'Help': 'Reply with these keywords for assistance: Pricing, Refund, Contact Support. Or connect with human support.'
}

// 2. Create Wechaty instance
const wechaty = WechatyBuilder.build({
  name: 'smart-customer-bot',  // Naming the bot helps with log separation
})

// 3. Listen to QR scan event
wechaty.on('scan', (qrcode, status) => {
  const url = `https://wechaty.js.org/qrcode/${encodeURIComponent(qrcode)}`
  console.log(`📱 Please scan to log in!\nStatus: ${status}\nOpen link to view QR: ${url}`)
})

// 4. Listen to login event
wechaty.on('login', async (user) => {
  console.log(`🎉 Login successful! Bot started. Account: ${user.name()}`)
  
  // Send a confirmation message to yourself upon startup
  await user.say('🤖 Smart Customer Bot is online and ready!')
})

// 5. Listen to message event (Core Logic)
wechaty.on('message', async (msg) => {
  // Ignore messages sent by the bot itself to prevent infinite loops
  if (msg.self()) return

  const text = msg.text()
  const from = msg.from()

  // --- Scenario A: Private Chat Auto-Reply ---
  if (!msg.room() && from) {
    console.log(`💬 DM - From ${from.name()}: ${text}`)
    
    // Iterate FAQ rules, reply if keyword matches
    for (const [keyword, reply] of Object.entries(FAQ)) {
      if (text.toLowerCase().includes(keyword.toLowerCase())) {
        await msg.say(reply)
        console.log(`📤 Auto-replied: ${reply.substring(0, 30)}...`)
        return
      }
    }
    
    // Fallback response if no keyword matches
    await msg.say('🤖 Unable to recognize your query. Reply "Help" for common FAQs, or wait for human support.')
  }

  // --- Scenario B: Group Interaction ---
  if (msg.room()) {
    const room = await msg.room()
    const roomName = await room.topic()
    console.log(`👥 Group [${roomName}] - ${from?.name() || 'Unknown'}: ${text}`)

    // Reply when "help" keyword is detected in group
    if (text.toLowerCase().includes('help')) {
      const helpMsg = `📋 Group Bot Features:
1. Reply "Pricing" for service plans
2. Reply "Refund" for refund policies
3. Reply "Contact Support" for human agents`
      await room.say(helpMsg)
    }
  }
})

// 6. Listen to member join event
wechaty.on('room-join', async (room, inviteeList, inviter) => {
  const roomName = await room.topic()
  const inviteeNames = inviteeList.map(c => c.name()).join(', ')
  const inviterName = inviter?.name() || 'Unknown'

  console.log(`🎊 New member joined: ${inviteeNames} (invited by ${inviterName}), Group: ${roomName}`)

  const welcomeMsg = `👋 Welcome @${inviteeNames} to 【${roomName}】!\nI'm your group assistant. Ask me anything or reply "Help" for features.`
  await room.say(welcomeMsg)
})

// 7. Start the bot
wechaty.start()

Code Breakdown

Module Purpose Design Rationale
FAQ Dictionary Maps keywords to replies In production, replace with an LLM API call or knowledge base query. A dictionary is perfect for prototyping.
msg.self() Check Filters bot's own messages Without it, your bot's replies would trigger the message event again, causing an infinite loop.
msg.room() Distinguishes DMs from group chats null/undefined means DM. A truthy value means group chat, allowing you to call room.say(), room.topic(), etc.
room-join Event Auto-welcome for new members Highly efficient for managing large groups compared to manual greetings.
@ Mention Using @Name in room.say() Wechaty automatically handles the underlying mention logic for you.

Common Pitfalls & Troubleshooting

1. Web Protocol Login Fails

Error: login failed is the most common issue with the default Web Puppet. WeChat officially restricts Web login for many accounts. Solution: Switch to an alternative Puppet via environment variables:

bash 复制代码
## Linux/macOS
export WECHATY_PUPPET=wechaty-puppet-service
## or
export WECHATY_PUPPET=wechaty-puppet-wechat4u

## Windows (PowerShell)
$env:WECHATY_PUPPET="wechaty-puppet-service"

wechaty-puppet-service uses a hosted iPad/Windows protocol. It's highly stable but may require a token (apply on the Wechaty official website).

2. SyntaxError: Cannot use import statement outside a module

This happens when Node.js doesn't recognize ES Modules. Add this to your package.json:

json 复制代码
{
  "type": "module"
}

After adding it, node bot.js will correctly parse import statements.

3. Account Ban Risk from Frequent Auto-Replies

Excessive automated replies can trigger WeChat's anti-bot security. Mitigation strategies:

  • Add Random Delays: await new Promise(r => setTimeout(r, Math.random() * 2000 + 1000)) before replying.
  • Set Daily Caps: Track daily reply counts and stop responding after hitting a threshold.
  • Only Respond to Mentions: Use msg.mentionSelf() to reply only when @mentioned, significantly reducing trigger frequency.

4. Running in Docker

Docker deployment eliminates Node.js environment setup headaches. The official image works out-of-the-box:

bash 复制代码
docker run -ti --rm --volume="$(pwd)":/bot wechaty/wechaty smart-bot.js

Place smart-bot.js in your current directory. Docker mounts it to /bot inside the container and executes it. Scan the QR link printed in the terminal as usual.


Summary & Next Steps

Let's recap what we've accomplished:

  1. Set up the environment with npm init & npm install wechaty
  2. Ran a basic QR login + message listener in 6 lines of code
  3. Built a fully functional Smart Customer Bot covering DM auto-replies, group welcomes, and keyword recognition
  4. Navigated Web protocol limits, ES Module errors, and anti-bot risks

Where to go from here:

  • Integrate LLMs: Replace the FAQ dictionary with OpenAI/Claude API calls for true AI conversational capabilities.
  • Plugin Architecture: Use Wechaty's WechatyPlugin system to modularize welcome messages, cron jobs, and keyword handlers.
  • Database Persistence: Log chats and user interactions to MongoDB or PostgreSQL for analytics and user profiling.
  • CI/CD Deployment: Use GitHub Actions + Docker to automate deployments to your VPS on push.

With 23,000+ GitHub stars, multi-platform support (WeChat/WhatsApp), and a 6-line quick start, this toolkit is well worth an afternoon of your time. Writing code always beats reading articles. Drop your questions in the comments, and happy building!

Last Updated:

Comments (0)

Post Comment

Loading...
0/500

No comments yet, be the first to comment!