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 🙏

© 2026 – Pkg Stats / Ryan Hefner

nodejs-insta-private-api-mqt

v1.3.90

Published

Complete Instagram MQTT protocol with full-featured REALTIME and REST API — all in one project.

Readme

Full featured Java and nodejs Instagram api private with Mqtt full suport and api rest

Dear users The repository on github is currently unavailable will be available soon

If you Like This Project You Can Help Me with Donation revolut , My revolut revtag is @gvny22

nodejs-insta-private-api-mqt

This project implements a complete and production-ready MQTT protocol client for Instagram's real-time messaging infrastructure. Instagram uses MQTT natively for direct messages, notifications, and real-time presence updates. This library replicates that exact implementation, allowing developers to build high-performance bots and automation tools that communicate with Instagram's backend using the same protocol the official app uses.

By leveraging MQTT instead of Instagram's REST API, this library achieves sub-500ms message latency, bidirectional real-time communication, and native support for notifications, presence tracking, and thread management. The implementation is reverse-engineered from Instagram's mobile app protocol and tested extensively for reliability and compatibility.

Features (v5.66.0 - Complete REST API + MQTT)

REST API (32 Repositories)

  • Account - Login, 2FA (TOTP + SMS), challenge resolver, edit profile, change password, privacy settings
  • User - Info, search, follow/unfollow, block/unblock, mute, get posts/reels/stories with pagination
  • Media - Like, comment (pin/unpin/bulk delete/reply), save, archive, download, PK/shortcode conversion
  • Reels/Clips - Upload, configure, discover reels, download, music info
  • Stories - Upload photo/video stories, react, mark seen, highlights management
  • Highlights - Create, edit, delete highlights, add/remove stories, update cover
  • Direct Messages - Send text/photo/video/link/media, inbox, pending inbox, group threads
  • Friendship - Follow, block, restrict, close friends, favorites, pending requests
  • Search - Users, hashtags, places, music, recent/suggested searches
  • Explore - Topical explore, report, mark seen
  • Feed - Timeline, hashtag/location feeds, saved/liked, carousel upload
  • Upload - Photo/video upload with configure to feed, story, or clips
  • Insights - Account, media, reel, story analytics (business/creator accounts)
  • Notes - Create, delete, view Instagram Notes
  • Notifications - Per-type notification settings (likes, comments, follows, etc.)
  • TOTP - 2FA setup with authenticator app, SMS 2FA, backup codes
  • Challenge - Auto-resolve security checkpoints, verify methods
  • Signup - Account creation, email/phone verification, username availability
  • Music/Tracks - Search, get info, download audio tracks
  • Fundraiser - Create, donate, get fundraiser info
  • Multiple Accounts - Account family, switch accounts
  • Captcha - reCAPTCHA / hCaptcha handling
  • Share - Decode QR/NFC share codes, parse share URLs
  • Bloks - Low-level Instagram Bloks engine actions

MQTT Real-Time

  • Real-time MQTT messaging - Receive and send DMs with <500ms latency
  • FBNS Push Notifications - Follows, likes, comments, story mentions, live broadcasts
  • 33 Preset Devices - 21 iOS + 12 Android device emulation
  • View-Once Media - Download disappearing photos/videos before they expire
  • Raven (View-Once) Sending - Send view-once and replayable photos/videos via REST
  • sendPhoto() / sendVideo() - Upload and send media directly via MQTT
  • Session persistence - Multi-file auth state like Baileys (WhatsApp library)
  • Automatic reconnection - Smart error classification with type-specific backoff
  • Session health monitoring - Auto-relogin, uptime tracking
  • Persistent logging - File-based logging with rotation
  • Message ordering - Per-thread message queuing
  • Pure JavaScript - No compilation required, works in Node.js 18+

Scope: DM-Focused Implementation

This library is optimized for Direct Messages and implements the core MQTT protocols used by Instagram for:

  • Real-time message delivery and reception
  • Presence status tracking
  • Typing indicators
  • Notifications for follows, mentions, and calls
  • Group thread management

For full MQTT coverage analysis, see MQTT_COVERAGE_ANALYSIS.md

Installation

npm install nodejs-insta-private-api-mqt

Requires Node.js 18 or higher.


NEW: Custom Device Emulation (v5.60.7)

Default Device: Samsung Galaxy S25 Ultra (Android 15) - used automatically if you don't set a custom device.

This feature allows you to choose which phone model Instagram sees when your bot connects. Instead of using a default device, you can emulate any Android phone like Samsung Galaxy S25 Ultra, Huawei P60 Pro, Google Pixel 9, and more.

Why Use Custom Device Emulation?

  • Avoid detection - Use realistic, modern device fingerprints
  • Match your target audience - Emulate devices popular in specific regions
  • Testing - Test how Instagram behaves with different devices
  • Reduce bans - Modern devices are less likely to trigger security checks

Quick Start: Use a Preset Device

const { IgApiClient } = require('nodejs-insta-private-api');

const ig = new IgApiClient();

// Set device BEFORE login
ig.state.usePresetDevice('Samsung Galaxy S25 Ultra');

// Now login - Instagram will see a Samsung S25 Ultra
await ig.login({
  username: 'your_username',
  password: 'your_password'
});

console.log('Logged in with device:', ig.state.deviceString);

Available Preset Devices

| Device Name | Manufacturer | Android Version | |-------------|--------------|-----------------| | Samsung Galaxy S25 Ultra | Samsung | Android 15 | | Samsung Galaxy S24 Ultra | Samsung | Android 14 | | Samsung Galaxy S23 Ultra | Samsung | Android 14 | | Samsung Galaxy Z Fold 5 | Samsung | Android 14 | | Huawei P60 Pro | Huawei | Android 12 | | Huawei Mate 60 Pro | Huawei | Android 12 | | Google Pixel 8 Pro | Google | Android 14 | | Google Pixel 9 Pro | Google | Android 15 | | OnePlus 12 | OnePlus | Android 14 | | Xiaomi 14 Ultra | Xiaomi | Android 14 | | Xiaomi Redmi Note 13 Pro | Xiaomi | Android 14 | | OPPO Find X7 Ultra | OPPO | Android 14 |

Set a Fully Custom Device

For complete control, use setCustomDevice() with your own configuration:

const ig = new IgApiClient();

ig.state.setCustomDevice({
  manufacturer: 'samsung',
  model: 'SM-S928B',
  device: 'e3q',
  androidVersion: '15',
  androidApiLevel: 35,
  resolution: '1440x3120',
  dpi: '505dpi',
  chipset: 'qcom',
  build: 'UP1A.231005.007'
});

Quick Start: Instant MQTT Boot

const { IgApiClient, RealtimeClient, useMultiFileAuthState } = require('nodejs-insta-private-api-mqt');

async function startBot() {
  const ig = new IgApiClient();
  const auth = await useMultiFileAuthState('./auth_info_ig');
  
  ig.state.usePresetDevice('Samsung Galaxy S25 Ultra');
  
  const realtime = new RealtimeClient(ig);

  realtime.on('connected', () => {
    console.log('Bot is online and MQTT is connected!');
  });

  realtime.on('message_live', async (msg) => {
    console.log(`[${msg.username}]: ${msg.text}`);
    
    if (msg.text.toLowerCase() === 'ping') {
      await realtime.directCommands.sendText({
        threadId: msg.thread_id,
        text: 'pong!'
      });
    }
  });

  if (!auth.hasSession()) {
    await ig.login({
      username: 'your_username',
      password: 'your_password'
    });
    
    await auth.saveCreds(ig);
    await realtime.startRealTimeListener();
    await auth.saveMqttSession(realtime);
  }
}

startBot().catch(console.error);

EnhancedDirectCommands - Complete MQTT Methods Reference

