npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

sulyap-fca

v1.3.7

Published

Sulyap - Unofficial Facebook Chat API for Node.js. A fully-featured, reverse-engineered Facebook Messenger API library with TypeScript support, MQTT for Group Chat and Private Messages, anti-ban protection, and command handler support.

Readme

Sulyap - Complete Facebook Chat API Library

   ███████╗██╗   ██╗██╗  ██╗   ██╗ █████╗ ██████╗ 
   ██╔════╝██║   ██║██║  ╚██╗ ██╔╝██╔══██╗██╔══██╗
   ███████╗██║   ██║██║   ╚████╔╝ ███████║██████╔╝
   ╚════██║██║   ██║██║    ╚██╔╝  ██╔══██║██╔═══╝ 
   ███████║╚██████╔╝███████╗██║   ██║  ██║██║     
   ╚══════╝ ╚═════╝ ╚══════╝╚═╝   ╚═╝  ╚═╝╚═╝     

Unofficial Facebook Chat API for Node.js

npm version License: MIT Node.js TypeScript


Ang Sulyap ay isang complete unofficial Facebook Chat API library na ginawa para sa mga Filipino developers na nais gumawa ng automated bots at applications para sa Facebook Messenger. Ito ay lubos na sumusuporta sa Messenger Groups, Private Messages, at iba't ibang uri ng conversations gamit ang personal Facebook accounts.

IMPORTANT: Sulyap ay gumagamit ng unofficial/reverse-engineered API. Ito ay direct na nakikipag-communicate sa Facebook Messenger servers gamit ang private endpoints at protocols na ginagamit ng Facebook mobile/web apps.


Installation

npm install sulyap-fca

Quick Start

Using Async/Await (Recommended)

const login = require('sulyap-fca');
const fs = require('fs');

async function startBot() {
    const appState = JSON.parse(fs.readFileSync('appstate.json', 'utf8'));

    try {
        const api = await login({ appState });
        console.log('Logged in as:', api.getCurrentUserID());

        api.listenMqtt((err, event) => {
            if (err) return console.error(err);

            if (event.type === 'message') {
                console.log(`${event.senderID}: ${event.body}`);
                
                if (event.body === '/ping') {
                    api.sendMessage('Pong!', event.threadID);
                }
            }
        });
    } catch (err) {
        console.error('Login failed:', err);
    }
}

startBot();

Using Callback (Legacy)

const login = require('sulyap-fca');
const fs = require('fs');

const appState = JSON.parse(fs.readFileSync('appstate.json', 'utf8'));

login({ appState }, (err, api) => {
    if (err) return console.error(err);

    console.log('Logged in as:', api.getCurrentUserID());

    api.listenMqtt((err, event) => {
        if (err) return console.error(err);

        if (event.type === 'message') {
            console.log(`${event.senderID}: ${event.body}`);
            
            if (event.body === '/ping') {
                api.sendMessage('Pong!', event.threadID);
            }
        }
    });
});

Complete API Functions

All API methods now use async/await and return Promises. No more callbacks needed!

Core Functions

| Function | Return Type | Description | |----------|-------------|-------------| | login(credentials) | Promise<Api> | Main login function for authentication | | api.getAppState() | AppState | Get current session cookies/appState | | api.getCurrentUserID() | string | Get the user ID of currently logged-in account | | await api.logout() | Promise<void> | Logout and clear session | | api.setOptions(options) | void | Configure API behavior |

Messaging Functions

| Function | Return Type | Description | |----------|-------------|-------------| | await api.sendMessage(message, threadID, replyToMessage?) | Promise<MessageInfo> | Send text, attachments, stickers, URLs, emojis | | await api.sendTypingIndicator(threadID) | Promise<{end: () => void}> | Send typing indicator | | await api.setMessageReaction(reaction, messageID, forceCustom?) | Promise<void> | React to messages with emoji | | await api.unsendMessage(messageID) | Promise<void> | Unsend/delete sent messages | | await api.editMessage(newMessage, messageID) | Promise<void> | Edit previously sent messages | | await api.forwardAttachment(attachmentID, users) | Promise<void> | Forward attachments to other users |

Group/Thread Management

