The Updates module provides a unified interface for receiving events from VK using User Long Poll, Bots Long Poll, or Callback API (webhooks).
Initialization
import { API , Upload , Updates } from 'vk-io' ;
const api = new API ({
token: process . env . VK_TOKEN
});
const upload = new Upload ({ api });
const updates = new Updates ({
api ,
upload
});
Configuration Options
API instance for making requests
Upload instance for file operations
Time to wait (in ms) before re-querying Long Poll
Number of retries for failed polling requests
Group ID for Bots Long Poll (required for group bots)
Secret key for webhook request validation
Confirmation code for Callback API setup
Event Handling
Subscribe to Events
Use the on() method to handle specific event types:
updates . on ( 'message_new' , async ( context ) => {
console . log ( 'New message:' , context . text );
await context . send ( 'Hello!' );
});
Event Types vs Subtypes
Events have both a type (main category) and subtypes (specific events):
// Subscribe by main type - receives ALL message events
updates . on ( 'message' , ( context ) => {
console . log ( context . type ); // 'message'
console . log ( context . subTypes ); // ['message_new', 'message_edit', etc.]
});
// Subscribe by subtype - receives only new messages
updates . on ( 'message_new' , ( context ) => {
console . log ( context . subTypes ); // ['message_new']
});
Multiple Event Types
// Listen to multiple events
updates . on ([ 'message_new' , 'message_edit' ], ( context ) => {
console . log ( 'Message created or edited' );
});
Available Events
Message Events
message_new
message_edit
message_reply
updates . on ( 'message_new' , ( context ) => {
console . log ( 'New message from:' , context . senderId );
console . log ( 'Text:' , context . text );
});
Group Events
updates . on ( 'group_join' , ( context ) => {
console . log ( 'User joined:' , context . userId );
});
updates . on ( 'group_leave' , ( context ) => {
console . log ( 'User left:' , context . userId );
});
Wall Events
updates . on ([ 'wall_post_new' , 'wall_repost' ], ( context ) => {
console . log ( 'Wall post:' , context . wall . text );
});
updates . on ([
'photo_comment_new' ,
'video_comment_new' ,
'wall_reply_new'
], ( context ) => {
console . log ( 'New comment:' , context . text );
});
Other Events
message_event - Callback button pressed
message_allow / message_deny - Message subscription changes
typing - User is typing
photo_new / video_new / audio_new - New media
poll_vote_new - New poll vote
user_block / user_unblock - User blocked/unblocked
like_add / like_remove - Like added/removed
market_order_new / market_order_edit - Market order events
donut_subscription_* - Donut subscription events
Middleware Pattern
Updates use middleware chains instead of EventEmitter:
// Middleware that modifies context
updates . use ( async ( context , next ) => {
context . state . startTime = Date . now ();
await next (); // Pass to next middleware
const duration = Date . now () - context . state . startTime ;
console . log ( `Processed in ${ duration } ms` );
});
// Middleware that filters events
updates . use ( async ( context , next ) => {
// Only process messages from specific user
if ( context . is ( 'message' ) && context . senderId === 123456 ) {
return next ();
}
});
// Handler receives modified context
updates . on ( 'message_new' , ( context ) => {
console . log ( 'Start time:' , context . state . startTime );
});
Always return a Promise from middleware. Use async functions or explicitly return next().
Middleware Best Practices
// BAD: Blocks all events
updates . use (( context , next ) => {
if ( ! context . isOutbox ) {
return ; // Stops all non-message events!
}
return next ();
});
// GOOD: Check event type first
updates . use (( context , next ) => {
if ( context . is ( 'message' ) && ! context . isOutbox ) {
return ;
}
return next ();
});
// BETTER: Use specific event handler
updates . on ( 'message' , ( context , next ) => {
if ( ! context . isOutbox ) {
return ;
}
return next ();
});
Starting Updates
Auto-Detection Mode
Automatically detects whether to use polling or webhook:
Long Poll (User/Group)
User Long Poll
Bots Long Poll
For user accounts: const api = new API ({
token: process . env . USER_TOKEN
});
const updates = new Updates ({ api , upload });
updates . on ( 'message_new' , ( context ) => {
console . log ( 'Message:' , context . text );
});
await updates . startPolling ();
console . log ( 'User Long Poll started' );
User Long Poll provides fewer events and less complete data.
For community bots: const api = new API ({
token: process . env . GROUP_TOKEN
});
const updates = new Updates ({
api ,
upload ,
pollingGroupId: 123456789 // Your group ID
});
updates . on ( 'message_new' , ( context ) => {
console . log ( 'Message:' , context . text );
});
await updates . startPolling ();
console . log ( 'Bots Long Poll started' );
Webhook (Callback API)
Built-in Server
Express Middleware
Koa Middleware
Start a standalone HTTP server: const updates = new Updates ({
api ,
upload ,
webhookSecret: 'your_secret_key' ,
webhookConfirmation: 'your_confirmation_code'
});
updates . on ( 'message_new' , ( context ) => {
console . log ( 'Message:' , context . text );
});
await updates . startWebhook ({
port: 8080 ,
host: '0.0.0.0' ,
path: '/webhook'
});
console . log ( 'Webhook server listening on :8080/webhook' );
Integrate with Express.js: import express from 'express' ;
const app = express ();
const updates = new Updates ({
api ,
upload ,
webhookSecret: 'your_secret_key' ,
webhookConfirmation: 'your_confirmation_code'
});
updates . on ( 'message_new' , ( context ) => {
console . log ( 'Message:' , context . text );
});
// Add webhook route
app . post ( '/webhook' , updates . getWebhookCallback ());
app . listen ( 3000 );
Integrate with Koa.js: import Koa from 'koa' ;
import bodyParser from 'koa-bodyparser' ;
const app = new Koa ();
const updates = new Updates ({
api ,
upload ,
webhookSecret: 'your_secret_key' ,
webhookConfirmation: 'your_confirmation_code'
});
updates . on ( 'message_new' , ( context ) => {
console . log ( 'Message:' , context . text );
});
app . use ( bodyParser ());
app . use ( updates . getKoaWebhookMiddleware ());
app . listen ( 3000 );
HTTPS Webhook
import { readFileSync } from 'fs' ;
await updates . startWebhook ({
port: 443 ,
path: '/webhook' ,
tls: {
key: readFileSync ( './privkey.pem' ),
cert: readFileSync ( './cert.pem' )
}
});
Webhook Setup in VK
Go to Community Settings → API Usage → Callback API
Set API Version to 5.199 or higher
Add server URL: https://yourdomain.com/webhook
Copy Confirmation Code to webhookConfirmation option
Set Secret Key to webhookSecret option
Enable required event types
Stopping Updates
// Stop receiving updates
await updates . stop ();
Error Handling
import { Composer } from 'vk-io' ;
const updates = new Updates ({
api ,
upload
});
// Global error handler
updates . use ( async ( context , next ) => {
try {
await next ();
} catch ( error ) {
console . error ( 'Error processing update:' , error );
if ( context . is ( 'message' )) {
await context . send ( 'An error occurred' );
}
}
});
updates . on ( 'message_new' , async ( context ) => {
// This error will be caught by middleware above
throw new Error ( 'Something went wrong' );
});
Manual Update Dispatch
Process updates manually:
// Handle webhook update
const webhookUpdate = {
type: 'message_new' ,
object: { /* message data */ },
group_id: 123456
};
await updates . handleWebhookUpdate ( webhookUpdate );
// Handle polling update
const pollingUpdate = [ 10004 , /* ...update data */ ];
await updates . handlePollingUpdate ( pollingUpdate );
Checking Status
if ( updates . isStarted ) {
console . log ( 'Updates are running' );
await updates . stop ();
}
Long Poll Configuration
The polling transport uses specific configuration:
Version : 19 (User Long Poll)
Mode flags :
2 - Receive attachments
8 - Return extended events
64 - Return online user platform ID
128 - Return random_id
Wait time : 25 seconds per request
Webhooks are recommended for production bots as they’re more reliable and don’t require constant polling.