- FAQ
- Introduction
- Quick Start
- Comparisons
- Disclaimer
- Requirements
- Installation
- Code Editor
- Create Your App
- Authentication
- Listen To Events
- Message Replying
- Command Handling
- Messages
- Chats
- Groups
- Contacts
- Channels
- Polls
- Orders
- Payments
- Multi Device
- Presence and Profile
Decision objective
Use a strategy that matches your runtime constraints:
- low friction local development,
- stable single host production,
- distributed runtime with shared session persistence.
The three strategies
NoAuth
No persistent session. Every restart requires a new login.
Best for:
- quick experiments,
- temporary testing,
- disposable local runs.
LocalAuth
Persists session data in local filesystem, by default under .wwebjs_auth.
Best for:
- local development,
- single machine servers with persistent storage,
- simple production topology.
RemoteAuth
Persists session data through a store adapter in remote storage.
Best for:
- containers and ephemeral hosts,
- multi instance deployments,
- central session management.
Decision logic
- If filesystem is not durable, use
RemoteAuth. - If you run one persistent machine, use
LocalAuth. - If you only test quickly, use
NoAuth.
Minimal examples
NoAuth
const { Client, NoAuth } = require('whatsapp-web.js')
const client = new Client({
authStrategy: new NoAuth(),
})
client.initialize()LocalAuth
const { Client, LocalAuth } = require('whatsapp-web.js')
const client = new Client({
authStrategy: new LocalAuth({
clientId: 'main',
}),
})
client.initialize()RemoteAuth
const { Client, RemoteAuth } = require('whatsapp-web.js')
const { MongoStore } = require('wwebjs-mongo')
const mongoose = require('mongoose')
async function main() {
await mongoose.connect(process.env.MONGODB_URI)
const client = new Client({
authStrategy: new RemoteAuth({
store: new MongoStore({ mongoose }),
clientId: 'main',
backupSyncIntervalMs: 300000,
}),
})
client.initialize()
}
main()Events you should always track
qrauthenticatedauth_failurereadydisconnected- for remote auth, also
remote_session_saved
Without these signals, incident analysis becomes difficult.
LocalAuth
LocalAuth stores the WhatsApp session in a local folder (.wwebjs_auth by default). After the first login, subsequent restarts restore the session automatically, no QR code needed.
Setup
LocalAuth is built into whatsapp-web.js. No extra packages required.
const { Client, LocalAuth } = require('whatsapp-web.js')
const client = new Client({
authStrategy: new LocalAuth(),
})
client.on('qr', qr => {
console.log('First run, scan this QR code')
})
client.on('ready', () => {
console.log('Ready!')
})
client.initialize()What Gets Created
After the first successful login, a .wwebjs_auth directory appears next to your app file:
Add .wwebjs_auth to your .gitignore to avoid accidentally committing session data.
Options
const client = new Client({
authStrategy: new LocalAuth({
clientId: 'my-app', // Unique name - lets multiple apps share one machine
dataPath: './sessions', // Where to store session files (default: ./.wwebjs_auth)
}),
})clientId
When you run more than one app on the same machine, give each a different clientId so their sessions don't overwrite each other:
// app 1
const client1 = new Client({
authStrategy: new LocalAuth({ clientId: 'support-app' }),
})
// app 2
const client2 = new Client({
authStrategy: new LocalAuth({ clientId: 'sales-app' }),
})This creates separate folders: .wwebjs_auth/support-app/ and .wwebjs_auth/sales-app/.
First Run vs Subsequent Runs
First run:
qrevent fires - scan with your phone- Session is saved to disk
authenticatedthenreadyfires
Subsequent runs:
- Session is restored from disk
authenticatedthenreadyfires - no QR code
client.on('qr', qr => {
// This only fires on first run (or if session expires)
console.log('Scan QR code')
})
client.on('ready', () => {
console.log('Ready!')
})Limitations
- One instance per
clientId: Two processes with the sameclientIdwill conflict. - Tied to the filesystem: Moving the app to a different server means copying the session folder.
- Not suitable for containers: If the container is recreated, the session is lost. Use RemoteAuth instead.
RemoteAuth
RemoteAuth saves sessions to a remote store, a database or cloud storage service. This makes it suitable for Docker, Kubernetes, serverless, and any setup where the local filesystem cannot be trusted to persist data.
When to Use RemoteAuth
- Your app runs in a container that can be recreated
- You need more than one app instance sharing the same account
- You deploy to a platform without persistent disk (e.g. Heroku, Railway, serverless)
Installation
RemoteAuth itself is built in, but it needs three helper packages and a store adapter:
Then install the adapter for your storage backend:
# MongoDB
npm install wwebjs-mongo mongoose
# AWS S3
npm install wwebjs-aws-s3 aws-sdkWith MongoDB
const { Client, RemoteAuth } = require('whatsapp-web.js')
const { MongoStore } = require('wwebjs-mongo')
const mongoose = require('mongoose')
async function start() {
await mongoose.connect(process.env.MONGODB_URL)
const client = new Client({
authStrategy: new RemoteAuth({
store: new MongoStore({ mongoose }),
backupSyncIntervalMs: 600000, // Sync every 10 minutes
}),
})
client.on('qr', qr => {
console.log('Scan QR code')
})
client.on('ready', () => {
console.log('Ready!')
})
client.initialize()
}
start()Options
new RemoteAuth({
store, // Required, the storage adapter instance
clientId: 'my-app', // Unique ID when running multiple instances
dataPath: './sessions', // Temporary local path during sync
backupSyncIntervalMs: 600000, // How often to sync (minimum 60000 ms)
})backupSyncIntervalMs
Sessions are synced to the remote store on an interval while the app is running. The minimum allowed value is 60000 (1 minute). For most apps, 5–10 minutes (300000–600000) is a good balance.
clientId
Lets you run multiple apps against the same remote store without them overwriting each other's sessions:
const clientA = new Client({
authStrategy: new RemoteAuth({
store: myStore,
clientId: 'app-a',
}),
})
const clientB = new Client({
authStrategy: new RemoteAuth({
store: myStore,
clientId: 'app-b',
}),
})Session Lifecycle Events
client.on('remote_session_saved', () => {
console.log('Session backed up to remote store')
})
client.on('disconnected', reason => {
console.log('Disconnected:', reason)
// Re-initialize or exit depending on your strategy
})Best Practices
- Store database credentials in environment variables, never in source code
- Set
backupSyncIntervalMslow enough that a crash won't lose too much session state - Handle
disconnectedto restart or alert on unexpected disconnections
On This Page
clientIdFirst Run vs Subsequent RunsLimitationsRemoteAuthWhen to Use RemoteAuthInstallationWith MongoDBOptionsbackupSyncIntervalMsclientIdSession Lifecycle EventsBest Practices