Appearance
Lists: followers, following and other feeds
A list of Instagram that has no screen, such as the followers of an account, is a feed. A feed is an effect that opens a cursor; its next effect loads the following page and reports whether there is more. The lists the screens show (the home feed, a profile's posts, the Reels viewer) are walked with nextPage() and swipeToNext() instead (Work with screens).
You call a feed inside the main of an entry, like any effect that has no screen (Effects inside main).
Page through a list
ts
import { AndroidIgpapi, FeedTimelineScreen, followersFeed } from '@igpapi/android';
import { Effect } from 'effect';
import { readFile } from 'node:fs/promises';
const saved = JSON.parse(await readFile('session.json', 'utf8'));
const total = await AndroidIgpapi.launch({
checkpoint: saved,
screen: FeedTimelineScreen,
main: _feed =>
Effect.gen(function* () {
// A feed is an effect that opens a cursor; its `next` effect loads one page.
const followers = yield* followersFeed({ id: '123456' });
const page = yield* followers.next;
let count = page.items.length;
let more = page.hasMore;
while (more) {
const nextPage = yield* followers.next;
count += nextPage.items.length;
more = nextPage.hasMore;
}
return count;
}),
});
console.log(total);followersFeed({ id }) takes the account's id; followingFeed takes the same input. Both are exported by @igpapi/android, as are the other feeds (saved posts, liked posts, blocked users and more): the API reference lists them together under the lists category, with the input of each.
Save a cursor
A feed's cursor says where the next page starts. feed.checkpoint is that cursor, an object you can store and give back to the feed later, so a long list is read over several runs.
ts
import { AndroidIgpapi, FeedTimelineScreen, followersFeed } from '@igpapi/android';
import { Effect } from 'effect';
import { readFile, writeFile } from 'node:fs/promises';
const saved = JSON.parse(await readFile('session.json', 'utf8'));
// The first two pages, and the cursor that says where to go on.
const cursor = await AndroidIgpapi.launch({
checkpoint: saved,
screen: FeedTimelineScreen,
main: _feed =>
Effect.gen(function* () {
const feed = yield* followersFeed({ id: '123456' });
yield* feed.next;
yield* feed.next;
return yield* feed.checkpoint;
}),
});
await writeFile('feed-cursor.json', JSON.stringify(cursor));
// Later, in another program: a saved cursor is an object, so parse what the storage returns.
const resumeFrom = JSON.parse(await readFile('feed-cursor.json', 'utf8'));
const items = await AndroidIgpapi.launch({
checkpoint: saved,
screen: FeedTimelineScreen,
main: _feed =>
Effect.gen(function* () {
const resumed = yield* followersFeed(resumeFrom);
const page = yield* resumed.next;
return page.items.length;
}),
});
console.log(items);