| Function | Return Type | Description | |----------|-------------|-------------| | await api.addUserToGroup(userID, threadID) | Promise<void> | Add user(s) to group chat | | await api.removeUserFromGroup(userID, threadID) | Promise<void> | Remove user from group chat | | await api.changeAdminStatus(threadID, adminIDs, status) | Promise<void> | Promote/demote admins | | await api.changeGroupImage(image, threadID) | Promise<void> | Change group profile picture | | await api.changeNickname(nickname, threadID, userID) | Promise<void> | Change user nickname in thread | | await api.changeThreadColor(color, threadID) | Promise<void> | Change thread color theme | | await api.changeThreadEmoji(emoji, threadID) | Promise<void> | Change default thread emoji | | await api.setTitle(newTitle, threadID) | Promise<void> | Change group chat name | | await api.muteThread(threadID, muteSeconds) | Promise<void> | Mute thread notifications | | await api.createNewGroup(participantIDs, title?) | Promise<ThreadInfo> | Create new group chat | | await api.createPoll(title, threadID, options) | Promise<void> | Create poll in thread | | await api.changeArchivedStatus(threads, archive) | Promise<void> | Archive/unarchive threads | | await api.changeBlockedStatus(userID, block) | Promise<void> | Block/unblock user | | await api.deleteThread(threads) | Promise<void> | Delete conversation(s) | | await api.handleMessageRequest(threadID, accept) | Promise<void> | Accept/decline message requests | | await api.changeApprovalMode(approve, threadID) | Promise<void> | Enable/disable group approval mode |

Message Status Functions

| Function | Return Type | Description | |----------|-------------|-------------| | await api.markAsRead(threadID) | Promise<void> | Mark messages as read | | await api.markAsReadAll() | Promise<void> | Mark all messages as read | | await api.markAsSeen() | Promise<void> | Mark inbox as seen | | await api.markAsDelivered(threadID, messageID) | Promise<void> | Mark message as delivered |

Information Retrieval

| Function | Return Type | Description | |----------|-------------|-------------| | await api.getUserID(name) | Promise<Array<{userID, name, profilePicture}>> | Get user ID from name | | await api.getUserInfo(userIDs) | Promise<Record<string, UserInfo>> | Get detailed user information | | await api.getFriendsList() | Promise<Friend[]> | Get complete friends list | | await api.getThreadInfo(threadID) | Promise<ThreadInfo> | Get thread/conversation details | | await api.getThreadList(limit, timestamp, tags) | Promise<ThreadInfo[]> | Get list of conversations | | await api.getThreadHistory(threadID, amount, timestamp?) | Promise<Message[]> | Get message history | | await api.getThreadPictures(threadID, offset, limit) | Promise<any[]> | Get photos shared in thread | | await api.getEmojiUrl(emoji, size) | Promise<string> | Get URL of emoji image | | await api.searchForThread(query) | Promise<ThreadInfo[]> | Search for threads by name | | await api.resolvePhotoUrl(photoID) | Promise<string> | Get direct URL of photo |

Listen Functions (Callback-Based by Design)

Listener methods remain callback-based because they emit continuous event streams. This is the industry-standard pattern for real-time subscriptions (similar to Firebase onSnapshot, WebSocket clients, etc.). Promises are unsuitable for unbounded multi-event flows.

| Function | Returns | Description | |----------|---------|-------------| | api.listen(callback) | () => void | Listen using HTTP polling (legacy). Returns stop function. | | api.listenMqtt(callback) | () => void | Listen using MQTT (recommended, auto anti-ban). Returns stop function. | | api.getProtectionStats() | object | Get anti-ban/anti-detection protection statistics | | api.getCookieRefreshStats() | object | Get cookie refresh statistics |


Usage Examples

Sending Messages

// Simple text message
const info = await api.sendMessage('Hello, World!', threadID);
console.log('Message sent:', info.messageID);

// Reply to a message
const reply = await api.sendMessage('This is a reply!', threadID, originalMessageID);

// Message with mentions
await api.sendMessage({
    body: 'Hello @John!',
    mentions: [{
        tag: '@John',
        id: '123456789',
        fromIndex: 6
    }]
}, threadID);

// Send sticker
await api.sendMessage({ sticker: '767334476626295' }, threadID);

// Send URL
await api.sendMessage({ url: 'https://example.com' }, threadID);

// Send emoji with size
await api.sendMessage({
    emoji: '👍',
    emojiSize: 'large' // 'small', 'medium', 'large'
}, threadID);

Getting Information

// Get thread info (Group Chat or PM)
const threadInfo = await api.getThreadInfo(threadID);
console.log('Thread name:', threadInfo.threadName);
console.log('Participants:', threadInfo.participantIDs);
console.log('Admins:', threadInfo.adminIDs);
console.log('Is Group:', threadInfo.isGroup);

