Introduction
NapCat implements the OneBot 11 event system to notify your application about various activities in QQ. Events are sent to your bot via the configured network adapter (HTTP POST, WebSocket, or Webhook) whenever something happens.
Event Structure
All OneBot 11 events share a common base structure:
Unix timestamp (in seconds) when the event occurred
The type of event. Possible values:
message - Message events
message_sent - Message sent by the bot
notice - Notice events
request - Request events
meta_event - Meta events (heartbeat, lifecycle)
Event Types
Message Events
Message events are triggered when the bot receives a message. There are two main types:
- Private Messages - Direct messages from friends or temporary chats
- Group Messages - Messages in group chats
Learn more in Message Events.
Notice Events
Notice events inform your bot about various activities and changes:
- Group member changes (join, leave, kick)
- Admin status changes
- Group file uploads
- Message recalls
- Friend additions
- Poke/nudge actions
- Group bans and mutes
- And many more
Learn more in Notice Events.
Request Events
Request events occur when someone wants to interact with the bot:
- Friend requests
- Group invitations
- Group join requests
Learn more in Request Events.
Meta events provide information about the bot’s status:
- Heartbeat - Periodic status updates
- Lifecycle - Bot startup and shutdown events
Receiving Events
HTTP POST
When using HTTP POST adapter, events are sent as POST requests to your configured URL:
POST /your-endpoint
Content-Type: application/json
{
"time": 1709641234,
"self_id": 123456789,
"post_type": "message",
"message_type": "private",
"sub_type": "friend",
"message_id": 123456,
"user_id": 987654321,
"message": [
{
"type": "text",
"data": {
"text": "Hello!"
}
}
],
"raw_message": "Hello!",
"font": 14,
"sender": {
"user_id": 987654321,
"nickname": "Friend Name",
"sex": "unknown",
"age": 0
}
}
WebSocket
With WebSocket adapter, events are pushed to connected clients in real-time:
const ws = new WebSocket('ws://localhost:3001');
ws.on('message', (data) => {
const event = JSON.parse(data);
console.log('Received event:', event.post_type);
// Handle different event types
if (event.post_type === 'message') {
// Handle message
} else if (event.post_type === 'notice') {
// Handle notice
} else if (event.post_type === 'request') {
// Handle request
}
});
Webhook
Webhook works similarly to HTTP POST but with additional configuration options for authentication and filtering.
Event Handling Best Practices
1. Check Event Types
Always check the post_type field to determine how to handle the event:
function handleEvent(event) {
switch (event.post_type) {
case 'message':
return handleMessage(event);
case 'notice':
return handleNotice(event);
case 'request':
return handleRequest(event);
case 'meta_event':
return handleMeta(event);
default:
console.warn('Unknown event type:', event.post_type);
}
}
2. Use Sub-types for Specific Logic
Most events have a sub-type field for more granular handling:
function handleNotice(event) {
if (event.notice_type === 'group_increase') {
console.log(`New member ${event.user_id} joined group ${event.group_id}`);
} else if (event.notice_type === 'group_decrease') {
console.log(`Member ${event.user_id} left group ${event.group_id}`);
}
}
3. Handle Errors Gracefully
Always implement error handling for event processing:
try {
await processEvent(event);
} catch (error) {
console.error('Error processing event:', error);
// Log for debugging but don't crash
}
4. Respond to Events
Some events support quick operations by returning a response:
// HTTP POST handler
app.post('/event', (req, res) => {
const event = req.body;
if (event.post_type === 'message') {
// Quick reply by returning action
res.json({
reply: 'Auto reply message',
at_sender: true // For group messages
});
} else {
res.status(204).send(); // No response needed
}
});
Example: Complete Event Handler
Here’s a complete example of handling different event types:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/napcat', async (req, res) => {
const event = req.body;
try {
switch (event.post_type) {
case 'message':
if (event.message_type === 'private') {
console.log(`Private message from ${event.user_id}: ${event.raw_message}`);
} else if (event.message_type === 'group') {
console.log(`Group message in ${event.group_id} from ${event.user_id}: ${event.raw_message}`);
}
break;
case 'notice':
if (event.notice_type === 'group_increase') {
console.log(`Welcome new member ${event.user_id} to group ${event.group_id}`);
} else if (event.notice_type === 'group_recall') {
console.log(`Message ${event.message_id} was recalled in group ${event.group_id}`);
}
break;
case 'request':
if (event.request_type === 'friend') {
console.log(`Friend request from ${event.user_id}: ${event.comment}`);
// You can approve by calling set_friend_add_request API
} else if (event.request_type === 'group') {
console.log(`Group request for ${event.group_id} from ${event.user_id}`);
}
break;
case 'meta_event':
if (event.meta_event_type === 'heartbeat') {
console.log('Heartbeat:', event.status);
}
break;
}
res.status(204).send();
} catch (error) {
console.error('Error handling event:', error);
res.status(500).send();
}
});
app.listen(5700, () => {
console.log('Event server listening on port 5700');
});
Next Steps