Instagram private API client for iOS. Covers device signals, request signatures, session handling, and a large chunk of the mobile API surface.
yarn add @igpapi/ios
import { createIosIgpapi, IosAppLaunchFlow, IosPostLoginFlow } from '@igpapi/ios';
const ig = await createIosIgpapi({
seed: 'any-stable-string', // deterministic device generation
});
// 1. Authenticate (bloks-based — same flow the app uses).
// loginBloks runs the required cold-start login warmup internally.
const login = await ig.loginBloks({ username: 'your_username', password: 'your_password' });
const user = login.logged_in_user;
// 2. The one-time work after a login, then the burst the app sends when it
// starts with a session (feed, stories tray, config sync, quick promotions, …)
// The order of the two is an assumption: how the app orders this work after
// a login has not been captured.
await ig.run(IosPostLoginFlow());
await ig.run(IosAppLaunchFlow());
console.log(`Logged in as ${user.username} (${user.pk_id})`);
// Now use the API
const info = await ig.users.info({ id: user.pk_id });
ig.loginBloksis the login flow the real Instagram app uses. It performs the platform cold-start login warmup internally before the Bloks login request.ig.loginNativecalls the legacy/accounts/login/endpoint — kept for reference only, don't use in production.
Do not manually run the pre-login flow immediately before
ig.loginBloks. The runtime login entrypoint already performs the required cold-start login warmup and chains its state into the Bloks login request. Still run the post-login and launch flows after authentication.
// First run — save snapshot after login
const ig = await createIosIgpapi({ seed: 'my-account' });
await ig.loginBloks({ username, password });
await ig.run(IosPostLoginFlow());
await ig.run(IosAppLaunchFlow());
const snapshot = ig.export();
await fs.writeFile('session.json', JSON.stringify(snapshot));
// Later — restore from snapshot, no re-login
const saved = JSON.parse(await fs.readFile('session.json', 'utf8'));
const ig2 = await createIosIgpapi({ snapshot: saved });
// Run the launch burst before doing anything else.
// The real app sends it on every start of a saved session.
await ig2.run(IosAppLaunchFlow());
♻️ Run
IosAppLaunchFlowwhen waking an idle session. Hitting feature endpoints from a restored session that hasn't been used for hours (or days) with no preceding warmup traffic is a strong anti-abuse signal — the real app always fires its launch burst (feed, stories tray, config sync, quick promotions, …) before the user sees the home feed.
IosAppLaunchFlow models the launch burst of Instagram iOS 451. Two of its
requests need values only the real device has, and are skipped unless you pass
them:
await ig.run(
IosAppLaunchFlow({
pushToken, // the device's APNs token → push/register
inboxUserIds, // the Direct inbox participants the app keeps locally → feed/get_latest_reel_media
}),
);
The flow also keeps a few values in the session for the next launch (a launch
counter, the last config-sync time, the public IP the server reported, the last
peak-hour answer), so persist ig.export() after it runs. That the app carries
these values from one launch to the next is our reading of the captures, not
something they show directly.
IosPostLoginFlow holds the one-time requests the app sent after a login on an
older app version (425): config sync, model downloads, content-filter
dictionaries and similar. They have not been re-checked against the current app
version yet.
Opening Direct screens sends their own requests:
import { IosDirectInboxOpen, IosDirectThreadDetailsOpen, IosDirectThreadOpen } from '@igpapi/ios';
await ig.run(IosDirectInboxOpen());
await ig.run(IosDirectThreadOpen({ threadId, peerUserId }));
await ig.run(IosDirectThreadDetailsOpen({ threadId, peerUserId }));
createIosIgpapi — the only entry point you need. It returns a runtime object whose type documents every available facade and method. Hover/click through the returned type in the reference to see the full API surface without digging through files.
createIosIgpapi returns a runtime with facades for every API surface:
ig.loginBloks — authentication (recommended); ig.loginNative — legacy, reference onlyig.users, ig.friendships, ig.account — profile & social graphig.activity, ig.news, ig.live, ig.clips, ig.highlights — feedsig.collections, ig.creatives, ig.restrict, ig.graphqlWww — other endpointsig.run(effect) — escape hatch for composing Effect workflows directlyIGPAPI_LICENSE_TOKEN environment variable@igpapi/android — Android variant@igpapi/core — core types and HTTP infrastructure