All MQTT direct messaging functionality is available through realtime.directCommands. These methods use proper payload formatting that matches the instagram_mqtt library format.

Basic Messaging

Send Text Message

await realtime.directCommands.sendText({
  threadId: '340282366841710300949128114477782749726',
  text: 'Hello from MQTT!'
});

Send Text (Alternative Signature)

await realtime.directCommands.sendTextViaRealtime(threadId, 'Hello!');

Reply to Message (Quote Reply)

await realtime.directCommands.replyToMessage(threadId, messageId, 'This is my reply');

Edit Message

await realtime.directCommands.editMessage(threadId, itemId, 'Updated text here');

Delete Message

await realtime.directCommands.deleteMessage(threadId, itemId);

Content Sharing

Send Hashtag

await realtime.directCommands.sendHashtag({
  threadId: threadId,
  hashtag: 'photography',
  text: 'Check this out'
});

Send Like (Heart)

await realtime.directCommands.sendLike({
  threadId: threadId
});

Send Location

await realtime.directCommands.sendLocation({
  threadId: threadId,
  locationId: '123456789',
  text: 'Meet me here'
});

Send Media (Share Post)

await realtime.directCommands.sendMedia({
  threadId: threadId,
  mediaId: 'media_id_here',
  text: 'Check this post'
});

Send Profile

await realtime.directCommands.sendProfile({
  threadId: threadId,
  userId: '12345678',
  text: 'Follow this account'
});

Send User Story

await realtime.directCommands.sendUserStory({
  threadId: threadId,
  storyId: 'story_id_here',
  text: 'Did you see this?'
});

Send Link

await realtime.directCommands.sendLink({
  threadId: threadId,
  link: 'https://example.com',
  text: 'Check this link'
});

Send Animated Media (GIF/Sticker)

await realtime.directCommands.sendAnimatedMedia({
  threadId: threadId,
  id: 'giphy_id_here',
  isSticker: false
});

Send Voice Message (after upload)

await realtime.directCommands.sendVoice({
  threadId: threadId,
  uploadId: 'your_upload_id',
  waveform: [0.1, 0.5, 0.8, 0.3],
  waveformSamplingFrequencyHz: 10
});

Reactions

Send Reaction

await realtime.directCommands.sendReaction({
  threadId: threadId,
  itemId: messageId,
  reactionType: 'like'
});

Send Emoji Reaction

await realtime.directCommands.sendReaction({
  threadId: threadId,
  itemId: messageId,
  reactionType: 'emoji',
  emoji: '🔥'
});

Remove Reaction

await realtime.directCommands.removeReaction({
  threadId: threadId,
  itemId: messageId
});

Read Receipts & Activity

Mark Message as Seen

Marks a message as seen (read receipt) in a DM thread. This uses Instagram's REST API internally and falls back to MQTT if needed. The method returns the server response — when successful, status will be "ok".

// Basic usage — mark a specific message as seen
const result = await realtime.directCommands.markAsSeen({
  threadId: '340282366841710300949128114477782749726',
  itemId: '32661457411201420841385410521202688'
});
console.log(result.status); // "ok"

Auto-Read All Incoming Messages

A common pattern is to automatically mark every incoming message as seen, so the sender always sees the blue "Seen" indicator:

realtime.on('message', async (data) => {
  const threadId = data.parsed?.threadId || data.message?.thread_id;
  const itemId = data.parsed?.messageId || data.message?.item_id;
  const status = data.parsed?.status;

  // Only mark messages from other users (skip our own)
  if (status === 'sent' || !threadId || !itemId) return;

  try {
    await realtime.directCommands.markAsSeen({ threadId, itemId });
  } catch (err) {
    console.error('Failed to mark as seen:', err.message);
  }
});

Mark as Seen with Delay (Human-Like Behavior)

If you want the bot to appear more human, you can add a small delay before sending the read receipt:

realtime.on('message', async (data) => {
  const threadId = data.parsed?.threadId || data.message?.thread_id;
  const itemId = data.parsed?.messageId || data.message?.item_id;

  if (data.parsed?.status === 'sent' || !threadId || !itemId) return;

  // Wait 1-3 seconds before marking as seen
  const delay = 1000 + Math.random() * 2000;
  await new Promise(resolve => setTimeout(resolve, delay));

  await realtime.directCommands.markAsSeen({ threadId, itemId });
});

Indicate Typing

// Start typing
await realtime.directCommands.indicateActivity({
  threadId: threadId,
  isActive: true
});

// Stop typing
await realtime.directCommands.indicateActivity({
  threadId: threadId,
  isActive: false
});

Mark Visual Message as Seen (disappearing media)

Mark view-once photos/videos as seen. Works the same way as markAsSeen but specifically for disappearing media items:

await realtime.directCommands.markVisualMessageSeen({
  threadId: threadId,
  itemId: messageId
});

Thread Management

Add Member to Thread

await realtime.directCommands.addMemberToThread(threadId, userId);

// Add multiple members
await realtime.directCommands.addMemberToThread(threadId, [userId1, userId2]);

Remove Member from Thread

await realtime.directCommands.removeMemberFromThread(threadId, userId);

Leave Thread

await realtime.directCommands.leaveThread(threadId);

Update Thread Title

await realtime.directCommands.updateThreadTitle(threadId, 'New Group Name');

Mute Thread

await realtime.directCommands.muteThread(threadId);

// Mute until specific time
await realtime.directCommands.muteThread(threadId, Date.now() + 3600000);

Unmute Thread

await realtime.directCommands.unmuteThread(threadId);

Message Requests

Approve Pending Thread

await realtime.directCommands.approveThread(threadId);

Decline Pending Thread

await realtime.directCommands.declineThread(threadId);

Moderation

Block User in Thread

await realtime.directCommands.blockUserInThread(threadId, userId);

Report Thread

await realtime.directCommands.reportThread(threadId, 'spam');

Disappearing Media (View-Once)

Send Disappearing Photo

await realtime.directCommands.sendDisappearingPhoto({
  threadId: threadId,
  uploadId: 'your_upload_id',
  viewMode: 'once'  // 'once' or 'replayable'
});

Send Disappearing Video

await realtime.directCommands.sendDisappearingVideo({
  threadId: threadId,
  uploadId: 'your_upload_id',
  viewMode: 'once'
});

Raven (View-Once / Disappearing) Media

Send photos and videos that disappear after viewing — just like the Instagram app camera button in DMs. Instagram calls these "raven" messages internally.

