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

@alaminnna/ica-unofficial

v2.9.0

Published

Unofficial Instagram Chat API for Node.js ? fca-style. Login, send messages, listen to events.

Downloads

1,115

Readme

npm version npm downloads License: MIT Node.js

Interact with Instagram DM programmatically. Built for bot developers.

⚡ Realtime MQTT listener + FBNS push — pure JavaScript, CommonJS, lightweight deps.

Installation • Basic Usage • API Reference • npm • Issues


I maintain this to keep Instagram bot building simple in Node.js. Small win by small win — faster reply paths, cleaner logs, and full DM surface coverage. — Al A Min

ICA (@alaminnna/ica-unofficial) is an unofficial Instagram Chat API for Node.js with fca-style ergonomics. It drives a user account: login once, send messages, listen for new ones — over HTTPS + realtime MQTT.

Keywords: instagram chat api nodejs, insta fca, unofficial instagram api, mqtt chatbot, instagram dm bot, alaminnna

🌟 What's New

  • 💬 Comments — post, like/unlike, pin/unpin, bulk delete, offensive check, paged list
  • 🧵 Direct room management — create/hide/retitle/add-users, unread, mute, presence, message search, spam inbox
  • 💾 Collections + Highlights — full saved/highlight CRUD
  • 🔍 Discovery — hashtag module, location, music detail, SERP surfaces, private mobile-GQL lists
  • 📖 Stories — info, likers, like, poll vote, sticker tray, archive, highlights
  • 🔔 Account — notification center (28 toggles), news inbox, AI label, USDID attestation, legacy signup
  • 👥 Users 100% surface — follow requests, close friends, mutes, friendship, about, chaining, stream + GQL lookups
  • 📊 Speed proof — MQTT typing RTT next to HTTP reply times

📦 Installation

npm install @alaminnna/ica-unofficial

Or with yarn:

yarn add @alaminnna/ica-unofficial

Requires Node.js >= 14. Plain CommonJS, no TypeScript build step. Ships index.js + src/ + LICENSE. Optional native helpers (better-sqlite3 for the listen() snapshot store, sharp for photo resize) install when supported and degrade gracefully when absent. ESM works too: import { login, ChallengeRequired } from '@alaminnna/ica-unofficial'.

⚠️ Important Disclaimer

We are not responsible if your account gets restricted for spammy activities such as:

  • Sending lots of messages to people you don't know
  • Sending messages very quickly
  • Logging in and out very quickly
  • Running aggressive follow/unfollow/report automation

Recommendation: use a test account, go slow, respect rate limits (writes are rate-guarded by default), and never commit real credentials or session files.

🔍 Introduction

Instagram's official API surface is built for businesses and creators — automating a user account's DMs needs the same private endpoints the app itself uses.

@alaminnna/ica-unofficial speaks those endpoints for you:

  • Making the exact same GET/POST requests as the app
  • Login with username/password (2FA + challenge aware) or a saved session
  • Realtime delivery over MQTT with polling fallback — no scraping

🚀 Basic Usage

1. Login and save the session

const { login } = require('@alaminnna/ica-unofficial');

const api = await login({ username: 'you', password: 'secret' });
api.saveSession('./session.json');

2. Resume from a saved session (no password needed)

const { login } = require('@alaminnna/ica-unofficial');

const api = await login({ session: require('./session.json') });

3. Send a message (promise or fca callback style)

const info = await api.sendMessage({ text: 'hello', threadId: '123' });
api.sendMessage('hello', '123', (err, info) => {});

4. Listen + reply, bot-style

const stop = await api.listen(async (event) => {
  if (event.type === 'message' && event.body === '.ping') {
    await api.sendMessage({ text: 'pong!', threadId: event.threadID });
  }
});
// stop() ends listening cleanly

5. Send a photo

await api.sendPhoto({ path: './pic.jpg', threadId: '123' });
await api.sendPhoto({ url: 'https://example.com/pic.jpg', threadId: '123' });

