Instagram Private API with Node.js – Beginner’s Comprehensive Guide

Instagram Private API with Node.js – Beginner’s Comprehensive Guide
Welcome to Instagram Private API with Node.js – a beginner-friendly documentation that will walk you through every aspect of using the Instagram Private API in Node.js. Whether you want to automate interactions, manage multiple accounts, or integrate Instagram features into your app, this guide has you covered. We’ll start from the basics and build up to advanced topics, providing in-depth explanations and step-by-step instructions along the way.
Table of Contents:
- Introduction to Instagram Private API
- Installation Guide
- Creating a Development and Testing Environment
- Understanding Proxies
- Account Management
- Working with API Features
- Error Handling and Debugging
- Security Best Practices
- Deploying and Running on Cloud Servers
- Advanced Automation Examples
- Community and Resources
Let’s dive in!
Introduction to Instagram Private API
What is the Instagram Private API? – The Instagram Private API is an unofficial interface that allows developers to interact with Instagram as if they were the official mobile app. Unlike the Instagram Graph API (the official API provided by Facebook/Instagram, which has limited features and strict permissions), the private API taps into the endpoints the Instagram app uses internally. This unofficial API is what many bots and automation tools use to gain broader access to Instagram features.
How does it work? – The private API works by mimicking the behavior of the Instagram mobile app. When you use an Instagram Private API library (like instagram-private-api
for Node.js), it handles the low-level details: crafting HTTP requests to Instagram’s private endpoints, managing authentication, and respecting Instagram’s expected request format (user agents, cookies, etc.). Essentially, it’s as if a real user is tapping and swiping in the app, but all that is done through code.
Key capabilities: What can you do with the Instagram Private API? Pretty much anything the official Instagram app can do, and often more than the public API. For example, you can:
- Access extended data: Get detailed user profiles, full list of followers/following, exact like counts, story views, etc., beyond the limitations of the official API.
- Automate interactions: Like, comment, follow/unfollow, view stories, and even respond to direct messages programmatically.
- Manage content: Post photos or videos, upload stories, send disappearing media, etc., which the official API might not allow for personal accounts.
- Real-time features: With additional tooling, listen for real-time events such as incoming direct messages, live comments, or story updates.
Keep in mind that using the private API is not officially supported by Instagram. It can be incredibly powerful, but it also comes with risks (more on legal and ethical considerations later). Instagram’s Terms of Service explicitly forbid unauthenticated access to their private API. So while it’s possible to use these capabilities, always do so responsibly and with awareness of the rules and consequences.
Why use the private API? – The official Instagram Graph API has significant limitations (especially for non-Business accounts) – for instance, it doesn’t allow posting on behalf of personal accounts, viewing stories, or sending DMs. The private API fills that gap. Developers and businesses use it to build custom bots, analytics tools, or marketing automation systems that need those extra features.
Important note: Because the private API isn’t endorsed by Instagram, things can break unexpectedly (Instagram can change their internal API without notice). There’s also a constant cat-and-mouse dynamic – as Instagram improves security, the maintainers of private API libraries update their code to keep up. As a developer using these tools, be prepared for occasional bumps and update your libraries regularly.
By the end of this guide, you will have a solid grasp of how to harness the Instagram Private API’s power with Node.js, and understand the best practices to do so safely and effectively.
Installation Guide
Let’s get your development environment set up! This section will guide you through installing Node.js, the Instagram Private API library, and any other dependencies needed to get started.
2.1 Installing Node.js
What is Node.js? – Node.js is a JavaScript runtime that allows you to run JavaScript code outside of a web browser. We’ll use Node.js to run our Instagram automation scripts. If you don’t have Node.js installed yet, follow these steps:
-
Download Node.js: Visit the official Node.js website and download the LTS (Long Term Support) version for your operating system (Windows, macOS, or Linux). The LTS version is recommended for stability.
-
Install Node.js: Run the installer. On Windows, this means executing the
.msi
file and following the setup wizard. On macOS, you’ll typically use a.pkg
installer. On Linux, you can often install via your package manager (for example, on Ubuntu:sudo apt update && sudo apt install nodejs npm
). -
Verify the installation: Open a terminal (Command Prompt on Windows, Terminal on macOS/Linux) and type:
node -v
You should see Node.js version printed (e.g.,
v18.x.x
). Also checknpm -v
to ensure the Node Package Manager is installed (npm comes bundled with Node.js).
2.2 Setting Up a Node.js Project
Once Node.js is installed, create a project directory for your Instagram bot or tool.
-
Create a project folder: For example,
mkdir instagram-bot
and navigate into it:cd instagram-bot
. -
Initialize the project: Run
npm init -y
. This creates apackage.json
with default values. (The-y
flag auto-confirms the defaults, but feel free to runnpm init
without-y
if you want to customize project info.) -
Install the Instagram Private API library: The most popular Node.js library for Instagram’s private API is
instagram-private-api
. Install it via npm:npm install instagram-private-api
This will download the library and its dependencies into your project’s
node_modules
folder. After installation, you can require it in your Node.js scripts. -
Project structure: At this point, your project directory might look like this:
instagram-bot/ ├── package.json ├── package-lock.json └── node_modules/
You can now create a script file (say,
index.js
) to start writing code.
2.3 Required Dependencies and Tools
Besides the main library, here are some additional tools and dependencies that will be useful:
- dotenv: We recommend using environment variables for sensitive data like usernames, passwords, or proxy URLs. Install
dotenv
(npm install dotenv
) to easily load variables from a.env
file intoprocess.env
. This way, you don’t hardcode credentials in your code. - Request/Puppeteer (optional): While
instagram-private-api
handles most interactions, sometimes you might need to do additional things like solve challenges or scrape a webpage. Tools likenode-fetch
oraxios
can make HTTP requests, andpuppeteer
can automate a headless browser if needed. These are optional and for special cases. - Bluebird (optional): A utility library for promises. One use-case is adding delays between actions (to mimic human behavior). You can also use native JS
setTimeout
, but the Syndicode article shows Bluebird’sdelay
function in use. Install vianpm install bluebird
if desired.
After installing needed packages, create a .env
file in your project root to store your Instagram credentials and other config values (like proxy settings). For example:
IG_USERNAME=your_instagram_username
IG_PASSWORD=your_instagram_password
IG_PROXY=http://username:password@proxy_address:port
Later in your code, you’ll do something like:
require('dotenv').config();
const { IgApiClient } = require('instagram-private-api');
const ig = new IgApiClient();
ig.state.generateDevice(process.env.IG_USERNAME);
// ig.state.proxyUrl = process.env.IG_PROXY; // we’ll cover proxies later
Using a .env
file this way keeps your code clean and your credentials secure (just remember not to commit your .env
file to any public repo).
With Node.js installed and your project set up with instagram-private-api
and other tools, you’re ready to start coding! In the upcoming sections, we’ll guide you through writing scripts to log in and use various features of the Instagram Private API.
Creating a Development and Testing Environment
Before diving into code, it’s important to set up a solid environment for development and testing. This includes deciding between running things locally or in the cloud, understanding what a cloud server is, and if you opt for cloud, how to configure one. This section will clarify all of that for you, step by step.
3.1 Local Setup vs. Cloud Hosting
Local Development: Initially, you can build and test your Instagram bot on your local machine (your laptop or desktop). This is convenient for debugging and quick iteration because you have direct access to files, can easily print logs to your console, etc. Local setup is straightforward – once Node.js is installed, you run your scripts with node index.js
and observe the behavior.
Cloud Hosting: At some point, you might want your Instagram automation to run 24/7 or be accessible from anywhere. That’s where the cloud comes in. Cloud hosting means running your code on a remote server (essentially someone else’s computer in a data center) that is always online. Services like Amazon Web Services (AWS), DigitalOcean, Heroku, or Google Cloud Platform allow you to deploy your Node.js app to the internet.
Key differences: Running locally vs. cloud is mostly about availability and scalability. Locally, your script stops when you shut down your computer. On the cloud, it can keep running. Also, cloud servers often allow easier scaling if your project grows (e.g., running multiple instances, load balancing, etc.).
It’s common in development to develop locally, then deploy to cloud for continuous operation. You can start locally to ensure everything works, and when you’re confident, set up a cloud environment to host your bot.
3.2 What is Cloud Computing? (For Absolute Beginners)
Cloud computing is essentially renting computing resources (like servers, databases, storage) from providers over the internet. Instead of owning a physical server, you use a portion of a server (or a whole server) provided by companies like AWS, Azure, or DigitalOcean.
In simpler terms, cloud computing is “the delivery of computer services (such as servers, storage, databases, networking, software) over the Internet (the cloud) to offer faster innovation, flexible resources, and economies of scale”. It enables users to access computing power or storage without having to own the hardware. A common example is Apple’s iCloud, which allows you to store data on Apple’s servers and access it from any device.
For our needs, think of a cloud server as a remote computer (running Linux, typically) where you can deploy and run your Node.js application just like you would on your own PC – but it’s accessible even when your PC is off.
(Download Cloud, Cloud Computing, Connection. Royalty-Free Vector Graphic - Pixabay) Illustration: A simple cloud computing concept – your local machine (on the left) can deploy applications to the cloud (right), where remote servers run your code continuously. Cloud servers are like always-on computers accessible via the internet.
3.3 Choosing an Operating System: Linux for Node.js
Most cloud servers (also called VPS – Virtual Private Servers) run Linux. Linux is a popular choice for servers due to its stability, security, and cost (it’s usually free and open-source). For Node.js applications, Linux is an excellent environment – Node.js runs very well on Linux, and most deployment guides assume a Linux server.
Should you use Linux? If you’re deploying to cloud, yes, it’s recommended. Don’t worry if you’re new to Linux; we’ll cover the basics. If you stay local, you can use whatever OS your machine has (Windows, macOS, etc.), but it’s good to at least test on a Linux environment eventually since that’s what your cloud server will likely use.
3.4 Setting Up a Linux Server (Optional, for Cloud Deployment)
If you decide to run your Instagram bot on a cloud server, here’s a simplified guide to get you started:
-
Choose a Cloud Provider: For beginners, providers like DigitalOcean or Linode are very user-friendly. AWS and Google Cloud are also powerful but have a steeper learning curve (and their free tier has more limitations). DigitalOcean, for instance, lets you spin up a Linux server (they call it a “Droplet”) in minutes. They even have one-click apps, but for now, a basic Ubuntu server will do.
-
Create a Server (Droplet): Select an Ubuntu LTS version (like Ubuntu 22.04 LTS) which is stable. A basic plan (1 CPU, 1GB RAM) is usually enough for a small bot.
-
Connect via SSH: After creating the server, you’ll get an IP address. Use an SSH client (Terminal in macOS/Linux, or PuTTY on Windows) to connect:
ssh root@your_server_ip
. You’ll need to accept the fingerprint and provide the password (or better, use SSH keys for authentication). -
Update and Install Node.js: Once logged in, you’re in the Linux shell of your server. Run updates and install Node.js:
sudo apt update && sudo apt upgrade -y # update system packages sudo apt install -y nodejs npm # install Node.js and npm (from Ubuntu's repositories)
Alternatively: You might want a more recent Node.js version than what Ubuntu has by default. In that case, use Node Version Manager (NVM) or nodesource. For simplicity:
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs
Verify Node is installed with
node -v
just like you did locally. -
Set Up Your Project on the Server: You can either clone your repository from GitHub or SFTP the files, or even reinitialize a project. For now, to test, you might do something simple:
mkdir instagram-bot && cd instagram-bot npm init -y npm install instagram-private-api dotenv
Then create a
.env
(usenano .env
to edit a file in terminal) with your credentials. Also, createindex.js
with a simple script (maybe just a login to test, see Section 6.1 for code). -
Run the Script: Use
node index.js
. Monitor the output. If it logs in successfully or shows expected output, congrats – your bot is running on a cloud server! -
Keeping the Bot Running: If you close your SSH session, the process will stop. To keep it running, consider using a process manager like PM2 or running it inside a screen or tmux session. For example, install pm2 (
npm install -g pm2
), then runpm2 start index.js
. PM2 will keep it alive and even restart it if it crashes.
3.5 Development vs. Production Environment Tips
- Source Control: Keep your code in a git repository. This makes it easy to push updates to your server (you can pull from GitHub on your server to deploy new changes). Don’t forget to add
.env
to your.gitignore
! - Environment Variables: In the cloud server, you’ll also use the
.env
file or set environment variables. If using PM2, you can use an ecosystem file or just ensure.env
is loaded in your script. - Local Testing: test heavily on local before deploying. Instagram might occasionally challenge logins from new locations (like your cloud server’s IP), so be ready to handle that (more in Error Handling section).
- Firewall & Security: For cloud servers, ensure your server’s firewall allows necessary connections. Typically, your bot doesn’t need to accept incoming connections (it’s connecting out to Instagram), so you can close all inbound ports except maybe SSH. Many providers have firewall settings – you can restrict inbound traffic to just your IP for SSH, for example.
In summary, start local, then move to cloud when you’re ready for 24/7 operation or need extra reliability. Cloud servers (especially Linux ones) are the industry standard for hosting bots and web services due to their uptime and scalability. And as a bonus, learning to set up a Linux Node.js server is a valuable skill in web development!
Understanding Proxies
When dealing with the Instagram Private API (or any Instagram automation), proxies are a crucial concept. This section will demystify proxies: what they are, why you might need one, how to set them up in your Node.js project, and some recommended proxy services.
4.1 What is a Proxy?
A proxy server acts as an intermediary between your device (client) and the internet. Instead of your requests going directly to Instagram, they first go to the proxy, and then the proxy forwards the request to Instagram on your behalf (What is a Proxy Server?). When Instagram responds, the data goes to the proxy, which then relays it back to you.
There are different types of proxies (forward proxies, reverse proxies, etc.), but in our context, we mean a forward proxy – something you (the client/bot) use to route your traffic through a different IP address.
In simpler terms: Imagine you want to ask Instagram for something, but you give your request to a middleman (the proxy) who then asks Instagram. Instagram sees the middleman’s identity (IP address), not yours. The response comes back to the middleman, who gives it to you (What is a Proxy Server?).
Why is this useful? Because Instagram keeps an eye on how often and from where requests come. By using proxies, you can:
- Avoid IP-based rate limits: If you send too many requests from one IP, Instagram may flag or throttle you. Proxies let you distribute requests across different IPs.
- Manage multiple accounts safely: Instagram might suspect if one IP is logging into 50 accounts. Using proxies, each account (or each small group of accounts) can have a distinct IP, appearing like different users from different locations (Proxy for Instagram Bots and How to Get It).
- Evade network restrictions: If your workplace or country blocks Instagram, a proxy can circumvent that by routing traffic through a different region.
4.2 Why Proxies are Important for Instagram Bots
Instagram’s systems track both account activity and IP activity. Running a bot intensifies both. Some reasons to seriously consider proxies:
- IP Ban / Throttling: If you run a very active bot from one IP (especially a cloud server’s IP that might be known for bots), Instagram could temporarily block that IP or require phone verification for actions. Proxies can mitigate this risk by rotating IPs or using residential IPs.
- Multiple Accounts: Instagram’s policy frowns upon one person having multiple accounts (they say max 5, but typically people use 2-3 actively). If you want to automate say, 10 accounts, doing it all from one IP is a red flag. Good proxies (like residential or mobile proxies) can make each account seem like it’s on a different user’s phone in a different city (Proxy for Instagram Bots and How to Get It).
- Geo-location testing: If you need to interact with content that’s region-specific, proxies in different locations can simulate a user from those regions.
In short, proxies help your automation stay under the radar by making your bot traffic blend in with normal user traffic.
4.3 How to Set Up a Proxy in instagram-private-api
The instagram-private-api
library makes using a proxy straightforward. The client has a state.proxyUrl
property where you can specify your proxy.
Supported formats: The proxy URL is typically specified with a protocol (like http://
), and may include a username/password if your proxy requires authentication.
Example proxy URLs:
- Without auth:
http://123.45.67.89:8080
(where123.45.67.89
is proxy IP and8080
is the port) - With auth:
http://username:password@123.45.67.89:8080
(How to set up proxy? · Issue #1204 · dilame/instagram-private-api · GitHub)
Setting it in code:
const { IgApiClient } = require('instagram-private-api');
const ig = new IgApiClient();
ig.state.generateDevice(process.env.IG_USERNAME);
if(process.env.IG_PROXY) {
ig.state.proxyUrl = process.env.IG_PROXY;
}
By doing this before login, all subsequent requests from ig
will go through the proxy URL you provided. The library uses the proxy-url
by underlying HTTP client and it will handle routing (How to set up proxy? · Issue #1204 · dilame/instagram-private-api · GitHub).
If you have multiple proxies for multiple accounts, you might create separate IgApiClient
instances, each with its own ig.state.proxyUrl
.
Testing the proxy: A quick way to test if the proxy works is to run a simple fetch (like get your own profile info) with and without the proxy and see if Instagram notices any difference. But generally, if no error is thrown upon login and subsequent API calls succeed, it’s working.
4.4 Choosing a Proxy Service
Not all proxies are equal. Instagram is particularly good at detecting proxies, especially datacenter ones. Here are types and recommendations:
- Residential Proxies: These route through real devices/ISPs. They look like normal home user traffic. They are generally the best for Instagram but can be pricey. Services: Luminati (Bright Data), Smartproxy, IPRoyal, etc. Example: Smartproxy notes that the best Instagram proxies are ones that look like everyday users, often residential or mobile IPs (Proxy for Instagram Bots and How to Get It).
- Mobile Proxies: A subset of residential, these use 3G/4G connections. Instagram highly trusts mobile IPs (since so many legit users are on phones). They’re excellent for automation (harder for IG to ban without risking collateral damage) but also more expensive.
- Datacenter Proxies: These are from cloud data centers. They’re cheap and fast, but easily flagged by Instagram if abused. Use with caution – maybe for low-volume activities or if residential isn’t an option.
Proxy Providers: Some popular ones:
- Smartproxy – Offers rotating residential proxies and has guides specifically for Instagram bots.
- Luminati (Bright Data) – Very reputable (formerly Luminati).
- GeoSurf, ProxyMesh, Oxylabs – other providers.
- AlertProxies – A community recommendation for affordable 4G proxies.
- Free proxies: Generally not recommended. Free proxies are often unreliable, slow, and possibly monitored (security risk). If you just need to test how a proxy works technically, you could find a free one, but for any serious usage, invest in a good proxy.
How many proxies do you need? – If you’re just running one account moderately, you might not need a proxy at all initially. If you run multiple accounts or high activity, consider a proxy per account (or per a small group of accounts). A rule of thumb some botters use is no more than 3 accounts per proxy (to mimic that maybe one person with 3 phones on the same WiFi). Many prefer 1:1 (one account, one proxy) for safety.
4.5 Configuring Proxy Settings (Tips)
- IP Authorization vs. User/Pass: Some proxy services let you whitelist your server’s IP so that any request from that IP can use the proxy without a username/password. Others give you a username/password to authenticate. Choose whichever is provided. For IP auth, you’d use a proxy URL without creds (as shown in code above). For user/pass, include them in the URL (How to set up proxy? · Issue #1204 · dilame/instagram-private-api · GitHub).
- Proxy Protocol: Usually
http://
is fine. Some proxies might give ansocks5://
address. Theinstagram-private-api
library usesrequest
under the hood for HTTP, which supports HTTP proxies. Socks5 might need additional configuration or a different approach; if required, check the library docs or consider wrapping in atunnel
agent. - Error Handling: If your proxy is down or IP blocked, your API calls may fail (e.g., network errors or 403s). If you get errors and you’re using a proxy, double-check the proxy by trying a simple curl through it, or try another proxy.
- Avoid Proxy Chains: Using one proxy is enough. Don’t set up multiple proxies in a chain (rarely needed and can complicate things with latency and more points of failure).
Using proxies might sound complex, but in practice, once you have a good provider and set it up, it just works in the background. Your code doesn’t change how it calls Instagram’s API; it just goes through a different route. Always monitor your accounts closely when using proxies initially: ensure logins are successful and there are no unusual verification prompts from Instagram. After that, proxies can significantly enhance your bot’s reliability and stealth.
Account Management
When using the Instagram Private API, especially for bots or automation, managing accounts wisely is essential. This includes handling multiple accounts, storing session data to avoid constant re-logins, preventing bans by mimicking human behavior, and understanding the legal considerations of automating accounts. In this section, we’ll cover best practices for managing accounts to keep your automation running smoothly and safely.
5.1 Handling Multiple Accounts
If you plan to automate more than one Instagram account, you need to structure your code and data to handle this. Key considerations:
- Separate
IgApiClient
instances: Each Instagram account should use its ownIgApiClient
instance (from theinstagram-private-api
library). Don’t reuse one client for multiple logins; the client holds state (like cookies, device ID, etc.) which should be isolated per account. - Session separation: Create separate storage for each account’s session data (like cookies). For example, you might have separate cookie files or DB entries keyed by username.
- Sequential Actions vs. Parallel: If you’re running many accounts, decide if they operate sequentially (one after another) or concurrently (in parallel). Running in parallel might need more system resources and careful proxy assignments to avoid overlapping IP usage.
A practical approach is to have a configuration file or database where you store all account credentials and settings (including their proxy, if any). Then your program loops through accounts, initializing an IgApiClient
for each with its respective config.
5.2 Session Storage – Avoiding Repeated Logins
Logging in to Instagram too frequently can raise red flags (like suspicious login attempts or checkpoint challenges). Session reuse is your friend:
- Save session after login: After a successful login, you can save the authentication state (cookies, device info, etc.) so next time you don’t have to login from scratch. The
instagram-private-api
library provides methods to serialize its state. For instance, you can do:
And later, to restore without a password:const serialized = await ig.state.serialize(); delete serialized.constants; // recommended to remove constants (device specifics that need not change) // Save `serialized` to a file or database for later.
By doing this, you simulate an already-authenticated session. The library’s author suggests you only need to login once, then restore state going forward (How to store user session in v1 · Issue #732 · dilame/instagram-private-api · GitHub) (How to store user session in v1 · Issue #732 · dilame/instagram-private-api · GitHub).await ig.state.deserialize(savedSerializedState);
- Cookies and Device ID: The state contains cookies (sessionid, etc.) and a device fingerprint. Save all those and re-use. If you always start fresh with
generateDevice()
andlogin()
, Instagram might see a “new device” or “new location” every time – which is suspicious. Instead, persist the device ID and cookies. - Implement persistent storage: This could be as simple as writing JSON to files named after the username, or using a database. Example:
sessions/username.json
containing the serialized state. On startup, if that file exists, deserialize it and skip the login call. - When to re-login: If the session expires or becomes invalid (maybe password changed or Instagram expired sessions after a while), you might catch an error and then decide to do a fresh login (and update the stored session). But ideally, with active use, the session stays valid indefinitely.
By avoiding repeated logins, you reduce the frequency of Instagram’s “unusual login attempt” warnings. Also, your automation becomes faster (no need to login each time) and kinder to Instagram’s servers (logins can be heavy operations server-side).
5.3 Best Practices to Avoid Bans (Mimic Human Behavior)
Instagram’s anti-bot detection looks at what you do and how you do it. Here are some guidelines to follow:
- Rate Limiting: Do not perform actions too quickly. Humans take time to scroll, read captions, etc. Use delays between actions. E.g., after liking a photo, wait 5-30 seconds (randomly). The
bluebird.delay
or simplesetTimeout
can help insert realistic pauses. - Don’t Spam Actions: Avoid excessive liking, commenting, or following in a short time. Instagram has unofficial action limits (like, say, roughly 100 likes/hour might be okay, but 500/hour is not). These aren’t documented, but user communities share limits. Keep your bot on the conservative side, especially at the beginning.
- Simulate Day/Night Cycles: Real users sleep or at least take breaks. If your bot runs 24/7 non-stop, that’s a clear signal. It might be wise to have your bot “sleep” during typical night hours of the account’s user or take random breaks.
- Vary Patterns: If you always comment “Nice pic!” on 100 photos in a row, Instagram’s algorithms can catch the repetitive pattern. Introduce variability: have a list of comments to pick from, or vary interaction types (like some posts, comment on some, follow some, etc.). The Syndicode example even randomizes which media to like from a couple of fetched pages.
- Use Instagram’s App Behavior: The
instagram-private-api
has simulation methods (preLoginFlow
,postLoginFlow
) which simulate the background network calls the official app makes during login. Using these is “not required but recommended”. It makes your bot’s login process resemble a real app’s login, which might reduce suspicious login detections. - Rotate Proxies / Accounts: If you have multiple accounts, don’t let one IP handle too many in a short time, as explained in the Proxies section. Also, if one account gets temporarily blocked for some action (say it hit a like limit), give it a rest and switch to another account for a while.
Remember, quality over quantity: It’s better to run a slightly slower bot that stays under the radar than an aggressive bot that gets an account banned in a day. Instagram does issue temporary action blocks or warnings before outright banning in many cases, so if you get one of those, treat it as a warning and dial back immediately.
5.4 Legal and Ethical Considerations
While building cool automations is exciting, always keep in mind:
- Instagram’s Terms of Service: Using private APIs likely violates their terms. This could lead to your account(s) being suspended. In worst cases, if you run a service, you could face legal notices (Facebook has pursued legal actions against bot operators in the past). Always weigh the risk.
- User Privacy: If your automation involves gathering data about other users (even if public), ensure you’re respectful and compliant with any applicable data protection laws. Just because the private API allows access to something doesn’t mean you should use it unethically.
- Consent: If you are automating actions on behalf of someone else (say clients in a social media agency context), make sure they’re aware and have permitted it. Also, a bot might do “weird” things occasionally – make sure it doesn’t accidentally violate someone’s privacy (e.g., don’t DM people without very good reason/consent).
- Attribution: If you gather content via the API (like downloading images to repost), respect copyrights. Instagram content belongs to the users who post it.
- Non-commercial vs. Commercial: If it’s a personal project, consequences are typically just your account. If it’s a commercial tool (resold or used widely), stakes are higher. Ensure you have something in your terms to handle if Instagram sends a cease-and-desist or if accounts get banned.
It’s not our place to give legal advice, but it is important to acknowledge: by using an unofficial API, you are “on your own” regarding support or issues, and you accept some risk. Many developers use the private API successfully for years, but some have also lost accounts.
In short: Be a responsible bot developer. Use the powers for good (or at least not for evil), and be prepared to adjust if Instagram pushes back.
5.5 Managing Account Data Securely
One more note – handle your account credentials and data securely:
- Do not hardcode usernames/passwords in scripts, especially if you share the code.
- Protect your session files (they contain auth tokens). If someone gets those, they could hijack your Instagram session.
- If using a public repo, never upload
.env
or session files. - Consider using separate “bot accounts” instead of personal main accounts, to be safer.
By following these account management best practices, you’ll minimize disruptions (like re-logins or blocks) and reduce risk of losing accounts. Managing accounts well is half the battle in making robust Instagram bots.
Working with API Features
Now to the fun part – using the Instagram Private API to actually do things on Instagram! This section breaks down how to leverage different features of Instagram via the Node.js library, with detailed instructions and examples for each major capability. We’ll go through:
- Logging in securely (including two-factor auth if needed).
- Fetching user feeds (like your home timeline or a user’s posts).
- Automating likes and comments on posts.
- Sending and receiving Direct Messages (DMs).
- Handling Instagram Stories (viewing and posting stories).
- Setting up real-time notifications for events (like incoming DMs or live activities).
Let’s tackle them one by one, with code snippets and explanations.
6.1 Logging in Securely
Logging in is the first step for almost any action. We touched on saving sessions in Account Management. Here, we’ll focus on the login process itself.
Basic Login Example:
require('dotenv').config();
const { IgApiClient } = require('instagram-private-api');
const ig = new IgApiClient();
(async () => {
// 1. Generate a device seed (based on username usually)
ig.state.generateDevice(process.env.IG_USERNAME);
// 2. Optionally, set up proxy
if(process.env.IG_PROXY) {
ig.state.proxyUrl = process.env.IG_PROXY;
}
// 3. Pre-login flow (optional but recommended)
await ig.simulate.preLoginFlow();
// 4. Perform login
const loggedInUser = await ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD);
// 5. Post-login flow
process.nextTick(async () => await ig.simulate.postLoginFlow());
console.log(`Logged in as @${loggedInUser.username}`);
})();
Let’s break down what’s happening:
- Device Generation:
ig.state.generateDevice(username)
creates a consistent device fingerprint for that username. It generates things like device ID, phone ID, etc., which identify the “device” to Instagram. Using the username as seed ensures the same device details every time for that user (stability). This reduces chances of getting flagged for a new device on each run. - Proxy: We set
proxyUrl
if provided. (We covered this in the Proxy section.) - simulate.preLoginFlow(): This simulates network calls that the Instagram app makes right before login. For instance, the app might ping certain endpoints or fetch config. Doing this can make our login appear more legit.
- Login:
ig.account.login(username, password)
does the actual login. It returns a user object for the logged in account (which includes username, user ID (pk), etc.). - simulate.postLoginFlow(): The library suggests calling this after login (even in a next tick) to simulate follow-up calls that happen right after login. This can run in background (hence the
process.nextTick
to not block main thread). - Logged in!: At this point
ig
is authenticated. All subsequentig.*
calls will be in the context of this logged-in user.
Two-Factor Authentication & Challenges:
Instagram might ask for a 2FA code if the account has it enabled, or present a “challenge” (like verify via email/SMS, or “Is this you?”). The instagram-private-api
library can handle these but it’s a bit more involved:
- For 2FA:
ig.account.login
will throw an error indicating 2FA is required, including atwoFactorIdentifier
. You then callig.account.twoFactorLogin({ username, verificationCode, twoFactorIdentifier, verificationMethod })
. This will complete the login with the code you got from SMS or authenticator app. - For Checkpoint Challenge: If you get a checkpoint, you may have to use
ig.challenge
. Typically:- Call
ig.challenge.auto(true)
to attempt auto-resolving the challenge (if it’s something like just clicking “It was me”). - If that doesn’t work, you might need to get challenge info and submit a code. This is advanced, but the high-level steps: use
ig.challenge.state()
to get challenge details (like which verification methods are available), thenig.challenge.selectVerifyMethod()
(maybe choose email or phone), thenig.challenge.sendSecurityCode(code)
.
- Call
- These flows can change, and often require manual input (from the user to get the code). In a beginner context, we’ll keep it simple: ensure you either disable 2FA for the bot account or be ready to handle these manually at first.
Login Errors: Common issues include:
- Bad credentials (check the username/password).
- “Checkpoint challenge required” – meaning Instagram wants you to verify via web or app that it’s you logging in. Often due to new IP or suspicious login. You might solve this by logging in once manually from the server’s IP (use a VPN or VNC on the server).
- If using proxies, sometimes the proxy IP location triggers a challenge (e.g., you usually log in from USA, but proxy is in Singapore). Consistency helps – try to use proxies near your usual location if possible, or just complete the challenge once and save session.
Once logged in successfully (even if you had to do a challenge, after it’s done), serialize and save the session (as discussed). That will make future runs not require the full login process and avoid repeat challenges.
Logging in is arguably the hardest part due to these security features, but once you have it, the rest of the API usage is straightforward. In the code examples below, we’ll assume you have a logged-in ig
client ready.
6.2 Fetching User Feeds
Instagram “feeds” refer to lists of content. Using the API, you can fetch various feeds:
- Timeline feed: Posts from accounts you follow (the home feed you see when you open Instagram).
- User feed: Posts from a specific user.
- Hashtag feed: Top/recent posts for a hashtag.
- Location feed: Posts tagged with a location.
- Story feeds: Stories of people you follow, etc.
- Direct inbox feed: Your DM conversations list.
The instagram-private-api
organizes these through the ig.feed
namespace. Some useful ones:
ig.feed.timeline()
– your home feed.ig.feed.user(userId)
– posts by a user (by numeric ID, not username; use helper to get ID from username).ig.feed.tags(hashtag, tagType)
– hashtag feed (e.g.,ig.feed.tags('food', 'top')
for top posts with #food).ig.feed.location(locationId)
.ig.feed.directInbox()
– your inbox.- etc.
Example: Get your own recent posts:
// Assuming ig is logged in
const userId = ig.state.cookieUserId; // the logged in user's ID
const userFeed = ig.feed.user(userId);
const myPostsFirstPage = await userFeed.items();
console.log("My recent posts:", myPostsFirstPage.map(p => p.id));
Here:
- We used
ig.state.cookieUserId
, which the library sets as the current account’s ID (also available from loggedInUser.pk from login). ig.feed.user(userId)
gives a feed object. Calling.items()
on it fetches a page of results.myPostsFirstPage
will be an array of media items (posts). You can inspect one to see what data it contains (caption, image URLs, like_count, etc.). It might by default return up to 12 items (Instagram’s page size varies).- To get more pages: call
await userFeed.items()
again for the next page. Each call to.items()
advances the feed’s pagination until no more results.
Example: Timeline Feed (Home):
const timelineFeed = ig.feed.timeline();
const firstPage = await timelineFeed.items();
for (let post of firstPage) {
console.log(`${post.user.username} posted: ${post.caption?.text}`);
}
The timeline feed returns posts similar to what you see on your home. It may include ads or suggested posts as well (they might be marked differently in the data).
Example: Hashtag Feed (Top posts):
const tagFeed = ig.feed.tags('food', 'top');
const topFoodPosts = await tagFeed.items();
console.log(`Top #food posts count: ${topFoodPosts.length}`);
if(topFoodPosts.length) {
console.log("First top post caption:", topFoodPosts[0].caption?.text);
}
In the Syndicode example, they got top posts for #food
. Note that 'top'
is one section; you could also fetch 'recent'
by changing the second parameter.
Example: Get followers list (via Feed):
const followersFeed = ig.feed.accountFollowers(targetUserId);
const page1 = await followersFeed.items();
console.log(`Followers (first page): ${page1.map(u => u.username).join(', ')}`);
Likewise, ig.feed.accountFollowing(userId)
for following. Keep in mind, large lists must be paginated through.
Important: When you fetch feeds, you get data objects returned by the API. These are plain JS objects but nested. It helps to log them to see structure, or check the docs for the shape. E.g., a media item has id
, caption.text
, user.username
, image_versions2
(with image URLs), etc. Access accordingly.
Also note, all feed requests are web requests under the hood. If you do too many heavy ones too fast (like pulling thousands of followers), you might get rate-limited. Pace them if doing in bulk.
Now that you can retrieve feeds, you can read and analyze Instagram content. Next, let’s act on that content (like, comment, etc.).
6.3 Automating Likes and Comments
Two common actions to automate: liking posts and commenting on posts. Using the private API, these are straightforward.
Liking a Media:
The library has ig.media.like({ mediaId })
for liking and ig.media.unlike({ mediaId })
for unliking. The tricky part is that mediaId is not the same as the shortcode or URL. It’s an internal identifier, usually a large number plus underscore plus poster’s ID (like "34823848384_4324324"
). If you fetch feeds via the API, each item will have an id
field which is the mediaId needed.
Example:
// Like the first post from the timeline
const timeline = ig.feed.timeline();
const [ firstPost ] = await timeline.items();
if(firstPost) {
await ig.media.like({
mediaId: firstPost.id,
moduleInfo: {
module_name: 'feed_timeline', // context of the like
user_id: firstPost.user.pk,
username: firstPost.user.username
},
d: 1 // probably "d" stands for double-tap (0 or 1)
});
console.log(`Liked media ${firstPost.id} by ${firstPost.user.username}`);
}
The extra moduleInfo
and d
are sort of metadata that the app sends; including them can simulate an app-like context of the like. For a beginner, the simplest call might be ig.media.like({ mediaId: id })
and it should work, but including moduleInfo might make it more “natural” (for instance, liking from profile vs timeline might have different module_name).
The README example shows usage with moduleInfo for a profile like. We used 'feed_timeline'
to indicate it came from the home feed.
Commenting on a Media:
Commenting uses ig.media.comment({ mediaId, text })
. Just provide the media ID and your comment text:
const mediaId = firstPost.id;
await ig.media.comment({ mediaId, text: "Nice post! 😊" });
console.log("Commented on post", mediaId);
From an earlier GitHub issue, note that ig.media.comment()
expects an object with mediaId and text (not just parameters】. Also, if you only have a shortcode (like Instagram URL shortcode), the library offers a way to get mediaId from it. But since we are fetching via API, we already get the mediaId.
Important considerations for likes/comments:
- Don’t spam: As mentioned, pace your likes and comments. If you fetch a feed of 100 items, don’t like all 100 in a minute. That will almost surely trigger a block.
- Comment content: Vary your comments if you automate many. Instagram’s filters might flag repetitive comments as spam. Also avoid obviously generic or promotional phrases if not appropriate; those get reported by users or filtered by IG.
- Error Handling: If a like or comment fails with a 4xx error (like 400 or 429), stop further actions and wait. It could be a rate limit or block. If 400 with “challenge required” or “feedback required”, you likely got an action block – better to pause that bot for a day.
- moduleInfo: The
module_name
can be other values like"profile"
if liking from user profile,"media_view_profile"
for grid view, etc. It’s not strictly required to set this, but it can add realism. - Liking Comments: There’s also an endpoint to like a comment (if needed), but that’s less common to automate. Not to be confused with liking a media.
Unlike or Delete Comment:
ig.media.unlike({ mediaId })
to unlike a post.ig.media.deleteComment({ mediaId, commentId })
to delete your comment if needed.
Now you can program your bot to iterate through a feed and like or comment on certain posts (e.g., like everything with a hashtag, or comment on new followers’ posts as a welcome gesture). Just always build in that randomness and delay.
6.4 Sending and Receiving DMs
Instagram Direct Messages (DMs) are a powerful way to interact with users privately. Historically, the official API didn’t allow DMs at all, which made the private API the go-to solutio】. Let’s see how you can send and receive DMs using the private API in Node.js.
6.4.1 Sending a Direct Message:
To send a DM, you typically need the user ID of the recipient. If you have their username, you can convert that to user ID via ig.user.getIdByUsername(username)
.
Once you have the ID, you create a direct thread and then broadcast a message.
Example: Send a text message to a user by username:
const recipientUsername = 'someuser';
const userId = await ig.user.getIdByUsername(recipientUsername);
const thread = ig.entity.directThread([userId.toString()]);
await thread.broadcastText('Hello from my Node.js bot!');
console.log(`Message sent to ${recipientUsername}`);
Explanation:
ig.user.getIdByUsername('someuser')
returns the numeric ID of the user “someuser”. The private API often needs IDs, not usernames, for actions.ig.entity.directThread([ userId ])
creates a thread object between you and that user (the array allows group threads if you had multiple IDs). We convert userId to string because the method expects string IDs.thread.broadcastText('...')
sends a text message in that threa】. You could also usethread.broadcastMedia()
to send a photo orbroadcastVoice()
etc. The library has various broadcast methods.- When done, the thread is sent. If successful, no error is thrown. If the user has blocked you or something, you might get an error or just no response.
Other DM types:
- To send a photo or video, you use
ig.entity.directThread([...]).broadcastPhoto({ file })
wherefile
is a Buffer or file path of the image, orbroadcastVideo
. - To send a profile or post (like share a post in DM), you would use something like
thread.broadcastProfile(profileId)
orthread.broadcastMedia(options)
– check the docs for these if needed.
6.4.2 Receiving (Reading) DMs:
To fetch your inbox (list of threads):
const inboxFeed = ig.feed.directInbox();
const threadsFirstPage = await inboxFeed.items();
for (let thread of threadsFirstPage) {
console.log(`Thread with ${thread.users.map(u=>u.username).join(', ')}: ${thread.items[0]?.text}`);
}
ig.feed.directInbox()
gives you your DM threads..items()
yields an array of thread objects. Eachthread
has info likethread.users
(participants),thread.items
(messages, with latest messages first typically).- You can page through if you have a lot of threads (
inboxFeed.items()
multiple times). - Each
thread.items
is an array of messages in that thread (limited by what’s fetched). If you want to retrieve all messages in a thread or get updates, you might need to useig.feed.directThread(threadId)
similarly.
To fetch a specific thread by its thread ID (you get thread_id from the inbox list):
const threadFeed = ig.feed.directThread(threadId);
const threadItems = await threadFeed.items();
for(let item of threadItems) {
console.log(`${item.user_id === ig.state.cookieUserId ? 'Me' : 'Them'}: ${item.text || '[non-text message]'}`);
}
This prints the conversation in that thread (for the page of messages retrieved).
Real-time new messages: If you want to actively listen for new DMs as they arrive, that’s where the Realtime client (MQTT) comes into play – it’s advanced, but a quick pointer:
- The library has a way to extend IgApiClient with real-time:
withFbnsAndRealtime(ig)
or similar, which then providesig.realtime.on('message', handler)
event】. This requires an additional package (instagram_mqtt
) and keeping an open connection. For a beginner, polling the inbox every minute or so might be easier to implement, albeit less efficient.
Note: As of August 2021, Instagram’s official API (for business accounts) added some messaging suppor】, but that’s limited to business accounts and requires Facebook app review. For personal accounts or without that complexity, the private API is still the way to go.
DM Ethics: Be careful not to spam DMs. Unsolicited bulk messages can get flagged quickly, or recipients might report. Instagram definitely monitors DMs for abuse. Use sending DMs for responsive actions (like replying to those who DM you first, or messaging new followers with a welcome message if that’s something you do manually sometimes).
6.5 Handling Instagram Stories
Instagram Stories are ephemeral content that last 24 hours (unless saved as highlights). With the private API, you can both fetch stories (view other’s stories) and post your own stories. Let’s explore both:
6.5.1 Viewing Stories (Fetching):
-
To get the stories of people you follow (the story tray you see atop the IG app):
const reelsFeed = ig.feed.reelsTray(); const storyTray = await reelsFeed.items(); for(let reel of storyTray) { console.log(`Story from ${reel.user.username}: ${reel.items.length} items.`); }
Each
reel
corresponds to a user who has active stories.reel.items
are the actual story media items. They might be images or videos. Each item will have things likeid
,media_type
(1=image, 2=video),taken_at
timestamp, etc., and links to the media (images/videos URLs). -
To get stories for a specific user (even if you don’t follow, if their profile is public or if you have access):
const targetUserId = await ig.user.getIdByUsername('some_username'); const reelsFeed = ig.feed.userReels(targetUserId); const userReel = await reelsFeed.items(); console.log(`User ${some_username} has ${userReel.length} story items currently.`);
Note: The library might have updated naming; older versions had
ig.feed.userReelMedia(userId)
. -
The items you get can be downloaded or processed. But be mindful – mass-downloading stories might trigger a lot of network calls. Also, ethically, don’t use this to spy on private accounts you’re not allowed to; ensure you have access if needed.
6.5.2 Posting Stories:
The private API allows uploading a story, similar to how you’d post a normal media but via ig.publish.story()
.
Basic example to post a photo as a story:
const { readFile } = require('fs/promises');
const imageBuffer = await readFile('./mystory.jpg'); // ensure this image exists
await ig.publish.story({
file: imageBuffer,
caption: "Hello, Instagram Story!"
});
console.log("Story posted!");
- The
file
can be a Buffer or a readable stream. We used fs to read an image into a buffer. caption
in story is actually the sticker text or something; actually for story the property might be slightly different (caption might not do anything for story). If you want text on story, you might have to embed it on the image or use story stickers.- If you wanted to add a link sticker, poll, etc., that’s more advanced: the example from the GitHub repository shows using
StickerBuilder
to add interactive stickers before publishin】. For a beginner, we can ignore stickers. But just know it’s possible (e.g., mention sticker, hashtag sticker as shown in that example).
Posting a video story is similar: read the video file into a buffer and call ig.publish.story({ video: videoBuffer, ... })
. There might be an extra param needed for thumbnail, not sure – the docs would clarify.
Story Metadata:
- The result of
ig.publish.story()
will likely include the media ID of the story and some info. You can use that to track it or delete it if needed viaig.media.delete({ mediaId, mediaType: 'story' })
(if supported). - Stories posted via API count just like normal – 24h life.
Viewing Your Own Story Views: You can also fetch who viewed your story, but that requires the story media ID and using an endpoint for viewers, which may be in ig.story
or ig.media
(like ig.media.storyViewers({ mediaId })
). This is a bit advanced and not commonly needed for basic automation.
Note: Instagram launched an official Story posting API for business accounts in 2021 (with limited features). But for personal accounts or more control, the private API remains useful.
6.6 Real-time Notifications and Events
Real-time event handling means your script can respond the moment something happens on Instagram, such as:
- A new direct message arrives.
- You receive a notification (e.g., someone liked your post, or started live).
- Presence events (like friend comes online) or live comments in a broadcast.
This is advanced because it involves maintaining an open connection to Instagram’s push servers. The instagram-private-api
library itself is mostly for on-demand queries. However, the maintainers provided a sub-project for real-time using MQTT (the protocol Instagram uses for push) – that’s what the withFbnsAndRealtime
extension doe】.
For beginners, implementing full real-time might be optional. You can often simulate “real-time” by polling (e.g., checking DMs every minute to see if there’s something new). But let’s outline how it would work:
- FBNS (Facebook Notification Service) – used for push notifications (like the notifications you get on your phone: new follower, like, etc.). It’s read-only.
- Realtime Client – used for direct messaging, live, typing indicators, etc., which require a constant connection.
The combination withFbnsAndRealtime(new IgApiClient())
wraps the client with those capabilitie】.
After login, you’d connect:
const ig = withFbnsAndRealtime(new IgApiClient());
await ig.account.login(user, pass);
// Connect realtime
ig.realtime.on('message', (data) => {
console.log("New DM received: ", data);
});
ig.fbns.on('push', (notif) => {
console.log("Push notification: ", notif);
});
await ig.realtime.connect();
await ig.fbns.connect();
The exact syntax might differ with versions. Essentially:
ig.realtime.connect()
establishes the websocket/MQTT for realtime messages.ig.fbns.connect()
connects to push notifications.- Then you attach event handlers to what you want:
ig.realtime.on('direct', handler)
might give structured direct message event】.ig.realtime.on('message', handler)
lower-level message events.- There are events for
realtimeSub
,presence
, etc. (the table in the code snippet outlines the】). - For FBNS, you get
'push'
events and can filter bynotif.collapseKey
for specific types (like direct_v2_message for DMs, etc.).
This is quite complex to set up and beyond a beginner guide’s scope to fully implement, but it’s good to know it’s possible. With real-time, you can do things like auto-reply to DMs immediately or log when someone mentions you.
Debugging Realtime: They mention setting DEBUG=ig:mqtt:*
to see low-level log】 if you try this.
Simpler Alternative: Polling.
For example, you could periodically do:
setInterval(async () => {
const unseen = await ig.feed.directInbox().items();
// check for any threads with unseen messages, then handle them
}, 30000); // every 30 seconds
This is not true real-time, but easier to implement initially. Just careful with rate (maybe 30s or 60s interval is okay).
Notifications: If you want to see things like “who liked my posts just now” or “new follower”, you could fetch relevant feeds periodically:
- For likes: check your own post’s like count periodically, or use
ig.feed.news()
which might show recent interactions. - For new followers: query followers feed and compare with stored list.
But the proper way is via notifications push (FBNS) which would tell you directly.
Given the complexity, you may choose to skip real-time initially. It’s an advanced topic. The key takeaway is the private API can handle it with additional tooling, but requires deeper work. Many community bots skip real-time and just schedule periodic tasks.
With that, we’ve covered logging in, feeds, likes/comments, DMs, stories, and touched on real-time. Now, you have the building blocks to create a wide variety of Instagram automation tasks. Next, we’ll address what to do when things go wrong (errors, debugging).
Error Handling and Debugging
No coding journey is complete without bumps along the way. When using the Instagram Private API, you’ll likely encounter errors – some from code issues, others from Instagram’s side (rate limits, challenges, etc.). In this section, we’ll go over common problems, how to troubleshoot them, and general debugging best practices to keep your bot stable.
7.1 Common Issues and Error Messages
Login Errors:
- Username/Password incorrect: Throws an authentication error. Double-check credentials; also note Instagram may require a re-login if password changed.
- Checkpoint Challenge Required: This appears as an error message (often HTTP 400 with a body mentioning checkpoint or challenge). Instagram is asking for verification. You might need to use the Instagram app or the challenge handling flows as described earlier (Section 6.1) to approve the login. Once done, you can try again or better, use the
ig.challenge
handling code. - Two-Factor Required: Similar to above, but explicitly a 2FA code is needed. The error will indicate it. You’ll have to catch and then call
twoFactorLogin
.
Action Errors (like when liking/commenting/following):
- HTTP 429 Too Many Requests: You’ve hit a rate limit. The response from Instagram might not explicitly say 429 in the library (could just throw an error). If you suspect you’re doing too much too fast, slow down. Use exponential backoff (wait longer each time it fails).
- Action Blocked (feedback_required): Instagram might respond with something like
feedback_required
and a message like “We’ve restricted certain activity”. This means that account is temporarily blocked from that action (liking, commenting, etc.) due to suspected bot activity. Typically lasts 24-48 hours for first offense. If you get this, stop those actions immediately for that account and let it cool down. Continuing to hammer could extend the block or risk a ban. - 404 or Not Found: If trying to like/comment on media that might have been deleted or a wrong ID. Double-check IDs. Could also happen if using an endpoint not available to your account (e.g., trying to view a private user’s info whom you don’t follow).
- 403 Forbidden: This can happen if your session is invalid (e.g., cookies expired) or if Instagram flagged your request. If you see this on everything suddenly, try logging in again (your session might have been revoked). If it persists, your IP might be temporarily banned – try switching IP (proxy) or waiting it out.
Network/Proxy Errors:
- ETIMEDOUT or ENOTFOUND: Indicates network issues – maybe your proxy is down or internet unreachable.
- ECONNREFUSED: Proxy refused connection – probably wrong proxy details.
- Proxy authentication error: If you set a wrong username/password for proxy.
- If using proxies and things fail, try without the proxy to isolate if proxy is the issue.
Unexpected Behavior:
- Getting empty feed where you expect items: Could be normal if no items, or if state is wrong (not logged in or hitting an endpoint that requires login).
- Data formats: If something in the response doesn’t match what you expect (e.g.,
item.caption
is null maybe because post has no caption), ensure to handle optional fields to avoid crashes (?.
optional chaining is useful in JS). - Crashes with no obvious error: Perhaps unhandled promise rejections. Always use try/catch in your async functions when calling API methods, so you can gracefully handle them and log them.
7.2 Debugging Techniques
Enable Debug Logs: The instagram-private-api
uses the debug
library internally with namespace “ig”. You can enable verbose logging by setting an environment variable:
DEBUG=ig:*,request
This might output a lot, but will show you the requests being made, responses, etc. (The snippet from instagram_mqtt
recommended DEBUG=ig:mqtt:*
for realtime, and ig:*
for everythin】.)
If you run your script with that env var, you’ll see detailed logs that can help pinpoint where it’s failing.
Use Try/Catch:
Wrap API calls in try/catch to intercept errors:
try {
await ig.media.like({ mediaId });
} catch (err) {
console.error("Failed to like:", err);
}
Examine err
. It might be an instance of IgResponseError
which has a response
property with details like response.body.message
or response.body.error_type
. Log those.
Reproduce with CURL/Postman (if possible):
If a certain endpoint is failing (like posting a comment), and you suspect it’s not your code, you could attempt to reproduce the request manually. This is advanced and requires capturing the request that library makes (via debug logs or proxy) and replaying it. But often not needed unless contributing to library debugging.
Stack Overflow & GitHub Issues:
Chances are someone encountered the same error. Search the error message or scenario. For example, searching “instagram-private-api challenge required” yields StackOverflow and GitHub thread】. These can have solutions or at least confirmation of the cause. The maintainers often respond on GitHub issues with insights.
Unit Testing:
For your code logic, test functions individually. For instance, test your “like recent posts” function on a dummy data object first (to ensure your logic works without hitting IG too). Then test with actual API once logic is confirmed.
Rate Limit Strategy: If you suspect hitting limits, implement a simple counter or limiter:
let likeCount = 0;
const LIKE_LIMIT = 100;
...
if(likeCount >= LIKE_LIMIT) {
console.log("Reached like limit for now, sleeping...");
await bluebird.delay(60 * 60 * 1000); // wait an hour
likeCount = 0;
}
await ig.media.like({ mediaId });
likeCount++;
This is simplistic. There are libraries like Bottleneck
for rate limiting tasks elegantly.
7.3 Handling Specific Cases
Challenge Solving:
If you want your bot to handle the “checkpoint challenge” automatically:
- One approach:
await ig.challenge.auto(true)
– the library will attempt to trigger the challenge and follow the link. If it’s like a “click yes it was me” challenge, it might solve it. - If it requires a code, you might use:
This is beyond beginner normally because you need to actually get the code that was emailed or texted. So often it’s easier to manually intervene: log the URL Instagram gave for the challenge (ig.challenge.url maybe) and open it in a browser, or use a real phone to verify.const { stepName, stepData } = ig.challenge; if(stepName === 'select_verify_method') { await ig.challenge.selectVerifyMethod(0); // 0 for email, 1 for phone perhaps } // Then wait for code out-of-band (email or SMS), then: await ig.challenge.sendSecurityCode(code);
Unexpected Logout:
Sometimes you might find your session stops working (maybe Instagram logged the account out remotely because they detected weird activity or password changed). If so, you’ll have to login again. Keep an eye on err.name
or message for things like “LoginRequired” etc., which tell you to re-auth.
Library Bugs vs. IG Changes:
Because this is unofficial, occasionally the library might break if Instagram changes something. If after an IG update your code suddenly fails (and you haven’t changed anything), check the GitHub repo for issues or updates. You might need to update the npm package if a fix was released, or if not, you might have to wait or contribute a fix.
Memory Leaks:
If your bot runs 24/7, monitor memory usage. If it climbs indefinitely, you might be collecting too much data without clearing. For instance, if you keep adding to an array of processed items and never remove old ones. Or if you keep old feed instances around. Not an IG-specific bug, but general.
Capturing Crashes:
Use process.on('unhandledRejection', ...)
and process.on('uncaughtException', ...)
to catch any unhandled errors. At least to log them before the program exits. It’s good to log errors to a file or external service for long-running bots.
Testing in Isolation:
If one part fails, isolate it. For example, if DM sending fails, write a small standalone script that just logs in and sends a DM to rule out interference from other parts of your code.
7.4 Best Practices for Debugging
- One change at a time: When adjusting to fix an error, change one thing and test, rather than changing many things at once. This way you know what fixed it (or what didn’t).
- Verbose Logging: Add lots of
console.log
while debugging, showing the flow and key variable values. Remove or reduce logging once stable (or use a logging library with log levels). - Backup Plan: If something fails, ensure your bot doesn’t go haywire. For example, if commenting fails, perhaps don’t try to comment repeatedly 100 times anyway. Handle errors gracefully, maybe skip that action for a while.
- Time/Date debugging: If scheduling posts or actions, ensure your server’s time is correct and you handle time zones properly. Logs with timestamps help.
- Check Instagram’s status: Rarely, Instagram might have downtime or issues. If everything was fine and suddenly nothing works, it could be Instagram’s servers (or your IP banned). Try logging in via the official app or website to see if the account or internet connection is okay.
By anticipating common issues and having a strategy to handle them, your bot will be much more robust. Remember that debugging is a normal part of development – don’t get discouraged by errors. Each error message is a clue to make your code better.
Security Best Practices
Automation can be powerful, but with great power comes the need for great security. Using the Instagram Private API involves handling sensitive information (like login credentials) and performing actions that, if not careful, could lead to account bans or other security issues. In this section, we’ll outline best practices to keep your bot and accounts secure.
8.1 Protecting Login Credentials
Never hardcode passwords: We’ve said it before – use environment variables or secure storage for your Instagram username/password. If someone gets hold of your code with hardcoded credentials, they literally have your Instagram login. If you use a public repository, double-check you haven’t accidentally committed your secrets. Tools like git-secrets
can help prevent committing passwords or keys.
Use .env or Config Files (secured): .env
is fine for local/dev. If you deploy to production, better to use actual environment variables or a secrets manager:
- On services like Heroku, you set config vars.
- On AWS EC2 or a VPS, you might export env variables or use a config file that’s kept secure.
- If you do keep a file with credentials on a server, restrict its permissions (
chmod 600
, owner-only access).
Encryption: For extra security, you could encrypt the credentials and only decrypt at runtime (though if someone has access to your code and running environment, they might get the key as well – so this is more to protect at rest).
Two-Factor Auth: If possible, keep 2FA off for the bot account to avoid complexity (or use an automation-friendly method). If you do want 2FA on for security, consider using an API that can handle it, or you’ll manually need to provide the code each time you login fresh. Some people set up email auto-retrieval or such, but that’s advanced.
Monitor Login Locations: Instagram often emails about new login from X location. If you get such and it’s not you or your proxy, someone else might have your credentials. Take action (change password, check your logs for any breach).
8.2 API Rate Limits and Avoiding Detection
We covered mimicking human behavior in Account Management, but let’s reiterate from a security perspective:
- Respect Rate Limits: Although the private API doesn’t have published rate limits, you can infer them. If you burst too fast, Instagram might throttle or flag. Spread out your actions. Especially write operations (likes, follows, etc.) should be limited. Also, even read operations (fetching 10,000 followers in a minute) could raise eyebrows.
- Use App Rate Limits as a Guide: The official Graph API might allow 200 calls/hour for certain endpoints. The private API might allow more, but try to stay within reasonable bounds. If your bot starts getting errors at some threshold, implement a cooldown.
Use Proxies Wisely:
- If one account gets action blocked, using another proxy won’t magically fix that – the block is on the account. But if one IP gets flagged, switching IP (proxy) can help for new accounts or actions.
- Avoid free or public proxies, as they could be sniffing data. Use trusted providers to ensure your login info isn’t intercepted.
- Keep your proxy credentials safe too (don’t log them or expose them in errors).
Device Identity:
- The library’s device simulation makes your bot look like a specific Android device. Don’t constantly change device fingerprint for the same account – that would look like you keep switching phones. Use
generateDevice
with a consistent seed (like username】. - If you run multiple bots for the same account on different machines, that’s like logging in from two devices; Instagram allows that, but keep it low (maybe one bot instance per account to avoid too many “active devices”).
Session Security:
- The saved session (cookies) essentially is like being logged in. If someone steals your
session.json
, they could impersonate your login without needing password (until Instagram expires that session). Treat session files as sensitive as passwords. If on a server, limit who can read them. - After significant changes (like password change or you suspect a cookie might be stolen), you can force logouts by changing password or explicitly logging out sessions via Instagram settings. But hopefully that’s not needed if you keep it secure.
Don’t Attract Attention:
- Running a bot that likes 10 posts a day probably won’t get noticed. Running one that comments on hundreds of posts with the same text will. The more “noisy” your bot’s actions are, the higher chance of detection or user reports. For longevity, low-and-slow is the way to go.
- If you’re automating from your own account, be extra cautious – losing a personal account can be painful. If it’s a bot-specific account, the stakes are lower, but if that account interacts with others (especially DMs or comments), a ban could still have ripple effects.
Be Ready for an Account Ban:
It’s a possibility. Backup content if needed. If an account is critical, consider not automating it heavily or have a contingency (like a spare account, or just avoid risky actions).
8.3 Preventing Detection or Bans (Advanced Tips)
- Randomized User Agents: The library probably handles user-agent strings, but ensure it’s set to something plausible (e.g., a modern Android device). You generally don’t need to change it often; in fact, keep it stable per device.
- Time Zone and Locale: The Instagram app sends locale info. If your proxy IP is from Germany but your simulated device locale is en-US, maybe that’s a slight discrepancy (though probably minor). Some bots set the timezone and locale to match IP. Not usually needed, but it’s a possible enhancement.
- Monitor Instagram’s Responses: Sometimes Instagram includes warnings in API responses (like a header or specific field) that indicate you’re nearing a limit or under suspicion. Keep your debug logs occasionally to inspect if any such hints are present.
- Use Newer API Versions: If the library updates to mimic the latest app version, use that. Running an outdated signature (older app version) might eventually get flagged if too old.
- Avoid Obvious Automation Patterns: For instance, don’t always post at exactly 00:00 every day, or don’t follow/unfollow 100 users exactly at a certain interval. Use randomness to your advantage. The more it looks like a human (who are inherently a bit random), the better.
- Single Responsibility: If one account is doing everything (liking 1000 posts, commenting 500, following 300, DMing 200 people all in one day), that’s not typical human usage. Most humans can’t physically do all that in a day. If you need high volume, spread it across multiple accounts/bots.
Server Security:
- If you deploy on a VPS, secure that server (use SSH keys, keep it updated, maybe use a firewall).
- Because if your server is compromised, the attacker could use your Instagram accounts for malicious purposes.
Compliance with Laws:
- Depending on your region, automated actions might have legal considerations (especially scraping data or sending unsolicited messages). Make sure you’re not violating any anti-spam laws for example, if sending DMs for marketing.
- If you are collecting data via the API, ensure compliance with privacy laws (don’t store personal data without reason, etc.).
Finally, always ask: “If Instagram staff manually looked at my account’s activity, would it look normal or obviously automated?” Aim for normal. If you find yourself thinking “but I want to like 1000 posts per hour”, then you’re likely going to get caught.
Security is about both protecting data and behaving in a way that doesn’t trigger alarms. By following these practices, you dramatically increase the chances your automation runs smoothly for the long term.
Deploying and Running on Cloud Servers
Once your Instagram automation script is working well on your local machine, you might want to deploy it to a cloud server so it can run continuously. This section will guide you through choosing a cloud provider, setting up a Linux VPS (Virtual Private Server), and deploying your Node.js bot to run 24/7.
9.1 Choosing a Cloud Provider
There are many cloud providers out there. Here are a few popular ones and considerations:
- DigitalOcean: Simple VPS provider, very beginner-friendly. You can spin up a droplet (server) in minutes. It’s a straightforward Linux box. They have a $5/month plan that is often enough for small bots.
- Linode/Vultr: Similar to DigitalOcean in pricing and simplicity.
- Amazon Web Services (AWS): More complex but very powerful. AWS offers a free tier (like a t2.micro EC2 instance free for 12 months). However, the learning curve is higher (EC2 setup, security groups, etc.). Overkill for a simple bot unless you’re already familiar.
- Google Cloud Platform (GCP): Also has free credits and micro instances. Similar complexity to AWS.
- Microsoft Azure: Also powerful, similar story. Not typical for a small hobby deployment.
- Heroku: A platform-as-a-service that can host Node.js easily. It’s very beginner-friendly (git push to deploy), but their free tier sleeps after 30 min of inactivity which isn’t good for a bot. Paid tiers are fine but might be pricier than a VPS.
- Glitch/Repl.it: Online IDEs that can host Node apps. Possibly could run a simple bot, but they often have limitations (sleep, no ability to run headless if needed for real-time, etc.).
- Others: There’s also the option of a Raspberry Pi at home (not cloud, but 24/7 at your home), or lesser-known providers.
For this guide, let’s assume using a basic Ubuntu Linux VPS on DigitalOcean (or similar provider). That’s a common scenario.
9.2 Setting Up a Linux VPS (Ubuntu Example)
From earlier in Section 3.4 we already went through initial setup. Here’s a condensed and focused recap for deployment:
-
Create a Server: Choose Ubuntu 22.04 x64 (for example) on your provider. Select a small instance (1GB RAM, 1 CPU). Choose a region close to you or where you want the IP to be (maybe same country as your Instagram usage).
-
Access the Server: They will give you an IP and a root password (or if you added an SSH key, use that). Use an SSH client:
- On Linux/Mac:
ssh root@your_server_ip
- On Windows, use PuTTY or the new Windows Terminal (which supports ssh).
Accept the fingerprint and proceed (for password auth, enter the given password; you’ll likely be prompted to change it on first login).
- On Linux/Mac:
-
Basic Security Config (optional but recommended):
- Create a new user so you’re not running everything as root:
Then you canadduser instabot # create a user named instabot usermod -aG sudo instabot # give it sudo privileges
ssh instabot@your_server_ip
from now on (after setting a password for instabot when prompted during adduser). - Enable firewall:
That ensures only SSH is open. Our bot doesn’t need any incoming ports open since it just makes outbound requests.sudo ufw allow OpenSSH sudo ufw enable
- (For deeper security, use SSH keys, disable password auth, etc. but that’s beyond scope.)
- Create a new user so you’re not running everything as root:
-
Install Node.js:
Update apt and install Node.sudo apt update && sudo apt upgrade -y sudo apt install -y nodejs npm
Check
node -v
. If it’s an older version (Ubuntu might give Node 12 or 14), you might want to use nvm:curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash source ~/.bashrc nvm install --lts
That would install latest LTS Node (like 18.x). Ensure when you type
node -v
it shows the correct version. -
Set up your project on the server:
- Option 1: Git clone – If your code is in a git repository (e.g., private GitHub), you can install git (
sudo apt install git
), thengit clone https://github.com/yourrepo.git
. This is clean. Update by pulling from git. - Option 2: SFTP – Secure copy the files directly to the server.
- Option 3: Recreate – For a simple script, you might just create a new
index.js
and copy-paste code via nano or vim. But better to have version control.
Assuming Option 1, after clone, go into the project directory:
cd instagram-bot
.
Then install dependencies:npm install
. (This will fetch instagram-private-api and others, so make sure your server has internet – it should). - Option 1: Git clone – If your code is in a git repository (e.g., private GitHub), you can install git (
-
Configure environment on server:
- Create your
.env
on the server (nano .env and paste your secrets). - Make sure permissions are such that only your user can read it (
chmod 600 .env
ideally).
- Create your
-
Test run:
Runnode index.js
on the server. Watch the output. If it logs in and does whatever it’s supposed to, great. If there’s an error like missing dependency or such, fix accordingly (maybe you forgot to install dotenv or something – just install it).Keep in mind if your bot is meant to run continuously, running it in a normal SSH session will tie it to your terminal.
-
Daemonize / Keep Alive:
To run the bot indefinitely:- Use PM2:
sudo npm install -g pm2
. Thenpm2 start index.js --name instabot
. PM2 will keep it running in background even after you disconnect. You can dopm2 logs instabot
to see output later, andpm2 startup
to configure PM2 to start on reboot. - Or use screen/tmux: You can start a screen session
screen -S bot
, run the script, detach (Ctrl+A, D). Not as robust as PM2 in case of crashes. - Or as a systemd service: If you know how, you can create a service file so it starts on boot.
- If using Heroku, you’d have a Procfile and use their worker dynos, etc. But we’ll stick to VPS scenario.
Using PM2 is straightforward and recommended for beginners. Check
pm2 status
to see it running. If it crashes, PM2 usually restarts it automatically. (You can configure restart delays, etc., if needed.) - Use PM2:
-
Monitor:
Keep an eye on it. You can reconnect via SSH any time and checkpm2 logs
or just see if your Instagram account is doing what it should. If you have logging in code (like writing to a file or DB), verify that’s working.
Also, ensure that your server’s clock is correct (for scheduling) – usually yes if NTP is on. -
Scaling / Multiple Instances:
If you eventually manage multiple bots, you could either:- Run multiple processes via PM2 (maybe one per account).
- Use one process that handles multiple accounts sequentially.
- Or get multiple servers if needed (if IP/proxy separation is important).
A single small VPS can often handle dozens of accounts if it’s just making network calls (not heavy CPU). But be mindful of memory if eachIgApiClient
holds a lot. Test gradually.
-
Backups:
Consider backing up your code and any important data (session files, etc.) from the server. Cloud servers can fail or you might accidentallyrm -rf
something. If your code is on git, you’re fine there. But also backup session files if you rely on them so you don’t lose all your saved logins.
9.3 Running and Scheduling Tasks on the Server
If your bot needs to run on a schedule (say, every day at 6pm, make a post), you have a couple options:
- Cron jobs: On Linux, you can set a cron to run a script at certain times. E.g.,
crontab -e
and add0 18 * * * cd /home/instabot/instagram-bot && /usr/bin/node post_picture.js
. This would run at 18:00 daily. - PM2 + Cron: Alternatively, you can keep a PM2 process running that checks the time and triggers tasks. Simpler for scheduling a one-off daily might be a cron though.
- Third-party schedulers: If not comfortable with cron, there are services or npm packages like
node-cron
where your app can schedule internally.
Since Node is always running, you can even write a loop that waits until a target time. But cron is reliable and decoupled.
Cloud-specific Considerations:
- AWS EC2: Similar to above, but you have security groups (make sure port 22 open for SSH). No other special steps.
- Heroku: If you went that route, you’d use a Worker dyno for continuous process. If it’s not web, free dyno would sleep though. So likely paid.
- Docker: Some might dockerize the bot. That’s an option if you prefer containerization, but for a single script, it might add complexity unless you’re comfortable with it.
Costs: Keep an eye on usage. DigitalOcean $5/mo is fixed. AWS free tier is free but after a year they charge. Don’t accidentally spin a high-tier instance.
IP Reputation: Sometimes cloud server IPs may have a poor reputation (if previously used by spammers). If you have trouble even logging in due to the IP, you might switch region or provider, or use a proxy as discussed. Generally, DO and Linode IPs are okay, but you never know who had that IP before.
Location: If you’re concerned about IG detecting sudden location changes (e.g., you always used in NY, now bot runs from Germany), you can either use a proxy near NY or just complete the challenge once saying “yes it was me” and it often remembers the device+location as trusted after.
Server Maintenance:
- Keep software updated (run updates monthly or so).
- If the server reboots (due to maintenance or power, etc.), ensure your bot restarts. If using PM2, run
pm2 save
and set up startup script aspm2 startup
guided. Or if using cron, ensure cron is in place. - Watch disk space if you log a lot. Use
df -h
to ensure logs aren’t filling up the disk (maybe implement log rotation or clear old logs).
Deploying to cloud might seem daunting if you’ve never done it, but it’s a great learning. Once set up, it’s largely hands-off, just occasionally check that everything is running fine. You can then boast that your code is running on a server and doing things while you sleep – which is really cool!
Advanced Automation Examples
Up to now, we’ve covered the fundamentals. In this section, we’ll explore a few real-world use cases of the Instagram Private API with complete sample code or pseudocode, combining features we’ve discussed. These examples will illustrate how to build specific automation tasks:
- Example 1: Auto Like & Comment Bot for a Hashtag – A bot that searches for recent posts in a hashtag and likes them (and maybe comments).
- Example 2: Welcome DM Bot – Automatically send a welcome message to new followers.
- Example 3: Scheduled Photo Poster – Post a photo from a folder every day at a given time.
- Example 4: Story Viewer & Saver – View stories of specific users and save them (like an archiver).
- Example 5: Multi-account manager – Handling two accounts in one script, e.g., to cross-post or monitor one from another.
These examples will consolidate the knowledge and provide templates you can adapt to your needs.
Example 1: Auto Like & Comment Bot for a Hashtag
Task: Periodically fetch recent posts for a given hashtag, like each post, and comment “Nice shot!” (or a random compliment) on each.
Important: This kind of bot can be spammy, so be cautious with usage. We’ll include safeguards like cooldown after X actions.
require('dotenv').config();
const { IgApiClient } = require('instagram-private-api');
const ig = new IgApiClient();
const Bluebird = require('bluebird');
const HASHTAG = 'sunset';
const COMMENTS = [
"Amazing shot! 😍",
"Love this! 🔥",
"Nice photo 👍",
"Great capture 😊"
];
(async () => {
ig.state.generateDevice(process.env.IG_USERNAME);
await ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD);
console.log(`Logged in as ${process.env.IG_USERNAME}. Starting hashtag bot for #${HASHTAG}`);
const hashtagFeed = ig.feed.tags(HASHTAG, 'recent');
let likeCount = 0;
const MAX_LIKES = 30; // do at most 30 likes per run
const MIN_DELAY = 15, MAX_DELAY = 45; // seconds between actions
let posts = await hashtagFeed.items();
for (let post of posts) {
if (likeCount >= MAX_LIKES) {
console.log("Reached max likes for this run. Stopping.");
break;
}
// Only interact if not already liked (the item has a property has_liked)
if (post.has_liked) {
console.log(`Already liked ${post.id}, skipping.`);
} else {
try {
await ig.media.like({ mediaId: post.id });
console.log(`Liked post ${post.id} by ${post.user.username}`);
likeCount++;
} catch (err) {
console.error("Error liking post:", err.message);
// If rate limit or action block, break out to avoid further issues
if(err.message.includes('feedback_required') || err.message.includes('rate limit')) {
break;
}
}
// Comment as well
try {
const commentText = COMMENTS[Math.floor(Math.random()*COMMENTS.length)];
await ig.media.comment({ mediaId: post.id, text: commentText });
console.log(`Commented "${commentText}" on post ${post.id}`);
} catch (err) {
console.error("Error commenting on post:", err.message);
// Not breaking out; commenting might fail if disabled on post or etc.
}
}
// Delay between actions
const delaySec = Math.floor(Math.random() * (MAX_DELAY - MIN_DELAY + 1)) + MIN_DELAY;
await Bluebird.delay(delaySec * 1000);
}
console.log("Hashtag like/comment run complete.");
})();
Explanation: This script logs in, then gets the “recent” feed for #sunset. It iterates through the fetched posts, likes each if not already liked, comments a random compliment, and waits 15-45 seconds between each action. It also stops after 30 likes in one go to avoid overdoing it.
You could set this script to run every hour or two via cron to continuously engage with a hashtag. Just be mindful not to exceed safe limits.
Example 2: Welcome DM Bot
Task: When someone follows your account, automatically send them a welcome or thank you message via DM.
Approach: We need to identify new followers. One way: keep track of current followers list, periodically check for changes. For simplicity, we’ll store the last seen follower count and fetch the newest followers. A robust way is to keep a file or DB of all follower IDs and diff, but that’s beyond a short example, so we might just react to an increase in follower count.
require('dotenv').config();
const { IgApiClient } = require('instagram-private-api');
const ig = new IgApiClient();
const fs = require('fs');
const WELCOME_MSG = "Hey, thanks for the follow! 😊 Let me know if you have any questions.";
(async () => {
ig.state.generateDevice(process.env.IG_USERNAME);
await ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD);
console.log("Logged in, checking followers...");
// Load last follower count from file (or 0 if not exists)
let lastCount = 0;
const countFile = 'lastFollowerCount.txt';
if(fs.existsSync(countFile)) {
lastCount = parseInt(fs.readFileSync(countFile, 'utf8')) || 0;
}
// Get current followers count and list
const profile = await ig.account.currentUser();
const currentCount = profile.follower_count;
console.log(`Current followers: ${currentCount}, last recorded: ${lastCount}`);
if(currentCount > lastCount) {
// We have new followers
const newFollowersNum = currentCount - lastCount;
console.log(`Detected ${newFollowersNum} new follower(s).`);
// Fetch the most recent followers
const followersFeed = ig.feed.accountFollowers(profile.pk);
const followersFirstPage = await followersFeed.items();
// followersFirstPage is sorted newest first typically.
for(let i = 0; i < Math.min(newFollowersNum, followersFirstPage.length); i++) {
const newFollower = followersFirstPage[i];
const username = newFollower.username;
const userId = newFollower.pk;
console.log(`Sending welcome DM to ${username}`);
try {
const thread = ig.entity.directThread([userId.toString()]);
await thread.broadcastText(WELCOME_MSG);
console.log(`Sent welcome message to @${username}`);
} catch(err) {
console.error(`Failed to DM @${username}:`, err.message);
}
// small delay between DMs to be safe
await new Promise(res => setTimeout(res, 3000));
}
} else {
console.log("No new followers since last check.");
}
// Update the last follower count file
fs.writeFileSync(countFile, currentCount.toString());
})();
Usage: You’d run this script periodically (e.g., every 10 minutes via cron). It remembers the last follower count from a file. When new followers are found, it sends each a thank you message. We limited welcome DMs to at most the page size of first fetch. For accounts gaining hundreds of followers a day, you’d need a better approach (pagination and memory of who was messaged already).
Ensure to not spam someone who unfollows and re-follows (this simplistic method would message them again since they’d appear as a new follower). A more robust solution is to store the list of messaged user IDs persistently.
Example 3: Scheduled Photo Poster
Task: Automatically post a photo (with a caption) every day at a certain time. The photos are pre-collected in a folder.
We can use node-cron to schedule daily posting, or rely on an external scheduler. Here’s with node-cron for simplicity:
require('dotenv').config();
const { IgApiClient } = require('instagram-private-api');
const fs = require('fs');
const path = require('path');
const cron = require('node-cron');
const ig = new IgApiClient();
const PHOTO_DIR = './photos'; // directory with photos and captions
(async () => {
ig.state.generateDevice(process.env.IG_USERNAME);
await ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD);
console.log("Logged in. Scheduler started.");
// Schedule to run every day at 9am (server time). Adjust cron as needed.
cron.schedule('0 9 * * *', async () => {
console.log("Cron triggered - time to post a photo.");
try {
// Pick the next photo to post
const files = fs.readdirSync(PHOTO_DIR).filter(f => f.toLowerCase().endsWith('.jpg') || f.toLowerCase().endsWith('.png'));
if(files.length === 0) {
console.log("No files left to post.");
return;
}
const fileToPost = path.join(PHOTO_DIR, files[0]);
// Determine caption: maybe have a matching .txt file with same name
let captionText = '';
const captionFile = fileToPost.replace(path.extname(fileToPost), '.txt');
if(fs.existsSync(captionFile)) {
captionText = fs.readFileSync(captionFile, 'utf8');
}
const imageBuffer = fs.readFileSync(fileToPost);
await ig.publish.photo({ file: imageBuffer, caption: captionText });
console.log(`Posted image ${files[0]} with caption: ${captionText}`);
// Move or delete the photo after posting to avoid reposting
fs.unlinkSync(fileToPost);
if(fs.existsSync(captionFile)) fs.unlinkSync(captionFile);
} catch(err) {
console.error("Error in scheduled post:", err.message);
}
});
})();
In this script:
- We use
node-cron
to schedule a job at 9 AM every day. - On trigger, it reads the first image in
./photos
directory, reads a caption from a.txt
file if available (e.g., if you haveimage1.jpg
andimage1.txt
). - Posts the photo with that caption.
- Deletes the photo (and caption file) after posting to not duplicate next time.
You would just leave this script running (via PM2 or similar). Each day at 9 AM it runs the function. You could also schedule multiple times or specific days using cron syntax.
This way you could load up a folder with content for a week or month, and the bot will handle posting.
Example 4: Story Viewer & Saver
Task: Check a list of specific users (could be your friends or competitors) and save their story content locally for archival or later viewing.
We’ll illustrate viewing and downloading stories of one user. It can be looped for multiple users.
require('dotenv').config();
const { IgApiClient } = require('instagram-private-api');
const fs = require('fs');
const https = require('https');
const ig = new IgApiClient();
const TARGET_USERS = ['friend1', 'friend2']; // usernames whose stories to save
const DOWNLOAD_DIR = './saved_stories';
(async () => {
ig.state.generateDevice(process.env.IG_USERNAME);
await ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD);
if (!fs.existsSync(DOWNLOAD_DIR)){
fs.mkdirSync(DOWNLOAD_DIR);
}
for(let username of TARGET_USERS) {
try {
const userId = await ig.user.getIdByUsername(username);
const reelsFeed = ig.feed.userReels(userId);
const storyItems = await reelsFeed.items();
if(storyItems.length === 0) {
console.log(`No active stories for ${username}.`);
continue;
}
console.log(`${username} has ${storyItems.length} story items. Saving...`);
for(let item of storyItems) {
// Each item could be image or video
const url = item.media_type === 1
? item.image_versions2.candidates[0].url // image
: item.video_versions[0].url; // video
const filename = path.join(DOWNLOAD_DIR, `${username}_${item.id}.${item.media_type===1?'jpg':'mp4'}`);
const file = fs.createWriteStream(filename);
await new Promise((resolve, reject) => {
https.get(url, response => {
response.pipe(file);
file.on('finish', () => {
file.close(resolve);
});
}).on('error', err => {
fs.unlink(filename, ()=>{}); // delete partial file
console.error("Download error:", err);
reject(err);
});
});
console.log(`Saved story ${item.id} to ${filename}`);
}
} catch(err) {
console.error(`Failed to get stories for ${username}:`, err.message);
}
}
})();
This logs in, then for each target user:
- Gets their userId.
- Fetches their story feed (
userReels
). - For each story item, determines if image or video, grabs the URL and downloads it using https.get to a file. We name the file with username and the item’s ID and appropriate extension.
You could run this script every hour to keep saving new stories. But beware: downloading content may violate copyright if you misuse it. Do this only for personal archival or with permission.
Also note: Instagram might have measures to not allow saving of some content; however, since it’s just grabbing the media URL, it should work as long as the session is valid to access it.
Example 5: Multi-Account Manager
Task: You have two Instagram accounts and you want to occasionally cross-post or monitor one from the other. For instance, if account A gets a DM mentioning a keyword, account B should post a photo.
Multi-account typically means logging in with two different clients. It’s often simpler to just run two separate processes (one per account). But you can do it in one script by juggling two IgApiClient
instances.
However, for demonstration, let’s show handling two accounts sequentially:
require('dotenv').config();
const { IgApiClient } = require('instagram-private-api');
// assume we have two sets of credentials in env: IG_USERNAME_1, IG_PASSWORD_1, IG_USERNAME_2, IG_PASSWORD_2
const ig1 = new IgApiClient();
const ig2 = new IgApiClient();
(async () => {
// Login first account
ig1.state.generateDevice(process.env.IG_USERNAME_1);
await ig1.account.login(process.env.IG_USERNAME_1, process.env.IG_PASSWORD_1);
console.log(`Logged in as ${process.env.IG_USERNAME_1}`);
// Login second account
ig2.state.generateDevice(process.env.IG_USERNAME_2);
await ig2.account.login(process.env.IG_USERNAME_2, process.env.IG_PASSWORD_2);
console.log(`Logged in as ${process.env.IG_USERNAME_2}`);
// Example action: Forward any new DMs from account1 to account2 via DM
const inboxFeed = ig1.feed.directInbox();
const threads = await inboxFeed.items();
for(let thread of threads) {
if(thread.has_newer) { // indicates new unseen messages in thread
const threadId = thread.thread_id;
const threadFeed = ig1.feed.directThread(threadId);
const items = await threadFeed.items();
// find new messages that are not sent by me
const newMessages = items.filter(item => !item.seen_by && item.user_id !== ig1.state.cookieUserId);
for(let msg of newMessages) {
if(msg.item_type === 'text') {
const text = msg.text;
console.log(`Forwarding message from ${thread.users.map(u=>u.username).join(', ')} to second account: ${text}`);
// Send as DM from second account to second account itself or a specific user (maybe to me on account2)
const selfId2 = ig2.state.cookieUserId;
const thread2 = ig2.entity.directThread([selfId2.toString()]);
await thread2.broadcastText(`Forwarded from ${process.env.IG_USERNAME_1}: ` + text);
}
}
// Mark thread as seen on account1 to avoid reforwarding same messages
await ig1.directThread.seen(threadId, items[0].item_id);
}
}
})();
This is a contrived example: It logs in account1 and account2. Then checks account1’s inbox for new messages, and forwards the text of any new messages to account2 (here I just DM it to myself on account2 as a way of receiving it).
Multi-account scripts can get complicated. It might be easier to separate them. But it’s important to note you should not reuse one IgApiClient
for multiple logins – always separate as shown.
These advanced examples serve as starting points. They combine different aspects of the API:
- Example 1: Hashtag scraping + like/comment automation.
- Example 2: Follower monitoring + DM sending.
- Example 3: Media uploading with scheduling.
- Example 4: Story fetching and downloading.
- Example 5: Multi-account coordination + DM reading.
By studying these, you can mix and match ideas for your own needs. Always remember to adjust the logic to fit safe practices (e.g., add delays, check for errors, etc.). Automation is powerful, but should be used thoughtfully, especially on a platform like Instagram.
Community and Resources
The journey doesn’t end with this guide. The Instagram Private API landscape is always evolving – Instagram changes things, libraries get updates, and new tips/tricks are discovered by the community. In this final section, we’ll point you to resources and communities where you can get help, stay updated, and delve deeper.
11.1 Official Documentation and Library Resources
-
GitHub – instagram-private-api: The repository where the Node.js library is mainta-L385】.
- Check the README for basic usage examples (some of which we referenced).
- The Wiki/Docs folder: It contains documentation for different classes and functions. For example, you can find what methods
IgApiClient
has, or what fields aMediaRepository
-L179】. - Issues: Searching issues can reveal how others solved problems (like handling challenges, using certain endpoints, etc.). For example, someone asked how to send DMs on Stack Overflow and referenced a GitHub-L175】.
- The maintainers (like
dilame
andNerixyz
) sometimes post updates or important notes in issues about changes or deprecations.
-
npmjs.com: The np5-L22】 for instagram-private-api shows basic info and sometimes usage instructions. It also links to the GitHub.
-
Examples directory: On GitHub there’s an
examples
folder with sampl-L206】. These can be super helpful to see how to do certain things (e.g., uploading story e-L554】).
11.2 Stack Overflow and Q&A
Stack Overflow has a lot of Q&A about Instagram automation:
- Questions tagged
instagram-api
orinstagram-private-api
often contain nuggets. For example:- Someone asking about direct me-L117】 and an answer shows how to use
broadcastText
. - “How to use a proxy with instagram-privat-L111】 had a Q&A around setting
proxyUrl
.
- Someone asking about direct me-L117】 and an answer shows how to use
- If you have a specific error or use-case, search there first. (Be mindful: Stack Overflow doesn’t like questions that are too broad or about violating terms, but technical usage of a library is usually fine.)
11.3 Developer Forums and Blogs
- Reddit: There’s a subreddit
r/Instagram
(though more user-centric), andr/InstagramAPI
might exist. Alsor/socialengineering
or similar sometimes talk about bots. But for direct dev help, Reddit might be hit or miss. - Blogs/Tutorials: Many developers share experiences:
- The Syndicode blog we refe-L153】 – “Make magic with instagram-private-api” – explained a scenario of finding food bloggers.
- Personal dev blogs: e.g., Ryan Carmody’s blog had a tutorial on automating5-L18】.
- Medium articles: *“How I integrated the Instagram Private API in React Na7-L21】 or *“Using Instagram Private API for data extrac-L142】 – these give insights and sometimes code.
- YouTube: Some videos demonstrate building bots with this API (like a search 5-L18】 references automating posts with Node.js and instagram-private-api).
- Dev.to: There’s at least one a9-L27】.
When reading community content, always cross-check if it’s up-to-date. A post from 2019 might have outdated code due to library changes.
11.4 Community Forums and Chat
- Discord/Slack groups: There might be programming communities or growth hacking groups where Instagram automation is discussed. Be cautious – some might be focused on black-hat botting. But technical help can be found.
- GitHub Discussions/Issues: Some repos have a Discussions tab where you can ask questions not as formal as issues. Check if
dilame/instagram-private-api
has one. - Quora: Possibly, but quality of info can vary.
- If you find an active community, engage by sharing your experiences or asking for help on specific issues.
11.5 Keeping Updated with Instagram Changes
Since we’re using an unofficial API, we need to stay informed about Instagram’s platform changes:
- Instagram App Updates: When the Instagram app announces new features (like Reels, or new story features), the private API might eventually support them (or need to adapt to them).
- API Deprecation: If Instagram closes a loophole or changes how an endpoint works (for example, a change in login flow), the private API might break. Following the GitHub repo for new releases (watch or check occasionally) will tell you if you need to update.
- Data365 or other “Instagram Private API” services: There are services like data365 that provide APIs for Instagra9-L37】. Even if you don’t use them, their blogs or docs might give insight on current capabilities and -L155】.
- Hacker News: Occasionally, something about Instagram private APIs pops up (e.g., a news of Instagram DMCA takedowns of certain3-L27】, which has happened with another popular private API repo in PHP).
11.6 Legal and Best Practice Guides
- Facebook for Developers: For completeness, reading the official Instagram Graph API docs can be useful to understand what’s officially allowed or not. It also has best practices which sometimes apply generally (like handling rate limits).
- Legal Advice Communities: If you’re doing something on a larger scale (like providing a service), it’s worth seeing discussions on legality. The Reddit legaladvice 9-L15】 and others indicated using private API is against Instagram’s terms. Know the risks.
11.7 Packages and Alternatives
- There are similar libraries in other languages (Python’s instagrambot/instagrapi, PHP’s instagram-php, etc.). Sometimes reading their documentation can shed light on endpoints and usage as well, since they all target the same private API endpoints but in different languages.
- If Node.js library has limitations or is not updated, you might temporarily use Python’s if it’s more active, as a workaround (not ideal, but as a backup plan).
Lastly, a word on asking for help: When reaching out in communities, be specific about your problem, show what you’ve tried, and avoid indicating usage that clearly violates Instagram’s terms in malicious ways (like “how do I scrape all users’ emails” – that will get negative attention). Focus on technical issues and you’ll find people more willing to help.
Summary: You are not alone! Many developers are tinkering with Instagram automation. By tapping into these resources, you can learn new techniques, troubleshoot issues faster, and perhaps even contribute back with your own insights. The key is to keep learning and stay adaptable – what works today might need tweaking tomorrow.