// Get user info
const userInfo = await api.getUserInfo(['123456789', '987654321']);
for (const [userId, info] of Object.entries(userInfo)) {
    console.log(`${info.name} (${userId})`);
}

// Get friends list
const friends = await api.getFriendsList();
console.log(`You have ${friends.length} friends`);

// Get thread list
const threads = await api.getThreadList(20, null, ['INBOX']);
for (const thread of threads) {
    console.log(`${thread.threadName}: ${thread.snippet}`);
}

// Get message history
const messages = await api.getThreadHistory(threadID, 50);
for (const msg of messages) {
    console.log(`${msg.senderID}: ${msg.body}`);
}

Message Reactions

// React with emoji directly
await api.setMessageReaction('❤️', messageID);

// Use reaction shortcuts
await api.setMessageReaction(':love:', messageID);    // 😍
await api.setMessageReaction(':haha:', messageID);    // 😆
await api.setMessageReaction(':wow:', messageID);     // 😮
await api.setMessageReaction(':sad:', messageID);     // 😢
await api.setMessageReaction(':angry:', messageID);   // 😠
await api.setMessageReaction(':like:', messageID);    // 👍
await api.setMessageReaction(':dislike:', messageID); // 👎
await api.setMessageReaction(':heart:', messageID);   // ❤
await api.setMessageReaction(':glowingheart:', messageID); // 💗

// Remove reaction
await api.setMessageReaction('', messageID);

// Force custom emoji (bypass validation)
await api.setMessageReaction('🔥', messageID, true);

Group Management

// Add users to group
await api.addUserToGroup(['123456789', '987654321'], threadID);

// Remove user from group
await api.removeUserFromGroup('123456789', threadID);

// Make someone admin
await api.changeAdminStatus(threadID, '123456789', true);

// Remove admin status
await api.changeAdminStatus(threadID, '123456789', false);

// Change group name
await api.setTitle('New Group Name', threadID);

// Change thread color
await api.changeThreadColor('#0084FF', threadID);

// Change thread emoji
await api.changeThreadEmoji('🚀', threadID);

// Change nickname
await api.changeNickname('Cool Name', threadID, '123456789');

// Create new group
const newGroup = await api.createNewGroup(['123456789', '987654321'], 'My New Group');

// Create poll
await api.createPoll('What should we do?', threadID, {
    'Option 1': false,
    'Option 2': false,
    'Option 3': true // Pre-selected
});

// Enable approval mode
await api.changeApprovalMode(true, threadID);

Event Types

When using listenMqtt, you'll receive various event types:

api.listenMqtt((err, event) => {
    if (err) return console.error(err);

    switch (event.type) {
        case 'message':
            // New message received (Group Chat or PM)
            console.log(`From ${event.senderID}: ${event.body}`);
            console.log(`Thread: ${event.threadID}`);
            console.log(`Is Group: ${event.isGroup}`);
            break;
            
        case 'message_reaction':
            // Someone reacted to a message
            console.log(`${event.senderID} reacted with ${event.reaction}`);
            break;
            
        case 'message_unsend':
            // Message was unsent/deleted
            console.log(`Message ${event.messageID} was unsent`);
            break;
            
        case 'typ':
            // Typing indicator
            console.log(`${event.from} is ${event.isTyping ? 'typing' : 'stopped typing'}`);
            break;
            
        case 'read_receipt':
            // Read receipt
            console.log(`${event.reader} read messages in ${event.threadID}`);
            break;
            
        case 'presence':
            // Online/offline status
            console.log(`${event.userID} is ${event.statuses ? 'online' : 'offline'}`);
            break;
            
        case 'event':
            // Group events (title change, member added/removed, etc.)
            console.log(`Event: ${event.logMessageType}`);
            break;
    }
});

Complete Bot Example

const login = require('sulyap-fca');
const fs = require('fs');

