A node.js package for automating Facebook Messenger bot, and is one of the most advanced next-generation Facebook Chat API (FCA) by @PrinceMalhotra
npm install fca-prince-malhotra💁 fca-prince-malhotra is a fully refactored Facebook Chat API (FCA) client built for reliable, real-time, and modular interaction with Facebook Messenger. Designed with modern bot development in mind, it offers full control over Messenger automation through a clean, stable interface.
---
Full documentation and advanced examples:
https://exocore-dev-docs-exocore.hf.space
If you encounter issues or want to give feedback, feel free to message us via Facebook:
---
* 🔐 Precise Login Mechanism
Dynamically scrapes Facebook's login form and submits tokens for secure authentication.
* 💬 Real-time Messaging
Send and receive messages (text, attachments, stickers, replies).
* 📝 Message Editing
Edit your bot’s messages in-place.
* ✍️ Typing Indicators
Detect and send typing status.
* ✅ Message Status Handling
Mark messages as delivered, read, or seen.
* 📂 Thread Management
* Retrieve thread details
* Load thread message history
* Get lists with filtering
* Pin/unpin messages
* Change and lock group avatars/photos
* 👤 User Info Retrieval
Access name, ID, profile picture, and mutual context.
* 🖼️ Sticker API
Search stickers, list packs, fetch store data, AI-stickers.
* 💬 Post Interaction
Comment and reply to public Facebook posts.
* ➕ Follow/Unfollow Users
Automate social interactions.
* 🌐 Proxy Support
Full support for custom proxies.
* 🧱 Modular Architecture
Organized into pluggable models for maintainability.
* 🛡️ Robust Error Handling
Retry logic, consistent logging, and graceful failovers.
* 🔄 Advanced Session Management
- Long-term cookie persistence (10 years expiry)
- Auto-save cookies to prevent session loss
- Automatic session refresh to keep connection alive
- Smart error handling for session expiry
---
> Requires Node.js v20+
``bash`
npm i fca-prince-malhotra@latest
---
This file contains your Facebook session cookies.
Use a browser extension (e.g. "C3C FbState", "CookieEditor") to export cookies after logging in, and save them in this format:
`json`
[
{
"key": "c_user",
"value": "your-id"
}
]
If you don't know how to get cookie, you can follow this tutorial here.
Place this file in the root directory as appstate.json.
---
`js
const fs = require("fs");
const path = require("path");
const { login } = require("fca-prince-malhotra");
let credentials;
try {
credentials = { appState: JSON.parse(fs.readFileSync("appstate.json", "utf8")) };
} catch (err) {
console.error("❌ appstate.json is missing or malformed.", err);
process.exit(1);
}
console.log("Logging in...");
login(credentials, {
online: true,
updatePresence: true,
selfListen: false,
randomUserAgent: false
}, async (err, api) => {
if (err) return console.error("LOGIN ERROR:", err);
console.log(✅ Logged in as: ${api.getCurrentUserID()});
const commandsDir = path.join(__dirname, "modules", "commands");
const commands = new Map();
if (!fs.existsSync(commandsDir)) fs.mkdirSync(commandsDir, { recursive: true });
for (const file of fs.readdirSync(commandsDir).filter(f => f.endsWith(".js"))) {
const command = require(path.join(commandsDir, file));
if (command.name && typeof command.execute === "function") {
commands.set(command.name, command);
console.log(🔧 Loaded command: ${command.name});
}
}
api.listenMqtt(async (err, event) => {
if (err || !event.body || event.type !== "message") return;
const prefix = "/";
if (!event.body.startsWith(prefix)) return;
const args = event.body.slice(prefix.length).trim().split(/ +/);
const commandName = args.shift().toLowerCase();
const command = commands.get(commandName);
if (!command) return;
try {
await command.execute({ api, event, args });
} catch (error) {
console.error(Error executing ${commandName}:, error);`
api.sendMessageMqtt("❌ An error occurred while executing the command.", event.threadID, event.messageID);
}
});
});
---
To prevent account logout and maintain stable sessions, enable these optional features:
`js✅ Logged in successfully!
login(credentials, {
online: true,
updatePresence: true,
selfListen: false,
// Auto-save cookies every 30 minutes (default)
autoSaveState: true,
autoSaveInterval: 1000 60 30, // 30 minutes
appStatePath: 'appstate.json', // Where to save cookies
// Keep session alive by refreshing every 15 minutes (default)
keepSessionAlive: true, // Set to false to disable
sessionRefreshInterval: 1000 60 15, // 15 minutes
// Other options
autoReconnect: true, // Auto-reconnect on disconnection
randomUserAgent: false
}, (err, api) => {
if (err) return console.error("LOGIN ERROR:", err);
console.log();📝 Auto-save: Cookies will be saved every 30 minutes
console.log();🔄 Session refresh: Active session will be maintained
console.log();`
// Your bot code here
});
Benefits:
- Long cookie expiry: Cookies now last 10 years instead of 1 year (automatic)
- Auto-save: Automatically backs up your cookies to prevent loss (opt-in with autoSaveState: true)keepSessionAlive: false
- Session refresh: Keeps your session active to prevent auto-logout (enabled by default, set to disable)
- Better error handling: Detects session expiry and provides clear error messages (automatic)
Note:
- autoSaveState is disabled by default. Set it to true to enable automatic cookie backup.keepSessionAlive
- is enabled by default. Your session will be automatically refreshed every 15 minutes. Set it to false if you want to disable this behavior.
---
Lock your group's avatar/photo so that it automatically reverts if someone changes it. Similar to how you can lock group names and nicknames.
Example:
`js
const fs = require("fs");
const { login } = require("fca-prince-malhotra");
const LOCKED_GROUP_ID = "YOUR_GROUP_THREAD_ID";
const LOCKED_AVATAR_PATH = "./locked_avatar.jpg";
// Load credentials from appstate.json
const credentials = {
appState: JSON.parse(fs.readFileSync("appstate.json", "utf8"))
};
login(credentials, { listenEvents: true }, (err, api) => {
if (err) return console.error(err);
console.log("🔒 Group Avatar Lock enabled!");
// Set the locked avatar (only if file exists)
if (fs.existsSync(LOCKED_AVATAR_PATH)) {
api.changeGroupImage(
fs.createReadStream(LOCKED_AVATAR_PATH),
LOCKED_GROUP_ID
).then(() => console.log("✅ Locked avatar set!"))
.catch(err => console.error("Failed to set avatar:", err));
} else {
console.log("⚠️ Locked avatar file not found. Skipping initial setup.");
}
// Listen for avatar change events and revert automatically
api.listenMqtt((err, event) => {
if (err) return console.error(err);
// Detect group avatar change
if (
event.type === "event" &&
event.logMessageType === "log:thread-icon" &&
event.threadID === LOCKED_GROUP_ID &&
event.author !== api.getCurrentUserID()
) {
console.log("⚠️ Avatar changed! Reverting...");
// Revert to locked avatar
if (fs.existsSync(LOCKED_AVATAR_PATH)) {
api.changeGroupImage(
fs.createReadStream(LOCKED_AVATAR_PATH),
LOCKED_GROUP_ID
).then(() => {
api.sendMessageMqtt(
"🔒 Group avatar is locked! Reverting to original.",
LOCKED_GROUP_ID
);
}).catch(err => console.error("Revert failed:", err));
}
}
});
});
`
Full example: See examples/group-avatar-lock.js for a complete implementation with group name and nickname locking.
Available APIs:
- api.changeGroupImage(imageStream, threadID) - Change group photolog:thread-icon
- Event: - Detects when group photo is changedapi.gcname(newName, threadID)
- - Lock/change group nameapi.setNickname(nickname, threadID, participantID)` - Lock/change nicknames
-
---
* 🔧 Prince Malhotra – Main developer, equal maintainer, feature and patch contributions.
* 🔮 Prince Malhotra – Foundational core design and architecture.
> Copyright (c) 2025
> Prince Malhotra
---
MIT – Free to use, modify, and distribute. Attribution appreciated.