Tip: threadId also accepts full pk_userid ids, and most send methods accept userIds to auto-resolve the thread.

🔄 Auto-update check

Every login() first checks the npm registry for a newer release (cached for 6h, 8s timeout). When outdated, it runs npm install @alaminnna/ica-unofficial@latest in your project, then continues logging in — restart the process to run the new version. Registry/install failures never block login; they only log.

await login({ username: 'you', password: 'secret' }); // checks + auto-updates
await login({ username: 'you', password: 'secret', autoUpdate: false }); // check only, no install
await login({ session, skipUpdateCheck: true }); // no check at all

Env overrides: ICA_SKIP_UPDATE_CHECK=1 (no check), ICA_AUTO_UPDATE=0 (check, no install). Manual check: const { checkForUpdate } = require('@alaminnna/ica-unofficial').

✨ Features

  • Login two ways: credentials (2FA + challenge aware) or saved session
  • Send text/link, photo, video, voice notes, files, cutout stickers; replies
  • Threads, inbox, spam box, pending requests (list/count/approve)
  • Reactions, heart likes, unsend/delete, mark-seen, typing indicator
  • Realtime MQTT listener + FBNS push registration
  • Comments, collections, highlights, stories, notes (text + music)
  • Users 100% surface — follow requests, close friends, mutes, friendship, discovery, GQL lookups
  • Upload: photo/video/reel/album/IGTV (+music, schedule, crosspost)
  • Media manage: edit/archive/pin/seen/oembed/livestream
  • Discovery: topsearch, places, hashtags, music, insights, private-GQL lists
  • Account: profile, security, confirm flows, notifications, USDID, legacy signup
  • Proxy support (http/https/socks), anti-ban delays, fastMode

⚡ Realtime Listener

Two modes, one event surface. listenMode option: mqtt (default path via auto), polling, or auto (try MQTT, degrade on failure).

| | MQTT | Polling fallback | |---|---|---| | Detection | instant (<1s) | ~3s snapshot diff | | Typing/presence/seen | live | not available | | Transport | TLS socket + Thrift | plain HTTPS inbox |

const stop = await api.listen((event) => {
  console.log(event.type, event.body);
}, { listenMode: 'auto' });

auto falls back after 3 drops in 2 min (warn logged) or immediately when polling is forced. Auth failures halt with session_expired (polling cannot help a dead session). Reconnects rebuild auth params from the live session automatically, resume from the last seq_id, and dedupe by item_id (LRU-capped at 500 — no double-fire on replay).

Events: message, typing (alias typ), presence, seen (alias read_receipt), event, session_expired.

📡 Realtime & FBNS (Advanced)

Experimental: this rides Instagram's private MQTT transport, which Instagram can change at any time. HTTP Direct methods stay the source of truth for media and complex ops — MQTT actions cover text/reaction/seen/activity only.

Stateful client (api.realtimeConnect() returns a RealtimeClient, EventEmitter style):

| Method | What it does | |---|---| | realtimeConnect({transport?}) / realtimeDisconnect() | connect / teardown (singleton per client) | | realtimeOn(event, handler) / realtimePing() / realtimeReadOnce() | subscribe / PINGRESP await / read + dispatch one packet | | directSendText(threadId, text) | send_item text over MQTT (no HTTP round-trip) | | directSendReaction(threadId, itemId, emoji) | send_item reaction over MQTT | | directMarkSeen(threadId, itemId) | mark_seen over MQTT | | directIndicateActivity(threadId, isActive) | typing indicator over MQTT | | directSubscribe(amount?) / irisSubscribe(seqId, snapshotAtMs) | inbox sync + seq resume (no gaps on reconnect) | | graphQlSubscribe(list) / skywalkerSubscribe(list) | raw topic subscribe (advanced) | | sendForegroundState(state) / publishJson(topic, data) | raw publish helpers | | fbnsConnect() / fbnsDisconnect() / fbnsOn() / fbnsPing() | FBNS push channel (mqtt-mini.facebook.com) |

Not connected → realtime actions throw RealtimeNotConnected (no silent fallback). send_response events carry the matching client_context.

