Send WeCom Group Bot Messages with a CloudBase Cloud Function
In one sentence: Use a CloudBase Cloud Function to push messages — text, Markdown, images, and more — to a WeCom Group Bot via Webhook, with an optional timer trigger for monitoring alerts or daily data reports.
Estimated time: 15 minutes | Difficulty: Beginner
Applicable Scenarios
- Applicable: Pushing messages from the CloudBase backend to a WeCom group — monitoring alerts, deployment notifications, daily data reports, business event notifications
- Applicable: You already have WeCom (WeCom) access and can create groups and Group Bots
- Not applicable: Pushing to personal WeChat (WeChat has no open personal message push API)
- Not applicable: Two-way interactive conversations that require receiving user replies (Webhook is send-only)
Prerequisites
| Dependency | Version |
|---|---|
@cloudbase/node-sdk | 3.18.1 |
@cloudbase/cli | 3.0.4 |
| Node.js | ≥ 16.13 |
Pre-condition: CloudBase Cloud Functions have public internet access by default (when no VPC is configured). If your Cloud Function is inside a VPC without a NAT gateway, enable public internet access in the Console first — otherwise the function cannot reach the WeCom Webhook endpoint.
Step 1: Create a WeCom Group Bot
- Create a group in WeCom (or use an existing one)
- Click the group name → Group Bots → Add Group Bot
- Give the bot a name (e.g., "CloudBase Alerts")
- After creation, copy the Webhook URL, which looks like:
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Note the UUID after key=.
Step 2: Write the Push Cloud Function
mkdir -p cloudfunctions/wecomNotify
cd cloudfunctions/wecomNotify
npm init -y
npm install --save @cloudbase/node-sdk@3.18.1
cloudfunctions/wecomNotify/index.js:
const https = require('https');
const WECOM_KEY = process.env.WECOM_WEBHOOK_KEY;
exports.main = async (event, context) => {
const { msgtype, content } = event;
if (!content) {
return { error: 'MISSING_CONTENT', message: 'event.content is required' };
}
let body;
if (msgtype === 'markdown') {
body = {
msgtype: 'markdown',
markdown: { content },
};
} else {
// Default to plain text
body = {
msgtype: 'text',
text: {
content,
mentioned_list: event.mentioned_list || [],
},
};
}
const result = await postWebhook(body);
return result;
};
function postWebhook(body) {
return new Promise((resolve, reject) => {
const url = `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${WECOM_KEY}`;
const data = JSON.stringify(body);
const req = https.request(
url,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(data),
},
},
(res) => {
let raw = '';
res.on('data', (chunk) => (raw += chunk));
res.on('end', () => {
try {
resolve(JSON.parse(raw));
} catch (err) {
resolve({ raw });
}
});
},
);
req.on('error', reject);
req.write(data);
req.end();
});
}
This uses Node.js's built-in https module — no extra dependencies needed. Keeping node_modules small reduces cold start latency (see the "Trim dependencies" section in Optimize Cold Start).
Step 3: Deploy and Send a Test Message
tcb fn deploy wecomNotify --dir ./cloudfunctions/wecomNotify -e your-env-id
Console → Cloud Functions → wecomNotify → Environment Variables, add:
WECOM_WEBHOOK_KEY= the UUID copied in Step 1
Send a test message:
# Plain text
tcb fn invoke wecomNotify \
--data '{"content":"CloudBase Cloud Function push test — if you see this message, the integration is working."}' \
-e your-env-id
# Markdown format
tcb fn invoke wecomNotify \
--data '{"msgtype":"markdown","content":"## Deploy Notification\n\n**getLoginTicket** updated\n\n> Version: v1.2.3"}' \
-e your-env-id
Check your WeCom group — you should see the bot's message.
Step 4 (Optional): Add a Timer Trigger
For a daily 9 AM data report, go to Console → Cloud Functions → wecomNotify → Trigger Methods → Timer Trigger and configure a Cron expression.
CloudBase uses a 7-field Cron format: Seconds Minutes Hours Day Month Weekday Year. Common examples:
| Need | Cron expression |
|---|---|
| Every day at 09:00 | 0 0 9 * * * * |
| Every hour on the hour | 0 0 * * * * * |
| Weekdays at 09:00 | 0 0 9 * * MON-FRI * |
On a timer trigger, the event has no content field. Handle this in the function — if no content is passed, generate the report automatically:
exports.main = async (event, context) => {
let content = event.content;
if (!content) {
// Timer trigger: generate report automatically
content = await generateDailyReport();
}
// ... push logic unchanged below
};
async function generateDailyReport() {
const cloudbase = require('@cloudbase/node-sdk');
const app = cloudbase.init({ env: process.env.TCB_ENV });
const db = app.database();
const yesterday = Date.now() - 24 * 60 * 60 * 1000;
const count = await db
.collection('orders')
.where({ createdAt: db.command.gte(yesterday) })
.count();
return `## Daily Report\n\nNew orders yesterday: **${count.total}**`;
}
Verification
tcb fn invoketo send a text message → appears in the grouptcb fn invoketo send a Markdown message → appears in the group with correct formatting- The API returns
{ "errcode": 0, "errmsg": "ok" }on success - If a timer trigger is configured, wait for one firing and check the group for the report
WeCom Webhook Supported Message Formats
Full list (source: WeCom official documentation):
msgtype value | Description |
|---|---|
text | Plain text, supports @mention (pass mentioned_list) |
markdown | Markdown, supports headings, bold, links, quotes, code blocks |
markdown_v2 | Enhanced Markdown with additional support for tables, etc. |
image | Image, pass base64-encoded content |
news | Graphic card — title, description, link, cover image |
file | File message |
voice | Voice message |
template_card | Template card, supports text_notice and news_notice subtypes |
This recipe's sample code covers text and markdown — the two most commonly used formats. For other formats, refer to the official documentation for parameter structure.
Common Errors
| Symptom | Cause | Fix |
|---|---|---|
errcode: 93000 | Webhook URL is invalid, or the bot has been removed from the group | Check the group in WeCom — if the bot was removed, re-add it and get a new key |
errcode: 45009 | API call rate exceeded (max 20 messages per minute per bot) | Consolidate messages or reduce push frequency |
| Function executes successfully but no message in group | Cloud Function lacks public internet access | Console → Cloud Functions → Basic Configuration → confirm "Public Internet Access" is enabled; if using a VPC, add a NAT gateway |
| Markdown formatting not applied | msgtype was sent as "text" instead of "markdown" | Check that event.msgtype is set correctly when invoking |
| Timer trigger not firing | Cron expression format error | CloudBase uses 7-field Cron (includes seconds and year) — confirm the format is correct |
Related Documentation
- WeCom Group Bot developer docs — Webhook API spec, full msgtype list
- CloudBase Cloud Function timer triggers — Cron expression configuration
- CloudBase Cloud Function basic configuration — public internet access, memory, timeout, etc.
Next Steps
- Optimize Cloud Function cold start:
optimize-cloud-function-wechat-miniprogram - Add authentication:
add-auth-wechat-miniprogram