async function startBot() {
    const appState = JSON.parse(fs.readFileSync('appstate.json', 'utf8'));
    
    try {
        const api = await login({ appState });
        console.log('Bot started! User ID:', api.getCurrentUserID());

        api.listenMqtt(async (err, event) => {
            if (err) return console.error(err);
            if (event.type !== 'message' || !event.body) return;

            const body = event.body.toLowerCase();
            const threadID = event.threadID;

            // Ping command
            if (body === '/ping') {
                await api.sendMessage('Pong! 🏓', threadID);
            }

            // Get group info command
            if (body === '/info') {
                const info = await api.getThreadInfo(threadID);
                const response = [
                    `📋 Thread Info`,
                    `Name: ${info.threadName || 'N/A'}`,
                    `Type: ${info.isGroup ? 'Group Chat' : 'Private Message'}`,
                    `Participants: ${info.participantIDs.length}`,
                    `Admins: ${info.adminIDs.length}`,
                    `Messages: ${info.messageCount}`,
                ].join('\n');
                await api.sendMessage(response, threadID);
            }

            // Admin list command
            if (body === '/adminlist') {
                const info = await api.getThreadInfo(threadID);
                if (info.adminIDs.length > 0) {
                    const userInfo = await api.getUserInfo(info.adminIDs);
                    const adminNames = Object.values(userInfo).map(u => u.name).join(', ');
                    await api.sendMessage(`👑 Admins: ${adminNames}`, threadID);
                } else {
                    await api.sendMessage('No admins in this thread.', threadID);
                }
            }

            // User info command
            if (body.startsWith('/user ')) {
                const name = body.slice(6);
                const users = await api.getUserID(name);
                if (users.length > 0) {
                    const response = users.map(u => `${u.name} (${u.userID})`).join('\n');
                    await api.sendMessage(`🔍 Found:\n${response}`, threadID);
                } else {
                    await api.sendMessage('No users found.', threadID);
                }
            }
        });

    } catch (err) {
        console.error('Failed to start bot:', err);
    }
}

startBot();

API Options

const api = await login({ appState }, {
    logLevel: 'info',
    selfListen: false,
    listenEvents: true,
    online: true,
    updatePresence: true,
    forceLogin: false,
    userAgent: 'Mozilla/5.0 ...',
    autoMarkDelivery: true,
    autoMarkRead: false,
    proxy: 'http://proxy:8080',
    cookieRefreshInterval: 20000,
    sessionRotationInterval: 14400000,
    autoRotateSession: true,
});

Features

Anti-Ban System (Automatic)

Sulyap includes a comprehensive anti-ban protection system that is automatically enabled when you use listenMqtt(). No configuration needed!

  • Automatic Cookie Refresh - Refreshes cookies every 20 seconds to prevent session expiration
  • Session Fingerprint Rotation - Automatically rotates session fingerprints every 4 hours
  • Multiple Refresh Endpoints - Uses randomized Facebook endpoints for cookie refresh
  • Connection Keep-Alive - Maintains persistent connection to prevent timeout
  • Meta Platform Compatible - Updated for latest Meta/Facebook security measures
// Anti-ban is AUTOMATICALLY ENABLED - just use listenMqtt!
api.listenMqtt((err, event) => {
    // Protection is active - cookies auto-refresh every 20s
    console.log(event);
});

// Check protection status anytime
const stats = api.getProtectionStats();
console.log('Anti-ban active:', stats.enabled);
console.log('Cookie refreshes:', stats.cookieRefreshCount);

Full Messenger Support

  • Group Chats - Full support for all group chat operations
  • Private Messages (PM) - Complete support for 1-on-1 conversations
  • Message Requests - Handle incoming message requests
  • Attachments - Photos, videos, audio, files, stickers, GIFs, shares
  • Reactions - Send and receive message reactions
  • Typing Indicators - Real-time typing status
  • Read Receipts - Track message read status
  • Presence - Online/offline status updates

Compatibility

  • Node.js: 20.x+
  • OS: Windows, macOS, Linux, Docker
  • Cloud: Heroku, Replit, Railway, Render, AWS, GCP, Azure

Getting AppState

There are several ways to get your Facebook appState:

  1. c3c-fbstate - Browser extension to export cookies
  2. EditThisCookie - Chrome extension for cookie management
  3. Manual extraction - Use browser DevTools to copy cookies

AppState Format

[
    {
        "key": "c_user",
        "value": "123456789",
        "domain": ".facebook.com",
        "path": "/"
    },
    {
        "key": "xs",
        "value": "...",
        "domain": ".facebook.com",
        "path": "/"
    }
]

Important Notes

Disclaimer: Ito ay unofficial library at HINDI affiliated sa Meta/Facebook. Ginagamit nito ang reverse-engineered protocols ng Facebook Messenger para sa personal Facebook accounts.

Account Safety:

  • Gamitin ng responsibly
  • Sundin ang Facebook Terms of Service
  • Huwag gawing spam tool
  • Maaaring ma-ban ang account kung hindi ginagamit ng tama

Anti-Detection: Kahit may advanced anti-detection features, walang 100% guarantee na hindi ma-detect. Use at your own risk.


License

MIT License - Free to use, modify, and distribute.


Credits


Sulyap - The complete Facebook Chat API solution with 30+ async/await functions for full Messenger automation!