Events (raw kept in event.raw): receive (every decoded publish), message (message-sync), direct (parsed Direct payloads), typing / seen / presence (subsets of direct), send_response, iris_sub_response, realtime_sub. FBNS: push (parsed fbpushnotif), collapse_key names (e.g. direct_v2_message), reg_response, registered, logging, pp.

fbns_auth persists in the session file (survives restarts, reused on later runs) and is never logged — use maskFbnsAuth() before any FBNS state reaches logs.

📚 API Reference

| Method | Signature | Description | |---|---|---| | login | login(options, cb?) | credentials or {session\|cookies}; callback + promise | | getThreads | (options?) | inbox threads (amount/filter/box) | | getThread | (threadId, options?) | thread + message history | | getMessages | (threadId, options?) | messages only | | sendMessage | ({text, threadIds\|userIds, replyTo?}, cb?) | text/link (+reply) | | sendReply | (threadId, text, replyTo, cb?) | reply shortcut | | sendPhoto | ({path\|url, threadId\|userIds}, cb?) | JPEG photo | | sendVideo | ({path\|url, threadId\|userIds}, cb?) | H.264 MP4 | | sendVoice | ({path, threadId\|userIds}, cb?) | AAC m4a voice note | | sendFile | ({path\|url, threadId}, cb?) | photo/video by extension | | sendReaction / deleteReaction | (threadId, messageId, emoji?, cb?) | reaction set/remove | | likeDirectMessage / unlikeDirectMessage | (threadId, messageId, cb?) | heart like toggle | | setMessageReaction | ({emoji, messageId, threadId}, cb?) | react (use deleteReaction to remove) | | unsendMessage | (threadId, messageId, cb?) | unsend (= delete) | | deleteMessage | (threadId, messageId, cb?) | delete | | markThreadSeen | (threadId, messageId, cb?) | mark seen (MQTT fast path when connected) | | setTyping | (threadId, bool, cb?) | typing indicator (MQTT fast path when connected) | | sendTyping | (threadId) | fire-and-forget typing via MQTT | | listen / listenMqtt | (onEvent, options?) | realtime events, returns stop() (keeps a local snapshot store in ./ica-alaminnna/ unless store: false) | | realtimeConnect / realtimeDisconnect | (options?) | stateful MQTT client | | realtimeOn / realtimePing / realtimeReadOnce | (…) | subscribe / ping / single read | | directSendText / directSendReaction | (…, cb?) | MQTT direct actions | | directMarkSeen / directIndicateActivity | (…, cb?) | MQTT seen / typing | | directSubscribe / irisSubscribe | (…) | inbox sync + seq resume | | fbnsConnect / fbnsDisconnect / fbnsOn / fbnsPing | (…) | FBNS push channel | | createThread | ({userIds, title?}, cb?) | group thread create | | hideThread | (threadId, moveToSpam?, cb?) | hide (spam optional) | | updateThreadTitle / addUsersToThread | (threadId, ...) | retitle / add users | | removeMember | (threadId, users, cb?) | kick (admin-gated, clear error otherwise) | | leaveGroup | (threadId, cb?) | self-leave (live-confirmed) | | resolveGroupInvite | (link\|code, cb?) | resolve invite landing (join unconfirmed) | | setGroupTitle | (threadId, title, cb?) | admin-gated retitle | | getThreadAdmins | (threadId, cb?) | admins with refresh (latest wins) | | getGroupMembers | (threadId, cb?) | members with profile pics | | inspectAccount | (username\|userId, cb?) | flags + labeled bot signals | | markThreadUnread | (threadId, cb?) | mark unread | | muteThread / unmuteThread | (threadId, cb?) | thread mute toggle | | muteVideoCall / unmuteVideoCall | (threadId, cb?) | video-call mute toggle | | setE2eeEligibility | (value?, cb?) | e2ee state (default 4) | | getSpamInbox / getSpamInboxChunk | (amount?/cursor?, cb?) | spam inbox (paged) | | searchMessages | (query, cb?) | message-text search | | getUsersPresence / getActivePresence | (userIds?, cb?) | presence | | searchGenAiBots / getChannels | (…) | AI bots / channels | | searchThreads | (query, mode?, cb?) | ranked thread search | | getThreadByParticipants | (userIds, cb?) | thread lookup | | sendCutoutSticker | ({stickerId, threadId}, cb?) | cutout sticker share | | shareMedia | ({mediaId\|mediaUrl, threadId}, cb?) | share a post/reel | | shareStory | ({storyId, threadId}, cb?) | share a story | | shareProfile | ({userId, threadId}, cb?) | share a profile | | getUserInfo | (userId, cb?) | normalized profile | | getUserInfoByUsername | (username, cb?) | normalized profile | | getUserIdFromUsername | (username, cb?) | numeric id string | | getUsernameFromUserId | (userId, cb?) | username from id (cached + GQL fallback) | | getFollowers | ({userId, amount, order?}, cb?) | followers page (amount small!) | | getFollowing | ({userId, amount}, cb?) | following page | | getMutualFollowers | ({userId, amount}, cb?) | local intersection | | getFollowersChunk / getFollowingChunk | (options?, cb?) | {users, nextCursor} pages | | iterUserFollowers / iterUserFollowing | (options?) | async-generator streaming | | getFollowersPrivateGql / getFollowingPrivateGql | (options?, cb?) | mobile-GQL follow lists | | follow / unfollow | ({userId}, cb?) | rate-guarded writes | | block / unblock | ({userId, surface?}, cb?) | surface: profile | direct_thread_info | | getFriendship / getUserFriendship | (userId, cb?) | flags / following-vs-outgoing classifier | | getUserFriendships | (userIds, cb?) | bulk show_many | | getCreatorInfo | (userId, entryPoint?, cb?) | creator info + user | | getFollowRequests / getFollowRequestsChunk | (options?, cb?) | private-account follow inbox (paged) | | approveFollowRequest / declineFollowRequest | (userId, cb?) | single approve / decline | | approveFollowRequests / declineFollowRequests | (userIds, cb?) | sequential batch → {id: bool} | | closeFriendAdd / closeFriendRemove | (userId, cb?) | besties (wires to story audience) | | mutePostsFromFollow / unmutePostsFromFollow | (userId, cb?) | post mute toggle | | muteStoriesFromFollow / unmuteStoriesFromFollow | (userId, cb?) | story mute toggle | | setPostsNotifications / setVideosNotifications | (userId, enabled, cb?) | post/video favorites | | setReelsNotifications / setStoriesNotifications | (userId, enabled, cb?) | reels/story favorites | | removeFollower / reportUser | (userId[, reason], cb?) | remove / FRX spam report | | searchFollowers / searchFollowing | (userId, query, cb?) | in-list search | | getUserAbout / getUserGuides | (userId, cb?) | about-this-account / guides | | getChaining / fetchSuggestionDetails | (userId[, chainedIds], cb?) | suggestion surfaces | | getSuggestedProfiles / getRelatedProfiles | (userId[, expand], cb?) | suggested (gated → chaining fallback) | | getRecommendedAccountsForCategory | (userId, cb?) | business-category similars | | linkAddressBook / unlinkAddressBook | (contacts[, include], cb?) | contact upload (explicit only) | | getUserShortGql / getUserInfoV2Gql | (userId, cb?) | doc_id GraphQL lookups | | getUserInfoByUsernameV2Gql | (username, cb?) | doc_id search + profile | | getUserStreamById / getUserStreamByUsername | (id, cb?) | streamed envelopes | | getUserStreamByIdFlat / getUserStreamByUsernameFlat | (id, cb?) | merged user dicts | | getWebProfileInfo | (username, cb?) | private-host web profile | | getFeedUserStreamItem | (itemId, pullToRefresh?, cb?) | streamed feed item | | getUserMedias | ({userId, amount}, cb?) | user posts | | getUserTags | ({userId, amount}, cb?) | tagged medias | | getUserMediasPaginated / getUserTagsPaginated | ({userId, amount?, endCursor?}, cb?) | cursor pages | | iterUserMedias | ({userId, pageSize?}) | async iterator | | getPendingRequests | (options?, cb?) | pending threads | | getAccountInfo | (cb?) | full private account info | | editAccount | (fields, cb?) | edit profile (merges email/phone) | | setBiography | (text, cb?) | set bio | | getNewsInbox | (markAsSeen?, cb?) | news inbox | | setAiInfoLabel | (enabled, cb?) | AI-generated label toggle | | setNotificationSetting | (contentType, value, cb?) | app notification toggle | | muteAllNotifications / disableAllNotifications | (value?, cb?) | mute-all / disable-all | | notificationLikes / notificationComments / … (25) | (value?, cb?) | per-type toggles | | setExternalUrl | (url, cb?) | set external URL | | getBioLinks / removeBioLinks | (linkIds?, cb?) | list / remove bio links | | changeProfilePicture | ({uploadId}, cb?) | change avatar | | setPrivate / setPublic | (cb?) | visibility toggle | | convertToBusiness / convertToCreator | (categoryId?, opts?, cb?) | professional conversion | | convertToProfessional | (2\|3, categoryId?, opts?, cb?) | conversion core | | getSecurityInfo | (cb?) | 2FA state, backup codes | | changePassword | (old, new, cb?) | rate-guarded, never logged | | sendPasswordReset | (identifier, cb?) | sends link (www ajax) | | sendConfirmEmail / confirmEmail | (email[, code], cb?) | email two-step | | sendConfirmPhone / confirmPhone | (phone[, code], cb?) | phone two-step | | checkEmail / checkUsername / checkPhoneNumber | (…) | availability checks | | sendSignupSmsCode / sendVerifyEmail | (…) | code delivery | | checkConfirmationCode / checkAgeEligibility | (…) | code / age checks | | accountsCreate / signup | (options) | legacy registration | | getFeaturedAccounts / getAccountFamily | (…) | featured / family | | usdidGenerate / usdidRegister | (…) | USDID identity + registration | | usdidPublicKeyDer / usdidHeader | (…) | key DER / signed header | | attestationCreateAndroidKeystore / attestationParams | (…) | keystore nonce flow | | generateTOTP | (seed, opts?) | RFC 6238, zero deps | | getLikedMedias | (amount?, cb?) | medias you liked | | getMediaLikers | (mediaId, cb?) | who liked a media | | getCommentReplies | (mediaId, commentId, amount?, cb?) | comment replies | | getComments / getCommentsChunk | ({mediaId, amount}, cb?) | paged comment list | | postComment | ({mediaId, text, repliedToCommentId?}, cb?) | post a comment | | likeComment / unlikeComment | (commentId, cb?) | like toggle | | pinComment / unpinComment | (mediaId, commentId, cb?) | pin toggle | | bulkDeleteComments | (mediaId, commentIds, cb?) | bulk delete | | checkOffensiveComment | (mediaId, text, cb?) | offensive? boolean | | getCommentLikers | (commentId, amount?, cb?) | likers via GQL | | getCollections / getCollectionIdByName | (…) | saved collections | | getCollectionMedias / getCollectionMediasChunk | (options?, cb?) | collection medias (paged) | | getCollectionMediasByName | (options?, cb?) | medias by collection name | | saveMedia / unsaveMedia | (options?, cb?) | save toggle | | uploadPhoto | ({path\|url, caption?, usertags?, location?, extraData?, scheduleAt?, coauthorUserIds?, shareToFacebook?, shareToThreads?}, cb?) | feed photo publish | | uploadVideo | ({path\|url, caption?, thumbnail?, ...same}, cb?) | feed video publish | | uploadAlbum | ({paths[], caption?, usertags? (nested per-item), ...same}, cb?) | carousel publish | | uploadIGTV | ({path, title, caption?, thumbnail?, ...}, cb?) | IGTV publish (signed) | | uploadReel | ({path\|url, caption?, thumbnail?, topics?, trial?, showPreviewInFeed?, ...}, cb?) | reel publish (signed) | | uploadPhotoWithMusic / uploadAlbumWithMusic / uploadReelWithMusic | ({..., track, alacornSessionId?}, cb?) | music metadata attach (no mux) | | clipTrialEligible | (cb?) | trial reels preflight | | clipInterestTopics | (cb?) | topic catalog (name+fit_id) | | changeReelCover | (mediaPk, coverPath, cb?) | published reel cover | | deleteMedia | (mediaId, cb?) | delete own post | | editMedia | ({mediaId, caption, title?, usertags?, location?}, cb?) | edit caption/tags | | linkReel | (mediaId, targetMediaId, linkName?, cb?) | link reels | | archiveMedia / unarchiveMedia | (mediaId, cb?) | archive toggle | | getArchivedMedias | (amount?, cb?) | archived list | | pinMedia / unpinMedia / pinReel / unpinReel | (mediaPk, cb?) | profile/reel pin | | markMediaSeen / markClipsSeen | (mediaIds[], skipped?/blend?, cb?) | seen-state | | getMediaOembed / getMediaAuthor / getMediaInfoV2 | (url\|pk\|id, cb?) | oembed/author/v2 fallback | | videoRefreshResources | (mediaId, cb?) | refresh expired video URLs | | createMediaNote / deleteMediaNote | ({mediaId, text?}\|noteId, cb?) | post-attached notes | | createLivestream / startLivestream / endLivestream | (title?\|broadcastId, cb?) | live block (RTMP out of scope) | | getLivestreamInfo / getLivestreamComments / getLivestreamViewers | (broadcastId, cb?) | live reads | | getTimelineFeed / getReels / getExploreReels / getFriendsReels | (options?, cb?) | home feed + reels | | getUserClips / getUserVideos | ({userId, amount?}, cb?) | reels/videos by user | | uploadCutoutSticker | ({path}, cb?) | cutout sticker | | uploadPhotoStory / uploadVideoStory | ({path\|url, caption?, mentions?, links?, hashtags?, locations?, medias?, stickers?, polls?, threadIds?}, cb?) | story publish | | deleteStory | (storyId, cb?) | delete story | | storyBuilder | (background) | chainable composer → .build() | | getStoryViewers | ({storyPk, amount?}, cb?) | who viewed | | getStoryTray | (options?, cb?) | followed users' stories | | highlightPkFromUrl | (url) | pk from highlight URL | | getUserHighlights | (userId, amount?, cb?) | highlight tray | | getHighlightInfo | (highlightId, cb?) | single highlight | | createHighlight | ({title, storyIds, coverStoryId?}, cb?) | create | | editHighlight | (highlightId, options?, cb?) | add/remove/title/cover | | changeHighlightTitle / changeHighlightCover | (…) | title / cover from file | | addStoriesToHighlight / removeStoriesFromHighlight | (highlightId, storyIds, cb?) | story membership | | deleteHighlight | (highlightId, cb?) | delete | | getStoryInfo | (storyId, cb?) | story by pk_userid | | getStoryLikers / getStoryLikersChunk | (storyId, cb?) | likers (paged) | | likeStory / unlikeStory | (storyId, cb?) | heart toggle (seen first) | | voteStoryPoll | (storyId, pollId, vote, cb?) | poll vote | | getStickerTray | (cb?) | static sticker tray | | getArchiveStoryDays / getArchiveStories | (options?, cb?) | archive | | shareMediaToStory | ({mediaId, background, caption?}, cb?) | feed post as story | | searchLocations / getLocationInfo / getLocationMedias | ({lat,lng}\|pk\|{locationPk,...}, cb?) | places | | getLocationMediasTop / getLocationMediasRecent | (pk, amount?, cb?) | ranked / recent place medias | | searchLocationsByName / searchLocationByPk | (name\|pk, cb?) | name / exact-pk lookup | | completeLocation / buildLocation / locationStoryStickerId | (…) | smart fill / upload JSON / sticker id | | getLocationGuides | (pk, cb?) | place guides | | getAccountInsights / getMediaInsights | (\|mediaPk, cb?) | insights (business) | | searchMusic / musicInFeedBrowser / musicTrending | (query\|..., cb?) | track discovery | | searchMusicV2 / musicKeywordSearch | (query, options?, cb?) | v2 search / typeahead keywords | | bookmarkTrack / bookmarkedTracks | (audioId, cb?) | bookmark / saved tracks | | clipsAudioBrowser / verifyAudioTitle | (…) | clips candidates / title check | | trackInfoByCanonicalId / trackInfoById / trackStreamInfoById | (id, cb?) | track detail | | topsearchFlat / searchUsersAdvanced / searchHashtags | (query, cb?) | blended/user/tag search | | searchUsers | (query, count?, cb?) | exact users/search port | | searchPlaces / searchMedias | (query, cb?) | place/media search | | webSearchTopsearch / webSearchTopsearchHashtags | (query, cb?) | web blended / hashtags | | fbsearchItem / keywordTypeahead / typeaheadStream / typeaheadUsers | (…) | raw item / typeahead | | recentSearches | (cb?) | recent searches | | searchAccountsV2 / searchReelsV2 / topsearchV2 | (query, cb?) | SERP surfaces | | suggestedProfiles | (userId, cb?) | fbsearch suggestions | | getHashtagInfo | (tag, cb?) | hashtag profile | | getHashtagMedias / getHashtagMediasTop / getHashtagMediasRecent / getHashtagMediasReels | (…) | tag medias by tab | | followHashtag / unfollowHashtag / getFollowedHashtags | (tag, cb?) | tag follow management | | getFollowersPrivateGql / getFollowingPrivateGql | (options?, cb?) | mobile-GQL follow lists | | getClipsProfileGql / getInboxTrayGql | (userId, cb?) | clips / inbox-tray GQL | | getFeedUserStreamItem | (itemId, pullToRefresh?, cb?) | streamed feed item | | createNote | ({text, audience}, cb?) | create note | | deleteNote | (noteId, cb?) | delete note | | notesMusicBrowser | (cb?) | notes music candidates | | createMusicNote | ({track, text, audience?}, cb?) | music note via inbox-tray GQL | | getPendingCount | (cb?) | {total, unread} | | approveRequest | (threadId, cb?) | approve a request |

