> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/whiskeysockets/Baileys/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing Custom Functionality

> Extend Baileys by intercepting and handling custom WhatsApp protocol messages

Baileys is designed with extensibility in mind. Instead of forking the project and modifying internals, you can write custom extensions to handle specialized WhatsApp protocol messages.

## Overview

Custom functionality allows you to:

* Intercept specific WhatsApp protocol messages
* Handle custom binary nodes not processed by Baileys
* Track device state (battery, connectivity, etc.)
* Implement protocol-level features

## Enabling Debug Logging

First, enable debug-level logging to see all messages WhatsApp sends:

```typescript theme={null}
import makeWASocket from '@whiskeysockets/baileys'
import P from 'pino'

const sock = makeWASocket({
    logger: P({ level: 'debug' }),
})
```

For even more detailed protocol information, use `trace` level:

```typescript theme={null}
const sock = makeWASocket({
    logger: P({ level: 'trace' }),
})
```

<Info>
  At `trace` level, you'll see the full XML representation of each binary node sent and received.
</Info>

## Understanding WhatsApp Communication

WhatsApp uses binary nodes for communication. When debug logging is enabled, you'll see messages like:

```json theme={null}
{
    "level": 10,
    "fromMe": false,
    "frame": {
        "tag": "ib",
        "attrs": {
            "from": "@s.whatsapp.net"
        },
        "content": [
            {
                "tag": "edge_routing",
                "attrs": {},
                "content": [
                    {
                        "tag": "routing_info",
                        "attrs": {},
                        "content": {
                            "type": "Buffer",
                            "data": [8,2,8,5]
                        }
                    }
                ]
            }
        ]
    },
    "msg": "communication"
}
```

### Binary Node Structure

Each frame has three components:

* **`tag`** - Identifies what the frame is about (e.g., `message`, `ib`, `iq`)
* **`attrs`** - String key-value pairs with metadata (often contains message ID)
* **`content`** - The actual data (can be nested nodes, strings, or buffers)

See [Protocol Details](/advanced/protocol-details) for more information on binary node encoding.

## Registering Custom Callbacks

Use the WebSocket event system to register callbacks for specific message patterns:

```typescript theme={null}
import type { BinaryNode } from '@whiskeysockets/baileys'

// Listen for any message with tag 'edge_routing'
sock.ws.on('CB:edge_routing', (node: BinaryNode) => {
    console.log('Edge routing message received:', node)
})

// Listen for message with tag 'ib' and specific attributes
sock.ws.on('CB:ib,from:@s.whatsapp.net', (node: BinaryNode) => {
    console.log('IB message from WhatsApp server:', node)
})
```

See [WebSocket Events](/advanced/websocket-events) for detailed callback patterns.

## Example: Battery Tracking

Here's a complete example tracking your phone's battery percentage:

```typescript theme={null}
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@whiskeysockets/baileys'
import type { BinaryNode } from '@whiskeysockets/baileys'
import P from 'pino'
import { Boom } from '@hapi/boom'

const logger = P({ level: 'debug' })

async function startBatteryTracking() {
    const { state, saveCreds } = await useMultiFileAuthState('auth_info')
    
    const sock = makeWASocket({
        auth: state,
        logger,
        printQRInTerminal: true
    })

    // Register callback for battery status messages
    sock.ws.on('CB:ib,,notification', (node: BinaryNode) => {
        // Check if this is a battery notification
        const notificationNode = node.content?.[0]
        if (notificationNode && typeof notificationNode === 'object' && 
            notificationNode.tag === 'battery') {
            
            const batteryLevel = notificationNode.attrs?.value
            const isCharging = notificationNode.attrs?.live === '1'
            
            console.log(`Phone battery: ${batteryLevel}%`)
            console.log(`Charging: ${isCharging ? 'Yes' : 'No'}`)
        }
    })

    // Handle connection updates
    sock.ev.on('connection.update', (update) => {
        const { connection, lastDisconnect } = update
        if (connection === 'close') {
            const shouldReconnect = 
                (lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
            if (shouldReconnect) {
                startBatteryTracking()
            }
        } else if (connection === 'open') {
            console.log('Connected! Battery tracking active.')
        }
    })

    sock.ev.on('creds.update', saveCreds)
}

startBatteryTracking()
```

## Example: Custom Message Handler

Intercept and process custom protocol extensions:

```typescript theme={null}
// Handle custom business metadata
sock.ws.on('CB:ib,,business_profile', (node: BinaryNode) => {
    const profileNode = Array.isArray(node.content) 
        ? node.content.find(n => typeof n === 'object' && n.tag === 'business_profile')
        : null
    
    if (profileNode && typeof profileNode === 'object') {
        const businessData = {
            description: profileNode.attrs?.description,
            category: profileNode.attrs?.category,
            email: profileNode.attrs?.email,
            website: profileNode.attrs?.website
        }
        
        console.log('Business profile received:', businessData)
        // Store or process business data
    }
})
```

## Best Practices

<Note>
  **Selective Callbacks**: Register callbacks only for the messages you need to avoid performance overhead.
</Note>

<Warning>
  **Avoid Blocking Operations**: Keep callback functions fast and non-blocking. Use async operations or queue heavy processing.
</Warning>

```typescript theme={null}
// Good: Non-blocking callback
sock.ws.on('CB:message', async (node: BinaryNode) => {
    // Queue for background processing
    messageQueue.add(node)
})

// Bad: Blocking callback
sock.ws.on('CB:message', (node: BinaryNode) => {
    // Heavy synchronous processing
    processHeavyOperation(node) // Blocks event loop!
})
```

## TypeScript Types

Baileys exports TypeScript types for binary nodes:

```typescript theme={null}
import type { 
    BinaryNode, 
    BinaryNodeAttributes, 
    BinaryNodeData 
} from '@whiskeysockets/baileys'

const processNode = (node: BinaryNode) => {
    const tag: string = node.tag
    const attrs: BinaryNodeAttributes = node.attrs
    const content: BinaryNodeData = node.content
    
    // Content can be:
    // - BinaryNode[] (array of child nodes)
    // - string (text content)
    // - Uint8Array (binary data)
    // - undefined (no content)
}
```

## Debugging Tips

### Log Unhandled Messages

With debug logging enabled, Baileys logs unhandled messages:

```json theme={null}
{
    "unhandled": true,
    "msgId": "some-id",
    "fromMe": false,
    "frame": { ... },
    "msg": "communication recv"
}
```

These indicate protocol messages you might want to handle.

### Inspect Message Flow

Use trace-level logging to see both sent and received XML:

```typescript theme={null}
const sock = makeWASocket({
    logger: P({ 
        level: 'trace',
        transport: {
            target: 'pino-pretty',
            options: { colorize: true }
        }
    }),
})
```

## Learning Resources

<Info>
  To understand the WhatsApp protocol in depth, study:

  * **Libsignal Protocol** - End-to-end encryption
  * **Noise Protocol** - Handshake and session establishment
</Info>

## Next Steps

* [WebSocket Events](/advanced/websocket-events) - Detailed callback registration patterns
* [Protocol Details](/advanced/protocol-details) - Binary node encoding/decoding
* [Debugging](/advanced/debugging) - Troubleshooting and logging
