How to Scrape Instagram in 2026 (for Free!)
Instagram is the hardest target in this whole series, and pretending otherwise would waste your time. There is no requests one-liner that pulls a hashtag feed for free. Behind almost everything is a login wall, an aggressive rate limiter, and a legal minefield.
But "hard" is not "impossible." You can still pull public profile metadata, post lists, and hashtag samples at small scale with the right open-source tools — if you respect the limits and understand the two errors that stop everyone: the Instaloader 401 and the instagrapi challenge_required.
This guide is the honest map: what is actually scrapable, the three real tools and when to use each, how to survive the rate limits, and where the law draws a hard line.
TL;DR: Anonymous Instagram access is throttled to roughly 1–2 requests per 30 seconds, which is why Instaloader returns 401 "please wait." For more than a couple of public profiles you need an authenticated session, which risks the account and can trigger instagrapi's challenge_required. Use Instaloader for public profiles/posts, instagrapi for deeper private-API access, and the official Graph API for Business/Creator hashtag data (capped at 30 hashtags / 7 days). Pace everything, reuse sessions, and stay on the right side of GDPR. For hands-off public data, our Instagram data API handles the access.
What is actually scrapable (and what isn't)
Before writing a line of code, draw the line between public data and walled data. Most failed Instagram scrapers are people trying to reach the second category with tools built for the first.
| Data | Reachable? | How |
|---|---|---|
| Public profile metadata (followers, bio, post count) | Yes, at low volume | Instaloader / instagrapi |
| Public post lists, captions, like/comment counts | Yes, with a session | Instaloader / instagrapi |
| Hashtag post samples | Limited | instagrapi (risky) or Graph API (Business only) |
| Private accounts | No | Walled — do not attempt |
| Stories, DMs, follower lists at scale | No (practically) | Heavily walled, ban-prone, legally fraught |
The takeaway: public, aggregate, non-personal data is feasible at small scale. Anything that requires impersonating a logged-in user at volume is where accounts get banned and lawyers get involved. Aim for the top rows.
The three tools: Instaloader, instagrapi, Graph API
There are three serious ways in, and they sit on a spectrum from "safe but limited" to "powerful but risky."
Instaloader is a mature Python library for downloading public profiles, posts, and metadata. It can work anonymously (very limited) or with a saved session. It is the gentlest option and the right default.
instagrapi drives Instagram's private mobile API. It is far more capable — hashtags, user feeds, media details — but because it acts like a logged-in app, it carries the highest ban risk and is where challenge_required lives.
The official Graph API is the sanctioned route, but it only serves Business and Creator accounts you manage, and its hashtag search is capped (you can query a limited number of unique hashtags — on the order of 30 — in a rolling 7-day window). It is legitimate but narrow.
Scraping public profiles with Instaloader
Start with Instaloader because it fails safely. Here it pulls a public profile's headline numbers and walks its recent posts:
# pip install instaloader
import instaloader
L = instaloader.Instaloader(
download_pictures=False, # metadata only — kinder on rate limits
download_videos=False,
download_comments=False,
save_metadata=False,
)
profile = instaloader.Profile.from_username(L.context, "nasa")
print("followers:", profile.followers)
print("posts:", profile.mediacount)
print("bio:", profile.biography)
# Walk recent posts (each iteration is a request — go slow)
for i, post in enumerate(profile.get_posts()):
print(post.date_utc, post.likes, post.caption_hashtags)
if i >= 9: # just the latest 10
break
Turning off picture, video, and comment downloads is not just about disk space — each of those is extra requests, and on Instagram requests are the scarce resource. Metadata-only is the difference between a scraper that finishes and one that trips the limiter on profile two.
Fixing the 401 "please wait a few minutes"
Run the code above in a loop over many profiles and you will quickly meet this:
instaloader.exceptions.ConnectionException:
401 Unauthorized - "Please wait a few minutes before you try again."
This is not a bug. Anonymous access to Instagram's endpoints is throttled to roughly one or two requests every 30 seconds, so any tight loop trips it almost instantly. Three things fix it.
First, log in once and reuse the session, so you are not stuck on the harshest anonymous limit. Instaloader can save and reload a session file so you authenticate only occasionally:
USER = "your_account"
try:
L.load_session_from_file(USER) # reuse a saved session
except FileNotFoundError:
L.login(USER, "your_password") # first run only
L.save_session_to_file() # cache it for next time
Second, pace hard — tens of seconds between requests, not milliseconds. Third, use a stable residential IP; jumping IPs mid-session looks like account takeover and makes Instagram more suspicious, not less. Be aware that any automation on a real account risks that account, so use a throwaway you can afford to lose.
instagrapi and the challenge_required error
When you need more than Instaloader exposes — hashtag feeds, richer media data — instagrapi talks to Instagram's private mobile API. The cost is the most infamous error in Instagram automation:
instagrapi.exceptions.ChallengeRequired:
challenge_required
challenge_required means Instagram flagged the login as suspicious and wants verification, usually a code by email or SMS. It fires most often when you log in from a fresh IP or a datacenter range. You handle it with a challenge resolver that supplies the code, and you reuse the session afterward so you are not re-challenged every run:
# pip install instagrapi
from instagrapi import Client
from instagrapi.exceptions import ChallengeRequired
cl = Client()
cl.delay_range = [3, 8] # built-in randomized pacing between calls
try:
cl.load_settings("session.json")
cl.login("your_account", "your_password") # resumes the session
except (FileNotFoundError, ChallengeRequired):
cl.login("your_account", "your_password")
# When prompted, instagrapi calls your challenge handler for the code
cl.dump_settings("session.json") # persist for reuse
# Now you can pull, e.g., recent media for a public hashtag (sparingly)
medias = cl.hashtag_medias_recent("running", amount=20)
for m in medias:
print(m.pk, m.like_count, m.caption_text[:60] if m.caption_text else "")
Setting delay_range is the single most important line: it makes instagrapi pause a randomized few seconds between every call, which is the difference between looking like an app and looking like a bot. Even so, treat instagrapi as the high-risk option and keep volumes small.
Rate-limit survival
Every successful Instagram scraper is really a patience engine. The platform tolerates slow, human-like access and punishes bursts instantly, so your architecture should be built around restraint, not speed.
Reuse sessions instead of logging in repeatedly — each login is itself a suspicious event. Add long, randomized delays between every action. Cap how much you pull per session and stop well before the limiter does. If you must use proxies for distribution, use clean residential IPs and keep one identity per IP rather than rotating mid-session, because the bot signals that flag a session are the same ones we cover in beating headless Chrome detection.
And accept the ceiling: free Instagram scraping is a low-volume activity by design. If your plan needs millions of records, no amount of pacing makes the free path safe — that is the volume where a managed data provider exists precisely to absorb the risk.
The legal line: GDPR, CFAA, and big fines
This is the section to read twice, because Instagram is where casual scraping meets serious law.
On the access question, US courts have leaned permissive: hiQ v. LinkedIn held that scraping public data likely does not violate the Computer Fraud and Abuse Act. But Instagram differs from a public web page in two ways that change the calculus: most data sits behind a login, and almost all of it is personal data.
Personal data means GDPR and similar regimes apply, and regulators have shown they will act. The facial-recognition firm Clearview AI was fined tens of millions of euros across multiple European authorities for scraping personal images without a lawful basis. The lesson is blunt: scraping public aggregate signals is one thing; harvesting personal profiles at scale is what draws fines.
Practically: prefer public, non-personal, aggregate data; honor the terms of service; do not build a personal-data product on scraped profiles without legal advice. We go deeper in the legal and ethical guide to search data collection and is scraping legal in 2026. None of this is legal advice — for anything commercial, talk to a lawyer.
The hands-off alternative
If you want public Instagram signals without running session files, challenge handlers, and a babysitter for the rate limiter, a managed data API does the access for you and returns clean JSON. Serpent offers an Instagram data API alongside its search and YouTube endpoints:
import requests
resp = requests.get(
"https://api.apiserpent.com/api/instagram/profile",
headers={"X-API-Key": "sk_live_your_key"},
params={"username": "nasa"},
)
data = resp.json()
print(data["followers"], data["posts"], data["bio"])
The same account also covers search across Google, Bing, Yahoo, and DuckDuckGo if your project mixes social and web signals — one key, one JSON shape. You can explore the social and search endpoints in the playground before committing.
Skip the challenge handlers and session files.
Serpent's Instagram and social data APIs handle the access, sessions, and rate limits — you get clean JSON for public profiles and posts. Plus search across Google, Bing, Yahoo, and DuckDuckGo from the same key. Get 10 free searches on signup, pay-as-you-go after, no subscription.
Get Your Free API KeyExplore: Instagram API · Social Media APIs · Pricing
FAQ
Can I scrape Instagram without logging in?
Only barely. Instagram allows anonymous access to a small amount of public data, but the limits are brutal — a few requests per session before it returns a 401 and asks you to wait. For anything beyond one or two public profiles, you need an authenticated session, which carries account-ban risk. There is no high-volume anonymous path.
Why does Instaloader return 401 "please wait a few minutes"?
That message is Instagram rate-limiting the anonymous or lightly-authenticated endpoint Instaloader is using. Anonymous access is throttled to roughly one or two requests every 30 seconds, so any loop trips it almost immediately. The fix is to slow down drastically, reuse a saved login session, and pace requests with long randomized delays.
What is the instagrapi challenge_required error?
challenge_required means Instagram has flagged the login as suspicious and wants a verification step, usually a code sent to email or SMS. It commonly fires when you log in from a new IP or datacenter range. You resolve it with a challenge handler that submits the code, and you reduce it by logging in from a stable residential IP and reusing the session.
Is scraping Instagram legal?
Scraping public data is broadly treated as legal in the US after hiQ v. LinkedIn, but Instagram is a higher-risk target: it is behind a login wall, contains personal data covered by GDPR, and its terms of service forbid scraping. Collecting personal profiles at scale has drawn major regulatory fines. Stick to public, aggregate, non-personal data and consult a lawyer for anything commercial. This is not legal advice.