Every method supports both promise and fca-style callback ((err, result)).

Errors are typed (require('@alaminnna/ica-unofficial').ChallengeRequired, SessionExpired, RealtimeNotConnected, … — full list in src/exceptions).

📋 Logging

One logger, logLevel + logColors + showBanner in config:

  • silent — nothing
  • error — failures only (default-safe for bots)
  • info — bot in/out, listening mode, session saves
  • debug — wire details ([REALTIME], [FBNS], [THREAD], [USER] tags, payloads)

🛠️ Projects Using This API

  • Your bot here — built something with ICA? Open an issue with a link and get listed.

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a new branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Every src/ module follows the same contract: file header (responsibility/ported-from/may-use/must-not/debug), CommonJS, rate-guarded writes.

📄 License

MIT License - See LICENSE for details.

👨‍💻 Author — Al A Min (Alaminnna)

Al A Min — Alaminnna AI Developer • Full Stack Web Developer • Student • Entrepreneur • Open Source Builder 📍 Dhaka, Bangladesh

🌐 Website: alaminnna.ami.bd

GitHub LinkedIn npm Medium DEV YouTube Instagram Threads TikTok Pinterest StackOverflow Hashnode ProductHunt Linktree Facebook

⭐ Support

If this project is helpful, please give it a ⭐ on GitHub — it helps others find it.

🔗 Links


Built by Al A Min (Alaminnna) in Dhaka, Bangladesh. Next version already in progress.

Disclaimer: This is an unofficial API and is not officially supported by Instagram. Use responsibly and comply with Instagram Terms of Use.