Getting started
Two things are required: the hashtag, and a session cookie for an Instagram account you control.
Why a session is needed at all
Instagram serves hashtag data only to signed-in requests. There is no logged-out path to it — that is Instagram's decision and not a setting anyone can change.
This actor holds no Instagram accounts and never will. There is no account pool, no credential store and no sign-up automation in it. You supply a session for an account you control, which keeps the account risk with the person who chose the target. Expect the account you use to be rate limited by Instagram and eventually actioned, so use one you are willing to lose.
Getting your session cookie
Only two values are needed. Paste them as one line:
sessionid=<value>; csrftoken=<value>
Where to find them
- Open
https://www.instagram.comin a browser signed in to the account you want to use. - Open DevTools — F12, or Ctrl+Shift+I (Cmd+Option+I on a Mac).
- Go to the Application tab (called Storage in Firefox), then Cookies →
https://www.instagram.com. - Copy the Value column for
sessionidand forcsrftoken. - Paste them into the
sessionCookieinput in the format above.
Do not use the Console for this
Running document.cookie in the DevTools Console will not work, and will look like it did. sessionid is an httpOnly cookie, so JavaScript cannot read it — the Console returns every other cookie and silently leaves out the only one that matters. You get a long, plausible-looking string that fails with "has no sessionid".
The Application tab shows httpOnly cookies. The Console cannot, by design.
Pasting your whole cookie header also works — extra cookies are accepted and ignored. The input is marked secret, so it is not shown in the run log.
How long it lasts
Instagram issues sessionid with roughly a year of expiry, so it does not need refreshing often. What ends one early is signing out of that browser, changing the account password, or Instagram invalidating it. After that a run fails with "Instagram refused the session" and you copy a fresh value. Do not click Log Out on the browser you took the cookie from.
All the inputs
| Input | What it does |
|---|---|
hashtagstring · required |
The hashtag to scrape, with or without the leading #. |
resultsLimitinteger · default 100 |
Exact ceiling on delivered posts. This actor never delivers or charges for more than this number, whatever a feed page happens to contain. |
onlyPostsNewerThanstring |
Stop once the feed reaches this date. Accepts a date (2026-08-01), a datetime, or a relative window (7 days, 3 months). The run STOPS at the date rather than filtering afterwards, so asking for a week costs a week of rows. |
onlyPostsOlderThanstring |
Skip posts newer than this date. Combine with the field above to scrape one window. |
sessionCookiestring · required |
Two cookies from a browser signed in to an account you control, as sessionid=…; csrftoken=…. See Getting your session cookie above. Marked secret, so it is not shown in the run log. |
maxPagesinteger · default 50 |
Hard ceiling on requests to Instagram, so a very large hashtag cannot page indefinitely. |
A first run
The last week of #coffee, at most 200 posts:
{
"hashtag": "coffee",
"resultsLimit": 200,
"onlyPostsNewerThan": "7 days",
"sessionCookie": "sessionid=…; csrftoken=…"
}
The run stops at the date or the limit, whichever comes first, and you are charged for the rows that reached your dataset.
How a run ends, and what to do about it
Every run ends in exactly one of these and says which, in its status message and its run log. Nothing ends in silence.
| The run says | What happened | What to do |
|---|---|---|
| Delivered the number of posts you asked for. | It hit resultsLimit. | Nothing. Raise resultsLimit for more. |
| Reached your date cutoff — everything newer has been delivered. | It walked back to onlyPostsNewerThan and stopped. | Nothing. This is the cheap way to poll. |
| Instagram has no more posts for this hashtag. | The feed ran out before your limit. | Nothing. The hashtag is smaller than you asked for. |
| Stopped at the page budget. | It read maxPages pages without reaching your limit or your date. | Raise maxPages. A date far in the past will always hit this first. |
| Stopped at your run budget. | The platform's per-run charge limit was reached. | Raise the run’s max charge in Apify, or lower resultsLimit. |
| This run was started with … MB of memory, above this actor’s 1024 MB maximum. | The run was started outside the memory bounds the actor declares. Apify bills compute by memory × time, while this actor charges per delivered post — so a larger allocation buys no more rows. | You were not charged. Re-run with memory set to 1024 MB or less. It stops before reading anything, so nothing was spent on your side either. |
| Instagram refused the session. | The cookie is expired, wrong, or the account is behind a challenge. | Supply a fresh sessionCookie from a logged-in browser. If instagram.com shows that account a challenge, clear it there first — a cookie captured while the account is checkpointed is refused the same way. |
| Instagram rate-limited the session. | Too many requests from that account or IP. | Wait — the message carries the delay when Instagram gives one — then re-run. |
| Instagram has no hashtag "…". | The tag does not exist. | Check the spelling: the message quotes exactly what was asked for. |
| The request to Instagram failed: … | A network or HTTP error, quoted verbatim. | Re-run. If it repeats, the detail in the message is what to report. |
| Instagram answered with a shape this actor could not read. | Instagram changed its response and the parser stopped matching. | You were not charged. This one is our bug, and you do not have to report it: the parser is checked against live Instagram on a schedule and a break files its own report. |
The last six exit the run as FAILED, not as a success with an empty dataset. A scheduled task therefore sees a failed run rather than a clean one that happened to deliver nothing — the difference between "this hashtag is quiet" and "we never got to look".