How it works under the hood:

  1. The photo/video is uploaded to rupload.facebook.com/messenger_image/ (Instagram's dedicated raven upload endpoint)
  2. Then broadcast via REST to /direct_v2/threads/broadcast/raven_attachment/

You don't need to worry about any of that — the library handles everything. Just pick a method and go.

Two view modes: | Mode | What happens | |------|-------------| | 'once' | Recipient opens it once, then it's gone forever | | 'replayable' | Recipient can replay it, but it still disappears from the chat |


Quick Start — Send a View-Once Photo (Standalone, No MQTT)

The simplest way to send a disappearing photo. No MQTT setup needed — just login and send:

const { IgApiClient, useMultiFileAuthState, sendRavenPhotoOnce } = require('nodejs-insta-private-api-mqt');
const fs = require('fs');

async function main() {
  const ig = new IgApiClient();
  const auth = await useMultiFileAuthState('./my_session');
  ig.state.usePresetDevice('Samsung Galaxy S25 Ultra');

  // Login (or restore session)
  await ig.login({ username: 'your_username', password: 'your_password' });
  await auth.saveCreds(ig);

  // Read any photo from disk
  const photo = fs.readFileSync('./secret_photo.jpg');

  // Send it as view-once — one line, that's it
  const result = await sendRavenPhotoOnce(ig, photo, {
    threadId: '340282366841710300949128114477782749726'  // your DM thread ID
  });

  console.log('Sent! Status:', result.status);  // "ok"
}

main().catch(console.error);

Send a Replayable Photo

Same thing, but the recipient can replay it before it disappears:

const { sendRavenPhotoReplayable } = require('nodejs-insta-private-api-mqt');

const photo = fs.readFileSync('./photo.jpg');

const result = await sendRavenPhotoReplayable(ig, photo, {
  threadId: 'your_thread_id'
});

console.log('Replayable photo sent!', result.status);

Send a View-Once Video

Experience the new and improved video sending! Our implementation is now fully compatible with the latest Instagram protocols.

const { IgApiClientExt } = require('nodejs-insta-private-api-mqt');
const fs = require('fs');

async function sendMySecretVideo() {
  const ig = new IgApiClientExt();
  await ig.login({ username: 'your_username', password: 'your_password' });

  // Just read your video file
  const videoData = fs.readFileSync('./my_awesome_video.mp4');

  // Send it instantly as a view-once message
  const result = await ig.sendRavenVideoOnce(videoData, {
    threadId: '1234567890', // The DM thread ID
    duration: 10,           // Video length in seconds
    width: 720,             // Width (default 720)
    height: 1280            // Height (default 1280)
  });

  if (result.status === 'ok') {
    console.log('Boom! Your secret video is on its way.');
  }
}

Send a Replayable Video

If you want them to be able to see it one more time before it disappears:

const result = await ig.sendRavenVideoReplayable(videoData, {
  threadId: '1234567890',
  duration: 15
});

Using sendRavenPhoto / sendRavenVideo Directly (Choose Mode)

If you want to pick the view mode dynamically, use the base sendRavenPhoto or sendRavenVideo functions with the viewMode option:

const { sendRavenPhoto, sendRavenVideo } = require('nodejs-insta-private-api-mqt');
const fs = require('fs');

// Photo — choose 'once' or 'replayable'
const photoResult = await sendRavenPhoto(ig, fs.readFileSync('./photo.jpg'), {
  threadId: 'your_thread_id',
  viewMode: 'once'          // or 'replayable'
});

// Video — same pattern
const videoResult = await sendRavenVideo(ig, fs.readFileSync('./video.mp4'), {
  threadId: 'your_thread_id',
  viewMode: 'replayable',   // or 'once'
  duration: 8,
  width: 720,
  height: 1280
});

With MQTT / RealtimeClient (directCommands)

If you already have an MQTT connection running (for receiving messages in real-time), you can use directCommands to send raven media without importing anything extra:

// After setting up realtime connection...

const fs = require('fs');
const photo = fs.readFileSync('./secret.jpg');

// View-once photo
await realtime.directCommands.sendRavenPhotoOnce({
  threadId: threadId,
  photoBuffer: photo
});

// Replayable photo
await realtime.directCommands.sendRavenPhotoReplayable({
  threadId: threadId,
  photoBuffer: photo
});

// Or specify viewMode manually
await realtime.directCommands.sendRavenPhoto({
  threadId: threadId,
  photoBuffer: photo,
  viewMode: 'once'    // 'once' or 'replayable'
});

// View-once video
const video = fs.readFileSync('./clip.mp4');
await realtime.directCommands.sendRavenVideoOnce({
  threadId: threadId,
  videoBuffer: video,
  duration: 10,
  width: 720,
  height: 1280
});

// Replayable video
await realtime.directCommands.sendRavenVideoReplayable({
  threadId: threadId,
  videoBuffer: video,
  duration: 10
});

Complete Bot Example — Auto-Reply with Disappearing Photo

Here's a full working example of a bot that automatically replies to incoming messages with a view-once photo:

const {
  IgApiClient,
  withRealtime,
  useMultiFileAuthState,
  GraphQLSubscriptions,
  SkywalkerSubscriptions,
  sendRavenPhotoOnce,
  sendRavenPhotoReplayable,
} = require('nodejs-insta-private-api-mqt');
const fs = require('fs');

async function startBot() {
  const ig = new IgApiClient();
  const auth = await useMultiFileAuthState('./bot_session');
  ig.state.usePresetDevice('Samsung Galaxy S25 Ultra');

  await ig.login({ username: 'bot_username', password: 'bot_password' });
  await auth.saveCreds(ig);

  const { realtime } = withRealtime(ig);

  realtime.on('message', async (data) => {
    // When someone sends you a text message
    if (data.message && data.message.text) {
      const threadId = data.message.thread_id;
      const text = data.message.text.toLowerCase();

      if (text === '!secret') {
        // Reply with a view-once photo
        const photo = fs.readFileSync('./secret_photo.jpg');
        await sendRavenPhotoOnce(ig, photo, { threadId });
        console.log('Sent view-once photo to', threadId);
      }

      if (text === '!replay') {
        // Reply with a replayable photo
        const photo = fs.readFileSync('./replay_photo.jpg');
        await sendRavenPhotoReplayable(ig, photo, { threadId });
        console.log('Sent replayable photo to', threadId);
      }
    }
  });

  await realtime.connect({
    graphQlSubs: [GraphQLSubscriptions.getDirectTypingSubscription(ig.state.cookieUserId)],
    skywalkerSubs: [SkywalkerSubscriptions.directSub(ig.state.cookieUserId)],
    irisData: await ig.request.send({ url: '/api/v1/direct_v2/inbox/', method: 'GET' }),
  });

  console.log('Bot is running! Send "!secret" or "!replay" in DMs.');
}

startBot().catch(console.error);

All Available Raven Functions

| Function | What it does | |----------|-------------| | sendRavenPhoto(ig, buffer, { threadId, viewMode }) | Send disappearing photo with chosen mode | | sendRavenPhotoOnce(ig, buffer, { threadId }) | Send view-once photo (opens once, then gone) | | sendRavenPhotoReplayable(ig, buffer, { threadId }) | Send replayable photo (can replay, still disappears) | | sendRavenVideo(ig, buffer, { threadId, viewMode, duration, width, height }) | Send disappearing video with chosen mode | | sendRavenVideoOnce(ig, buffer, { threadId, duration, width, height }) | Send view-once video | | sendRavenVideoReplayable(ig, buffer, { threadId, duration, width, height }) | Send replayable video |

All functions return a response object with status: 'ok' on success and a payload containing the item_id and thread_id.


Low-Level: broadcastRaven (DirectThread Repository)

If you want full control over the process, you can handle the upload yourself and just call the broadcast. Important: media must be uploaded to rupload.facebook.com/messenger_image/ (not rupload_igphoto/) for raven to work.

// Step 1: Upload to messenger_image endpoint (see sendRavenPhoto.js for full headers)
// Step 2: Broadcast
const result = await ig.directThread.broadcastRaven({
  uploadId: uploadId,           // from the messenger_image upload response
  attachmentFbid: mediaId,      // media_id from the upload response
  threadId: threadId,
  viewMode: 'once'              // 'once' or 'replayable'
});

Notifications

Send Screenshot Notification

await realtime.directCommands.sendScreenshotNotification({
  threadId: threadId,
  itemId: messageId
});

Send Replay Notification

await realtime.directCommands.sendReplayNotification({
  threadId: threadId,
  itemId: messageId
});

Media Upload (HTTP + Broadcast)

These methods handle the full flow: upload via HTTP rupload, then broadcast to thread.

Send Photo

const fs = require('fs');
const photoBuffer = fs.readFileSync('./photo.jpg');

await realtime.directCommands.sendPhoto({
  threadId: threadId,
  photoBuffer: photoBuffer,
  caption: 'Check this out',
  mimeType: 'image/jpeg'
});

Send Video

const fs = require('fs');
const videoBuffer = fs.readFileSync('./video.mp4');

await realtime.directCommands.sendVideo({
  threadId: threadId,
  videoBuffer: videoBuffer,
  caption: 'Watch this',
  duration: 15,
  width: 720,
  height: 1280
});

Foreground State (Connection Keepalive)

await realtime.directCommands.sendForegroundState({
  inForegroundApp: true,
  inForegroundDevice: true,
  keepAliveTimeout: 60
});

Complete Method Reference Table

| Method | Description | |--------|-------------| | sendText({ threadId, text }) | Send text message | | sendTextViaRealtime(threadId, text) | Send text (alternative) | | sendHashtag({ threadId, hashtag, text }) | Send hashtag | | sendLike({ threadId }) | Send heart/like | | sendLocation({ threadId, locationId, text }) | Send location | | sendMedia({ threadId, mediaId, text }) | Share a post | | sendProfile({ threadId, userId, text }) | Share a profile | | sendUserStory({ threadId, storyId, text }) | Share a story | | sendLink({ threadId, link, text }) | Send a link | | sendAnimatedMedia({ threadId, id, isSticker }) | Send GIF/sticker | | sendVoice({ threadId, uploadId, waveform }) | Send voice message | | sendReaction({ threadId, itemId, emoji }) | React to message | | removeReaction({ threadId, itemId }) | Remove reaction | | replyToMessage(threadId, messageId, text) | Quote reply | | editMessage(threadId, itemId, newText) | Edit message | | deleteMessage(threadId, itemId) | Delete message | | markAsSeen({ threadId, itemId }) | Mark as read | | indicateActivity({ threadId, isActive }) | Typing indicator | | markVisualMessageSeen({ threadId, itemId }) | Mark disappearing media seen | | addMemberToThread(threadId, userId) | Add group member | | removeMemberFromThread(threadId, userId) | Remove group member | | leaveThread(threadId) | Leave group | | updateThreadTitle(threadId, title) | Change group name | | muteThread(threadId, muteUntil) | Mute thread | | unmuteThread(threadId) | Unmute thread | | approveThread(threadId) | Accept message request | | declineThread(threadId) | Decline message request | | blockUserInThread(threadId, userId) | Block user | | reportThread(threadId, reason) | Report thread | | sendDisappearingPhoto({ threadId, uploadId }) | Send view-once photo (MQTT metadata only) | | sendDisappearingVideo({ threadId, uploadId }) | Send view-once video (MQTT metadata only) | | sendRavenPhoto({ threadId, photoBuffer, viewMode }) | Upload & send disappearing photo (full flow) | | sendRavenPhotoOnce({ threadId, photoBuffer }) | Upload & send view-once photo | | sendRavenPhotoReplayable({ threadId, photoBuffer }) | Upload & send replayable photo | | sendRavenVideo({ threadId, videoBuffer, viewMode }) | Upload & send disappearing video (full flow) | | sendRavenVideoOnce({ threadId, videoBuffer }) | Upload & send view-once video | | sendRavenVideoReplayable({ threadId, videoBuffer }) | Upload & send replayable video | | sendScreenshotNotification({ threadId, itemId }) | Screenshot alert | | sendReplayNotification({ threadId, itemId }) | Replay alert | | sendPhoto({ threadId, photoBuffer, caption }) | Upload & send photo | | sendVideo({ threadId, videoBuffer, caption }) | Upload & send video | | sendForegroundState(state) | Connection keepalive |


Download Media from Messages

This feature provides Baileys-style media download for Instagram DM messages.

Quick Start: Save View-Once Photo

const { 
  downloadContentFromMessage,
  isViewOnceMedia 
} = require('nodejs-insta-private-api-mqt');
const fs = require('fs');

realtime.on('message', async (data) => {
  const msg = data.message;
  
  if (isViewOnceMedia(msg)) {
    const stream = await downloadContentFromMessage(msg);
    
    let buffer = Buffer.from([]);
    for await (const chunk of stream) {
      buffer = Buffer.concat([buffer, chunk]);
    }
    
    const ext = stream.mediaInfo.type.includes('video') ? 'mp4' : 'jpg';
    fs.writeFileSync(`viewonce_${Date.now()}.${ext}`, buffer);
  }
});

Download Regular Media

const { downloadMediaBuffer, hasMedia } = require('nodejs-insta-private-api-mqt');

realtime.on('message', async (data) => {
  const msg = data.message;
  
  if (hasMedia(msg)) {
    const { buffer, mediaInfo } = await downloadMediaBuffer(msg);
    fs.writeFileSync(`media_${Date.now()}.jpg`, buffer);
  }
});

Media Functions Reference

| Function | Description | |----------|-------------| | downloadContentFromMessage(message) | Download as stream | | downloadMediaBuffer(message) | Download as Buffer | | extractMediaUrls(message) | Get CDN URLs | | hasMedia(message) | Check if has media | | getMediaType(message) | Get media type | | isViewOnceMedia(message) | Check if disappearing |


Building Instagram Bots

Auto-Reply Bot Example

const { IgApiClient, RealtimeClient } = require('nodejs-insta-private-api-mqt');
const fs = require('fs');

(async () => {
  const ig = new IgApiClient();
  const session = JSON.parse(fs.readFileSync('session.json'));
  await ig.state.deserialize(session);

  const realtime = new RealtimeClient(ig);
  const inbox = await ig.direct.getInbox();
  
  await realtime.connect({
    graphQlSubs: ['ig_sub_direct', 'ig_sub_direct_v2_message_sync'],
    irisData: inbox
  });

  console.log('Bot Active\n');

  realtime.on('message', async (data) => {
    const msg = data.message;
    if (!msg?.text) return;

    console.log(`[${msg.from_user_id}]: ${msg.text}`);

    if (msg.text.toLowerCase().includes('hello')) {
      await realtime.directCommands.sendText({
        threadId: msg.thread_id,
        text: 'Hey! Thanks for reaching out!'
      });
    }
  });

  await new Promise(() => {});
})();

Smart Bot with Reactions and Typing

realtime.on('message', async (data) => {
  const msg = data.message;
  if (!msg?.text) return;

  // Mark as seen
  await realtime.directCommands.markAsSeen({
    threadId: msg.thread_id,
    itemId: msg.item_id
  });

  // Show typing
  await realtime.directCommands.indicateActivity({
    threadId: msg.thread_id,
    isActive: true
  });

  await new Promise(r => setTimeout(r, 2000));

  if (msg.text.toLowerCase().includes('hi')) {
    await realtime.directCommands.sendText({
      threadId: msg.thread_id,
      text: 'Hello there!'
    });

    // React with emoji
    await realtime.directCommands.sendReaction({
      threadId: msg.thread_id,
      itemId: msg.item_id,
      emoji: '👋'
    });
  }

  // Stop typing
  await realtime.directCommands.indicateActivity({
    threadId: msg.thread_id,
    isActive: false
  });
});

Session Management

Multi-File Auth State (Baileys Style)

const authState = await useMultiFileAuthState('./auth_folder');

| Method | Description | |--------|-------------| | hasSession() | Check if credentials exist | | hasMqttSession() | Check if MQTT session exists | | loadCreds(ig) | Load saved credentials | | saveCreds(ig) | Save current credentials | | isSessionValid(ig) | Validate with Instagram | | loadMqttSession() | Get saved MQTT session | | saveMqttSession(realtime) | Save MQTT session | | clearSession() | Delete all session files |


API Reference

IgApiClient

// Login
await ig.login({
  username: 'your_username',
  password: 'your_password'
});

// Save session
const serialized = ig.state.serialize();
fs.writeFileSync('session.json', JSON.stringify(serialized));

// Load session
const session = JSON.parse(fs.readFileSync('session.json'));
await ig.state.deserialize(session);

Direct Messages (REST)

// Get inbox
const inbox = await ig.direct.getInbox();

// Get thread
const thread = await ig.direct.getThread(threadId);

// Send text by username (looks up user, finds/creates thread, sends)
await ig.direct.send({ to: 'target_username', message: 'Hello!' });

// Send text by user ID (no username lookup needed)
await ig.direct.sendToUserId('12345678', 'Hello!');

// Send text to an existing thread (by thread ID)
await ig.directThread.sendToGroup({ threadId: '340282366841710300...', message: 'Hello!' });

// Low-level broadcast (full control over payload)
await ig.directThread.broadcast({
  threadIds: ['340282366841710300...'],
  item: 'text',
  form: { text: 'Hello!' },
});

REST API — Full Reference (v5.66.0)

Everything below uses the REST HTTP endpoints, not MQTT. You don't need RealtimeClient for any of this — just IgApiClient and a valid session.

const { IgApiClient } = require('nodejs-insta-private-api-mqt');
const ig = new IgApiClient();

ig.state.usePresetDevice('Samsung Galaxy S25 Ultra');
await ig.login({ username: 'your_username', password: 'your_password' });
// you're ready to use any of the methods below

Authentication & Login

Basic Login

await ig.login({ username: 'your_username', password: 'your_password' });

// or the shorter way
await ig.account.login('your_username', 'your_password');

Two-Factor Authentication (2FA)

When Instagram asks for a 2FA code, login() throws an error that contains the two_factor_identifier. Catch it and finish the flow:

try {
  await ig.account.login('username', 'password');
} catch (err) {
  if (err.response?.body?.two_factor_required) {
    const twoFactorId = err.response.body.two_factor_info.two_factor_identifier;
    
    // user enters the code from their authenticator app or SMS
    const code = '123456';
    
    await ig.account.twoFactorLogin('username', code, twoFactorId, '1');
    // verificationMethod: '1' = SMS, '3' = TOTP app
    console.log('2FA login successful');
  }
}

TOTP Two-Factor Setup

Set up authenticator-app-based 2FA for your account. This generates a seed you can add to Google Authenticator, Authy, etc.

// generate a TOTP seed (this is the secret key for your authenticator app)
const seed = await ig.totp.generateSeed();
console.log('Add this to your authenticator app:', seed.totp_seed);

// after adding it, verify with a code from the app to confirm
const code = '123456'; // from authenticator app
await ig.totp.enable(code);
console.log('TOTP 2FA is now enabled');

// get backup codes in case you lose your authenticator
const backupCodes = await ig.totp.getBackupCodes();
console.log('Save these somewhere safe:', backupCodes);

// disable TOTP 2FA
await ig.totp.disable();

SMS-Based 2FA

// enable SMS 2FA
await ig.totp.smsTwoFactorEnable('+1234567890');

// confirm with the code you received
await ig.totp.smsTwoFactorConfirm('123456');

// disable it later
await ig.totp.disableSmsTwoFactor();

Challenge Resolver

When Instagram triggers a security checkpoint (suspicious login, new location, etc.), you need to resolve the challenge:

try {
  await ig.account.login('username', 'password');
} catch (err) {
  if (err.response?.body?.challenge) {
    const challengeUrl = err.response.body.challenge.api_path;
    
    // option 1: automatic resolution (tries to handle it for you)
    const result = await ig.challenge.auto(challengeUrl);
    console.log('Challenge result:', result);
    
    // option 2: manual step-by-step
    // first, see what verification methods are available
    const page = await ig.challenge.getChallengePage(challengeUrl);
    
    // choose SMS (0) or email (1)
    await ig.challenge.selectVerifyMethod(challengeUrl, 1);
    
    // enter the code you received
    await ig.challenge.sendSecurityCode(challengeUrl, '123456');
  }
}

Account Management

Get Current User Info

const me = await ig.account.currentUser();
console.log('Username:', me.user.username);
console.log('Follower count:', me.user.follower_count);

Edit Profile

await ig.account.editProfile({
  fullName: 'John Doe',
  biography: 'building cool stuff',
  externalUrl: 'https://example.com',
  email: '[email protected]',
  phoneNumber: '+1234567890',
  username: 'johndoe_new'
});

Set Biography

await ig.account.setBiography('i like building things that work');

Set External URL / Remove Bio Links

await ig.account.setExternalUrl('https://mywebsite.com');
await ig.account.removeBioLinks();

Change Password

await ig.account.changePassword('old_password_here', 'new_password_here');

Switch to Private / Public

await ig.account.setPrivate();
await ig.account.setPublic();

Set Gender

// 1 = male, 2 = female, 3 = prefer not to say, 4 = custom
await ig.account.setGender(1);

Profile Picture

// you need an upload_id from a previous photo upload
await ig.account.profilePictureChange(uploadId);
await ig.account.profilePictureRemove();

Password Encryption Keys

// get the public keys for Instagram's password encryption (needed for some flows)
const keys = await ig.account.passwordPublicKeys();

Account Recovery

// send password recovery via email
await ig.account.sendRecoveryFlowEmail('[email protected]');

// or via SMS
await ig.account.sendRecoveryFlowSms('+1234567890');

User Operations

Fetch User Info

// by username
const user = await ig.user.infoByUsername('instagram');
console.log('User ID:', user.pk);
console.log('Followers:', user.follower_count);

// by user ID
const userById = await ig.user.info('25025320');

Resolve Username ↔ User ID

const userId = await ig.user.userIdFromUsername('instagram');
// returns '25025320'

const username = await ig.user.usernameFromUserId('25025320');
// returns 'instagram'

Search Users

const results = await ig.user.search('john', 20);
results.users.forEach(u => {
  console.log(u.username, '-', u.full_name);
});

// exact match
const exact = await ig.user.searchExact('johndoe');

Follow / Unfollow

await ig.user.follow('25025320');
await ig.user.unfollow('25025320');

Block / Unblock

await ig.user.block('25025320');
await ig.user.unblock('25025320');

// see all blocked users
const blocked = await ig.user.getBlockedUsers();

Mute / Unmute

// mute posts, stories, or both
await ig.user.mute('25025320', { mutePosts: true, muteStories: true });
await ig.user.unmute('25025320', { unmutePosts: true, unmuteStories: true });

Get Followers / Following (with pagination)

// get up to 200 followers at a time
const followers = await ig.user.getFollowers('25025320', 200);
console.log('Got', followers.users.length, 'followers');

// pagination — pass the maxId from the previous response
const moreFollowers = await ig.user.getFollowers('25025320', 200, followers.next_max_id);

// same for following
const following = await ig.user.getFollowing('25025320', 200);

Get User's Posts (with pagination)

// grab the latest 50 posts
const posts = await ig.user.getUserMedias('25025320', 50);
posts.items.forEach(item => {
  console.log(item.pk, '-', item.caption?.text?.substring(0, 50));
});

// next page
const morePosts = await ig.user.getUserMedias('25025320', 50, posts.next_max_id);

Get User's Reels / Clips

const reels = await ig.user.getUserReels('25025320', 50);
const clips = await ig.user.getUserClips('25025320', 50);

Get User's Stories

const stories = await ig.user.getUserStories('25025320');
stories.reel?.items.forEach(story => {
  console.log('Story:', story.pk, 'taken at:', story.taken_at);
});

Get Tagged Posts

const tagged = await ig.user.getUserTags('25025320');

Mutual Followers

const mutual = await ig.user.getMutualFollowers('25025320');

Remove a Follower

await ig.user.removeFollower('25025320');

Report a User

// reason: 1 = spam, 2 = inappropriate, etc.
await ig.user.report('25025320', 1);

Get Suggested Users

const suggestions = await ig.user.getSuggested();

Friendship Status (Bulk)

// check relationship status with multiple users at once
const statuses = await ig.user.getFriendshipStatuses(['12345', '67890', '11111']);

Media Operations

Get Media Info

const info = await ig.media.info('3193593212003331660');
console.log('Type:', info.items[0].media_type);
console.log('Likes:', info.items[0].like_count);

PK / Shortcode Conversion

These are super useful when you have a post URL and need the numeric ID, or the other way around.

const { MediaRepository } = require('nodejs-insta-private-api-mqt');

// convert shortcode to numeric PK
const pk = MediaRepository.mediaPkFromCode('CxR7Bsejq5M');
// '3193593212003331660'

// convert PK back to shortcode
const code = MediaRepository.mediaCodeFromPk('3193593212003331660');
// 'CxR7Bsejq5M'

// extract PK directly from a full URL
const pkFromUrl = MediaRepository.mediaPkFromUrl('https://www.instagram.com/p/CxR7Bsejq5M/');
// '3193593212003331660'

Like / Unlike

await ig.media.like('3193593212003331660');
await ig.media.unlike('3193593212003331660');

Comment

const comment = await ig.media.comment('3193593212003331660', 'great shot!');
console.log('Comment ID:', comment.comment.pk);

Reply to a Comment

await ig.media.replyToComment('3193593212003331660', '17858893269000001', '@user thanks!');

Like / Unlike Comments

await ig.media.likeComment('3193593212003331660', '17858893269000001');
await ig.media.unlikeComment('3193593212003331660', '17858893269000001');

Pin / Unpin Comments

await ig.media.pinComment('3193593212003331660', '17858893269000001');
await ig.media.unpinComment('3193593212003331660', '17858893269000001');

Delete Comments (Single or Bulk)

// single
await ig.media.deleteComment('3193593212003331660', '17858893269000001');

// bulk delete
await ig.media.bulkDeleteComments('3193593212003331660', [
  '17858893269000001',
  '17858893269000002',
  '17858893269000003'
]);

Get Comments (Paginated)

const comments = await ig.media.comments('3193593212003331660', null, 20);
// next page:
const moreComments = await ig.media.comments('3193593212003331660', comments.next_min_id, 20);

Get Comment Thread (Replies to a Comment)

const thread = await ig.media.commentThreadComments('3193593212003331660', '17858893269000001');

Get Likers

const likers = await ig.media.likers('3193593212003331660');
likers.users.forEach(u => console.log(u.username));

Save / Unsave

await ig.media.save('3193593212003331660');

// save to a specific collection
await ig.media.save('3193593212003331660', 'collection_id_here');

await ig.media.unsave('3193593212003331660');

Archive / Unarchive

await ig.media.archive('3193593212003331660');
await ig.media.unarchive('3193593212003331660');

Delete Media

// mediaType: 'PHOTO', 'VIDEO', 'CAROUSEL'
await ig.media.delete('3193593212003331660', 'PHOTO');

Edit Caption

await ig.media.edit('3193593212003331660', 'new caption goes here', {
  usertags: { in: [{ user_id: '12345', position: [0.5, 0.5] }] }
});

Enable / Disable Comments

await ig.media.disableComments('3193593212003331660');
await ig.media.enableComments('3193593212003331660');

Download Media

// download by URL
const buffer = await ig.media.downloadByUrl('https://instagram.cdnurl.com/...');

// download by PK (photo or video)
const photo = await ig.media.downloadPhoto('3193593212003331660');
const video = await ig.media.downloadVideo('3193593212003331660');

oEmbed

const oembed = await ig.media.oembed('https://www.instagram.com/p/CxR7Bsejq5M/');
console.log(oembed.title, '-', oembed.author_name);

Get User Who Posted a Media

const user = await ig.media.getUser('3193593212003331660');

Reels / Clips

Upload and browse Reels through the REST API.

Upload a Reel

const result = await ig.clip.upload({
  videoBuffer: fs.readFileSync('./reel.mp4'),
  caption: 'check this out',
  coverImage: fs.readFileSync('./cover.jpg'), // optional
  duration: 15,
  width: 1080,
  height: 1920,
  audisMuted: false,
});
console.log('Reel PK:', result.media?.pk);

Configure a Video as Reel (after uploading separately)

const configured = await ig.clip.configure({
  upload_id: uploadId,
  caption: 'my reel',
  duration: 15,
  width: 1080,
  height: 1920,
});

Discover Reels / Connected Reels

// the explore-style reels feed
const discover = await ig.clip.discoverReels(10);
discover.items.forEach(reel => {
  console.log(reel.media.code, '-', reel.media.caption?.text?.substring(0, 40));
});

// paginate
const more = await ig.clip.discoverReels(10, discover.paging_info?.max_id);

// connected reels (similar reels after watching one)
const connected = await ig.clip.connectedReels(10);

Download a Reel

const reelBuffer = await ig.clip.download('3193593212003331660');

// or from URL
const reelFromUrl = await ig.clip.downloadByUrl('https://instagram.cdnurl.com/...');

Get Music Info for Reels

const music = await ig.clip.musicInfo({ music_canonical_id: '12345' });

Stories

Get Your Story Feed (Tray)

const tray = await ig.story.getFeed();
tray.tray.forEach(reel => {
  console.log(reel.user.username, '- stories:', reel.media_count);
});

Get Someone's Stories

const stories = await ig.story.getUserStories('25025320');
stories.reel?.items.forEach(item => {
  console.log('Type:', item.media_type, 'Taken at:', item.taken_at);
});

Upload a Photo Story

const result = await ig.story.upload({
  file: fs.readFileSync('./story.jpg'),
  caption: 'hello world', // optional
});
console.log('Story ID:', result.media?.pk);

Upload a Video Story

const result = await ig.story.uploadVideo({
  file: fs.readFileSync('./story.mp4'),
  duration: 10,
  width: 1080,
  height: 1920,
});

Mark Stories as Seen

await ig.story.seen([
  { id: 'media_id_1', taken_at: 1700000000, user: { pk: '25025320' } }
]);

React to a Story

await ig.story.react({
  mediaId: '3193593212003331660',
  reelId: '25025320',
  emoji: '🔥'
});

Highlights

Get User's Highlights

const highlights = await ig.highlights.getHighlightsTray('25025320');
highlights.tray.forEach(h => {
  console.log(h.id, '-', h.title);
});

Get a Specific Highlight

const highlight = await ig.highlights.getHighlight('highlight:12345678');

Create a Highlight

await ig.highlights.create('My Trip', ['story_id_1', 'story_id_2'], 'cover_media_id');

Edit a Highlight

await ig.highlights.edit('highlight_id', 'Updated Title', ['new_story_id']);

Add / Remove Stories from Highlight

await ig.highlights.addStories('highlight_id', ['story_id_3', 'story_id_4']);
await ig.highlights.removeStories('highlight_id', ['story_id_1']);

Update Highlight Cover

await ig.highlights.updateCover('highlight_id', 'cover_media_id');

Delete a Highlight

await ig.highlights.delete('highlight_id');

Upload & Configure Media

Upload a Photo Post

const upload = await ig.upload.photo({
  file: fs.readFileSync('./photo.jpg'),
});

const post = await ig.upload.configurePhoto({
  upload_id: upload.upload_id,
  caption: 'sunset vibes',
  usertags: {
    in: [{ user_id: '12345', position: [0.5, 0.5] }]
  }
});
console.log('Posted! PK:', post.media?.pk);

Upload a Video Post

const upload = await ig.upload.video({
  file: fs.readFileSync('./video.mp4'),
  duration: 30,
  width: 1080,
  height: 1920,
});

const post = await ig.upload.configureVideo({
  upload_id: upload.upload_id,
  caption: 'check this clip',
  duration: 30,
  width: 1080,
  height: 1920,
});

Configure as Reel (Clips)

const reel = await ig.upload.configureToClips({
  upload_id: upload.upload_id,
  caption: 'my first reel',
  duration: 15,
  width: 1080,
  height: 1920,
});

Configure as Story

const story = await ig.upload.configureToStory({
  upload_id: upload.upload_id,
});

Upload a Carousel (Multiple Photos/Videos)

const carousel = await ig.feed.uploadCarousel({
  caption: 'summer trip highlights',
  children: [
    { type: 'photo', file: fs.readFileSync('./pic1.jpg') },
    { type: 'photo', file: fs.readFileSync('./pic2.jpg') },
    { type: 'video', file: fs.readFileSync('./vid1.mp4'), duration: 10, width: 1080, height: 1080 },
  ]
});

Feed

Home Timeline

const feed = await ig.timeline.getFeed();
feed.feed_items?.forEach(item => {
  const media = item.media_or_ad;
  if (media) console.log(media.user.username, '-', media.caption?.text?.substring(0, 40));
});

Hashtag Feed

const tagFeed = await ig.feed.getTag('photography');

Location Feed

const locFeed = await ig.feed.getLocation('213385402');

Liked Posts

const liked = await ig.feed.getLiked();

Saved Posts

const saved = await ig.feed.getSaved();

Reels Tray (Stories of People You Follow)

const tray = await ig.feed.reelsTray();

Explore Feed

const explore = await ig.feed.getExploreFeed();

Reels Feed

const reels = await ig.feed.getReelsFeed();
const userReels = await ig.feed.getUserReelsFeed('25025320');

Reels Media (Bulk)

// get stories for multiple users at once
const reelsMedia = await ig.feed.reelsMedia(['25025320', '12345678']);

Timeline (Reels)

// get reels from your timeline
const reels = await ig.timeline.reels(10);

// explore reels
const exploreReels = await ig.timeline.exploreReels(10);

Direct Messages (REST API)

The REST-based DM methods. These work without MQTT — they're regular HTTP requests.

Get Inbox

const inbox = await ig.direct.getInbox();
inbox.inbox.threads.forEach(t => {
  console.log(t.thread_title || t.users[0]?.username, '- last:', t.last_permanent_item?.text);
});

// paginate
const page2 = await ig.direct.getInbox(inbox.inbox.oldest_cursor, 20);

Pending Inbox (Message Requests)

const pending = await ig.direct.getPendingInbox();

Get a Thread

const thread = await ig.direct.getThread(threadId);
thread.thread.items.forEach(msg => {
  console.log(msg.user_id, ':', msg.text || `[${msg.item_type}]`);
});

Send Text via REST

There are multiple ways to send a text message via the REST API:

// Method 1: By username (auto-resolves user ID and thread)
await ig.direct.send({ to: 'target_username', message: 'hey there!' });

// Method 2: By user ID (skips username lookup)
await ig.direct.sendToUserId('25025320', 'hey there!');

// Method 3: By thread ID (for existing conversations / groups)
await ig.directThread.sendToGroup({ threadId: threadId, message: 'hey there!' });

// Method 4: Low-level broadcast (full control)
// Use threadIds to send to existing threads:
await ig.directThread.broadcast({
  threadIds: [threadId],
  item: 'text',
  form: { text: 'hey there!' },
});

// Or use userIds to send to users directly (creates thread if needed):
await ig.directThread.broadcast({
  userIds: ['25025320'],
  item: 'text',
  form: { text: 'hey there!' },
});

Send Photo / Video / Link via REST

All convenience methods use to (Instagram username) to identify the recipient:

await ig.direct.sendImage({
  to: 'target_username',
  imagePath: './photo.jpg',
});

await ig.direct.sendVideo({
  to: 'target_username',
  videoPath: './video.mp4',
});

await ig.direct.sendLink({
  to: 'target_username',
  text: 'check this out',
  urls: ['https://example.com'],
});

Share Media / Profile / Hashtag / Location

await ig.direct.sendMediaShare({ to: 'target_username', mediaId: '3193593212003331660' });
await ig.direct.sendProfile({ to: 'target_username', profileUserId: '25025320' });
await ig.direct.sendHashtag({ to: 'target_username', hashtag: 'photography' });
await ig.direct.sendLocation({ to: 'target_username', locationId: '213385402' });

Create a Group Thread

const group = await ig.direct.createGroupThread(['user_id_1', 'user_id_2'], 'Project Team');
console.log('Thread ID:', group.thread_id);

Ranked Recipients (Who to Message)

const recipients = await ig.direct.rankedRecipients('raven', 'john');

Get Presence

const presence = await ig.direct.getPresence();

Mark as Seen / Hide Thread

await ig.direct.markAsSeen(threadId, itemId);
await ig.direct.hideThread(threadId);

Send Raven (View-Once) Photo / Video via REST

Send disappearing photos and videos in DMs. These use the REST endpoint, no MQTT needed. The helpers handle the full flow — upload to rupload.facebook.com/messenger_image/ + broadcast via /direct_v2/threads/broadcast/raven_attachment/ — in a single call.

const { sendRavenPhotoOnce, sendRavenPhotoReplayable, sendRavenVideoOnce } = require('nodejs-insta-private-api-mqt');
const fs = require('fs');

// view-once photo (disappears after one view)
const photoBuffer = fs.readFileSync('./secret.jpg');
await sendRavenPhotoOnce(ig, photoBuffer, {
  threadId: threadId
});

// replayable photo (can replay, still disappears)
await sendRavenPhotoReplayable(ig, photoBuffer, {
  threadId: threadId
});

// view-once video
const videoBuffer = fs.readFileSync('./secret_clip.mp4');
await sendRavenVideoOnce(ig, videoBuffer, {
  threadId: threadId,
  duration: 8,
  width: 720,
  height: 1280
});

Friendship Management

Follow / Unfollow

await ig.friendship.create('25025320');  // follow
await ig.friendship.destroy('25025320'); // unfollow

Check Friendship Status

const status = await ig.friendship.show('25025320');
console.log('Following:', status.following);
console.log('Followed by:', status.followed_by);
console.log('Blocking:', status.blocking);

// bulk check
const many = await ig.friendship.showMany(['12345', '67890']);

Approve / Ignore Follow Requests

await ig.friendship.approve('25025320');
await ig.friendship.ignore('25025320');

// list pending requests
const pending = await ig.friendship.getPendingRequests();

Block / Unblock

await ig.friendship.block('25025320');
await ig.friendship.unblock('25025320');

const blocked = await ig.friendship.getBlockedUsers();

Restrict / Unrestrict

await ig.friendship.restrict('25025320');
await ig.friendship.unrestrict('25025320');

Mute / Unmute

await ig.friendship.mute('25025320', { muteStories: true, mutePosts: true });
await ig.friendship.unmute('25025320', { unmuteStories: true, unmutePosts: true });

Close Friends / Besties

// add someone to close friends
await ig.friendship.setCloseFriend('25025320', true);
// remove
await ig.friendship.setCloseFriend('25025320', false);

// bulk update close friends list
await ig.friendship.setBesties(['user1', 'user2'], ['user3']); // add, remove

Favorites

await ig.friendship.setFavorite('25025320');
await ig.friendship.unsetFavorite('25025320');

const favorites = await ig.friendship.getFavoriteFriends();

Remove Follower

await ig.friendship.removeFollower('25025320');

Get Followers / Following

const followers = await ig.friendship.getFollowers('25025320');
const following = await ig.friendship.getFollowing('25025320');
const mutual = await ig.friendship.getMutuafFollowers('25025320');

Search (FBSearch)

Instagram's unified search endpoint. Covers users, hashtags, places, and music.

Top Search (All Types)

const results = await ig.fbsearch.topSearch('coffee shop');
console.log('Users:', results.users?.length);
console.log('Places:', results.places?.length);
console.log('Hashtags:', results.hashtags?.length);

// flat version (simpler output)
const flat = await ig.fbsearch.topSearchFlat('coffee', 30);

Search by Type

const users = await ig.fbsearch.searchUsers('johndoe', 20);
const hashtags = await ig.fbsearch.searchHashtags('photography', 20);
const places = await ig.fbsearch.searchPlaces('new york');
const music = await ig.fbsearch.searchMusic('trending');

Search History

const recent = await ig.fbsearch.getRecentSearches();

// clear it
await ig.fbsearch.clearRecentSearches();

// manually add something to recent searches
await ig.fbsearch.registerRecentSearch('25025320', 'user');

Suggested Searches

const suggested = await ig.fbsearch.getSuggestedSearches('users');

Null State (Default Explore)

const nullState = await ig.fbsearch.nullStateDynamic();

Explore

Topical Explore

const explore = await ig.explore.topicalExplore({
  module: 'explore_popular',
  cluster_id: 'explore_all:0',
});

// basic explore
const basic = await ig.explore.explore();
// paginate
const page2 = await ig.explore.explore(basic.next_max_id);

Report Explore Media

await ig.explore.reportExploreMedia('3193593212003331660', 1);

Mark Explore as Seen

await ig.explore.markAsSeen();

Notes

Instagram Notes — the little status messages that show up in the DM tab.

// get all notes from people you follow
const notes = await ig.note.getNotes();
const followingNotes = await ig.note.getNotesFollowing();

// create a note (audience: 0 = followers, 1 = close friends)
await ig.note.createNote('currently building something cool', 0);

// delete your note
await ig.note.deleteNote('note_id_here');

// mark notes as seen
await ig.note.lastSeenUpdateNote();

Insights (Business/Creator Accounts)

Requires a business or creator account.

// account-level insights
const accountInsights = await ig.insights.account({
  ig_drop_table: 'is_feed',
  follower_type: 'followers',
  timeframe: 'one_week',
  query_params: JSON.stringify({ access_token: '', id: '' })
});

// insights for a specific post
const mediaInsights = await ig.insights.media('3193593212003331660');

// reel insights
const reelInsights = await ig.insights.reelInsights('3193593212003331660');

// story insights
const storyInsights = await ig.insights.storyInsights('3193593212003331660');

// all media feed insights
const allMedia = await ig.insights.mediaFeedAll({ count: 20 });

Notifications

Fine-grained control over push notification settings.

// mute all notifications for 8 hours
await ig.notification.muteAll('8_hour');

// disable all notifications
await ig.notification.disableAll();

// control individual notification types
await ig.notification.likes('off');
await ig.notification.comments('off');
await ig.notification.newFollower('off');
await ig.notification.commentLikes('off');
await ig.notification.directShareActivity('off');
await ig.notification.login('off');
await ig.notification.reminders('off');

// and many more: userTagged, firstPost, followRequestAccepted,
// connection, taggedInBio, pendingDirectShare, directGroupRequests,
// fundraiserSupporter, announcements, reportUpdated...

Music / Audio Tracks

// search for music
const tracks = await ig.track.search('trending pop');

// get track info
const trackInfo = await ig.track.infoById('track_id_here');
const trackByCanonical = await ig.track.infoByCanonicalId('canonical_id');

// download audio
const audioBuffer = await ig.track.downloadByUrl('https://instagram.cdnurl.com/...');

Signup (Account Creation)

Programmatic account creation flow.

// check if email/username is available
const emailCheck = await ig.signup.checkEmail('[email protected]');
const usernameCheck = await ig.signup.checkUsername('desired_username');

// get signup config
const config = await ig.signup.getSignupConfig();

// check age eligibility
await ig.signup.checkAgeEligibility(1995, 6, 15);

// send verification email and confirm
await ig.signup.sendVerifyEmail('[email protected]');
await ig.signup.checkConfirmationCode('[email protected]', '123456');

// phone-based signup
await ig.signup.sendSignupSmsCode('+1234567890');
await ig.signup.validateSignupSmsCode('+1234567890', '123456');

// get username suggestions
const suggestions = await ig.signup.getSuggestedUsernames('John Doe', '[email protected]');

// create the account
const newAccount = await ig.signup.accountsCreate({
  username: 'johndoe_2026',
  password: 'securepassword123',
  email: '[email protected]',
  first_name: 'John',
});

Multiple Accounts

const family = await ig.multipleAccounts.getAccountFamily();
const featured = await ig.multipleAccounts.getFeaturedAccounts();
const info = await ig.multipleAccounts.getAccountInfo();

// switch to another logged-in account
await ig.multipleAccounts.switchAccount('other_user_id');

Fundraiser

// get fundraiser info
const info = await ig.fundraiser.standaloneFundraiserInfo('fundraiser_pk');

// create a charity fundraiser
const fundraiser = await ig.fundraiser.createCharityFundraiser({
  title: 'Help Local School',
  description: 'Raising funds for supplies',
  charity_id: 'charity_pk',
  goal_amount: 5000,
});

// donate
await ig.fundraiser.donateFundraiser('fundraiser_pk', 25);

Captcha / Challenge Forms

// get challenge form (when Instagram shows a captcha)
const form = await ig.captcha.getChallengeForm('/api/v1/challenge/1234/');

// submit reCAPTCHA or hCaptcha response
await ig.captcha.submitRecaptchaResponse('/api/v1/challenge/1234/', 'recaptcha_token');
await ig.captcha.submitHCaptchaResponse('/api/v1/challenge/1234/', 'hcaptcha_token');

Share / URL Parsing

// decode a share code (from QR codes, NFC tags, etc.)
const info = ig.share.shareInfo('base64_encoded_code');
// returns { type: 'user', pk: '25025320' }

// parse from URL
const fromUrl = ig.share.shareInfoByUrl('https://www.instagram.com/share/abc123');

// extract share code from URL
const code = ig.share.shareCodeFromUrl('https://www.instagram.com/share/abc123');

Bloks (Instagram Bloks Engine)

Low-level access to Instagram's Bloks framework. Used internally by some flows.

await ig.bloks.action({
  action_name: 'some.action.name',
  params: { key: 'value' }
});

const layout = await ig.bloks.getLayoutData({
  layout_name: 'layout.name',
  params: {}
});

// bloks-based password change
await ig.bloks.changePassword('old_pass', 'new_pass');

Complete REST Repository Reference

Here's every repository and what it covers at a glance.

| Repository | Access | What it does | |------------|--------|--------------| | ig.account | Account management | Login, 2FA, edit profile, change password, privacy | | ig.user | User operations | Info, search, follow, block, mute, get medias/reels/stories | | ig.media | Media operations | Like, comment, pin, delete, save, archive, download | | ig.clip | Reels / Clips | Upload, discover, download reels | | ig.story | Stories | Upload, view, react, highlights | | ig.highlights | Highlights | Create, edit, delete, manage cover | | ig.feed | Content feeds | Timeline, hashtag, location, saved, liked, explore | | ig.timeline | Timeline reels | Reels feed, explore reels | | ig.upload | Upload & configure | Photo/video upload, configure to feed/story/clips | | ig.direct | Direct messages | Inbox, send text/media/links, raven (view-once), group threads | | ig.friendship | Relationships | Follow, block, restrict, close friends, favorites | | ig.fbsearch | Search | Users, hashtags, places, music, search history | | ig.explore | Explore page | Topical explore, report, mark seen | | ig.insights | Analytics | Account, media, reel, story insights | | ig.note | Notes | Create, delete, view notes | |