Instagram Hashtag Scraper

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

  1. Open https://www.instagram.com in a browser signed in to the account you want to use.
  2. Open DevTools — F12, or Ctrl+Shift+I (Cmd+Option+I on a Mac).
  3. Go to the Application tab (called Storage in Firefox), then Cookies → https://www.instagram.com.
  4. Copy the Value column for sessionid and for csrftoken.
  5. Paste them into the sessionCookie input in the format above.
The DevTools Cookies panel for instagram.com A drawing of the Application tab. The sidebar shows Cookies with https://www.instagram.com selected. The table lists seven cookies by name, with the values shown as blank bars because no real session is depicted. csrftoken and sessionid are marked as the two to copy. A HttpOnly column carries a tick on datr, ig_did, mid and sessionid, and the tick on sessionid is ringed as the reason JavaScript cannot read it. Elements Console Network Application STORAGE ▸ Local storage ▾ Cookies https://www.instagram.com NAME VALUE HTTPONLY csrftoken datr ✓ ds_user_id ig_did ✓ mid ✓ sessionid ✓ wd httpOnly — no JavaScript can read it
Where the two values are. The Value column is blank here because this is a drawing and not a capture of a real session — in your own browser it holds the strings you copy. The ringed tick is why the Console cannot do this job.

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

InputWhat it does
hashtag
string · required
The hashtag to scrape, with or without the leading #.
resultsLimit
integer · 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.
onlyPostsNewerThan
string
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.
onlyPostsOlderThan
string
Skip posts newer than this date. Combine with the field above to scrape one window.
sessionCookie
string · 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.
maxPages
integer · 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.

Open the actor on Apify

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 saysWhat happenedWhat 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".