Instagram serves a proxied client almost nothing in the DOM. On 17 September 2026 we read one public profile through exits in four countries, with and without a browser: the follower, following and post counts arrived only inside the meta description, the rendered pass added no data at all, and each exit country rewrote those fields into a different language.
What Instagram actually serves a proxied client
Every guide on this subject argues about which proxy type is least likely to get an account banned. None of them says what the site returns when you fetch it. So we measured it: eight passes across four Instagram surfaces on 17 September 2026, between 05:33 and 05:37 UTC, through rotating residential exits.
| Surface | Exit | No-JS fetch | Rendered fetch | What you can read |
|---|---|---|---|---|
| Public profile /nasa/ | US | 200, 40 words in the DOM | 200, 40 words — identical | Title and description carry 104M followers, 95 following, 4,925 posts |
| Public profile /nasa/ | DE | 200, 0 words in the DOM | 200, 298 words | Same counts, German labels; the only pass in six that produced a real DOM |
| Public profile /nasa/ | BR | 200, 40 words | 200, 40 words — identical | Same counts, Portuguese labels |
| Public profile /nasa/ | JP | 200, 23 words | not run | Same counts, Japanese labels, field order reversed |
| Post permalink /nasa/p/DdWojaYFDf-/ | US | 200, 0 words in the DOM | 200, 0 words — identical | Description carries 115K likes, 469 comments, the date and the full caption |
| Hashtag /explore/tags/coffee/ | US | redirected to /accounts/login/ | same redirect | Nothing. The public surface stops before the hashtag feed |
| Unknown handle | US | 200, title "Instagram", no canonical | not run | Nothing — and the status code does not tell you that |
| App endpoint /api/v1/users/web_profile_info/ | US | 401 JSON, 119 bytes | not run | require_login true, with rate-limit wording in the message |
Read that table as one sentence: the logged-out surface of Instagram is a profile page and a post page, both of which publish their numbers in <meta> tags for the search crawlers, and nothing else. Hashtag feeds, follower lists and comment threads are behind the login wall. Anything you have seen advertised as scraping "Instagram followers" at scale is either reading those meta tags, using an authenticated session, or using Meta's own Graph API with a business account that granted permission.
The browser tax buys nothing here
Rendering a page in a real browser is the standard answer to an empty DOM, and on Instagram it is the wrong one. Across the six passes where we ran both, the rendered pass returned the same title, the same description, the same canonical and the same word count as the plain HTTP fetch on five of them. The one exception was the German exit, where the rendered pass produced 298 words of DOM against zero without JavaScript — one pass in six, which is a lottery ticket, not an engineering plan.
The costs are not symmetric. The plain TLS fetch of the profile completed in 1.8 seconds; the browser render of the same URL took 4.6 seconds. One later TLS fetch needed a second attempt and took 33 seconds, so treat any single timing as an anecdote and the ordering as the finding. In bytes, one profile document was 835 KB decoded — 627 KB even for the "handle does not exist" shell — and it is compressed with zstd on the wire, so the bandwidth you are billed for is lower than that figure. The same 835 KB of markup yields 13.4 KB of extractable content: a kept ratio of 1.6%. You are paying for a JavaScript bundle to learn three numbers.
This is the same shape we found when we measured what AI crawlers get from JavaScript-rendered pages: the expensive tier is worth buying only where it changes the answer. On instagram.com it does not, so default your fetcher to the HTTP tier and treat the browser as a fallback for a specific, proven case.
Which proxy type Instagram actually needs
Split the question by what you are doing, because the honest answer differs.
- Reading public profiles and posts — rotating residential proxies are enough, and that is what every measurement above ran through. You are fetching a page that Instagram publishes for Googlebot; you need an ordinary consumer IP and a real TLS fingerprint, not an exotic network.
- Datacenter IPs — cheaper per gigabyte, and fine for throwaway checks against endpoints nobody guards. Meta's edge treats them differently from consumer lines, which is the whole reason the two classes exist; the difference is set out in residential versus datacenter proxies. We did not measure datacenter exits against Instagram on 17 September, so we are not going to publish a block rate for them.
- Mobile IPs — 4G and 5G carrier addresses are the closest match to how Instagram is actually used, and they carry carrier targeting. They are also the most expensive class, and for reading public meta tags they buy you nothing that a residential exit does not already give you.
- ISP static IPs — the right class when a workflow needs one stable address for a long time, such as an internal tool that a colleague has authorised. They are sold per IP per month rather than per gigabyte.
What no proxy class does is change Instagram's mind about an account. An IP is one signal among device, behaviour and account history. If you are managing several accounts, do it with the multi-account tools Instagram itself provides, under its rules — a proxy is not a way around a restriction, and any vendor telling you otherwise is selling you a story with your money in it.
Geo targeting changes the data, not just the view
The interesting finding is not that Instagram localises its interface. It is that the only machine-readable numbers on the page are inside a sentence that gets rewritten per country. From four exits, the same profile returned:
- US: 104M Followers, 95 Following, 4,925 Posts
- DE: 104M Follower, 95 Gefolgt, 4,925 Beitraege
- BR: 104M seguidores, 95 seguindo, 4,925 posts — with an em dash where the English string uses a hyphen
- JP: the same three numbers with Japanese labels and the field order reversed, counts trailing their labels rather than leading them
A regex keyed on the word "Followers" returns null on three of those four exits, and silently — the fetch succeeded, the status was 200, the field is just empty. If you are pinning exits by country for geo verification, pin the parser to the country too, or normalise on the numeric tokens and their position rather than on the labels. For ad and creative verification this cuts the other way and in your favour: the page genuinely differs by exit, so checking a campaign from a Brazilian or Japanese line is a real check, not theatre. Country selection is one flag on the username across our 190-plus country pool.
Errors: a 200 that means nothing, a 401 that says "wait"
Two error shapes on this site will waste your afternoon if you trust them at face value.
A missing handle answers HTTP 200. We fetched a username that does not exist and got a 200 response with 627 KB of HTML, the title "Instagram", no canonical and no description. There is no 404 to branch on. The reliable test is the presence of a canonical URL matching the handle, or of the og description; the status code carries no information.
The web app endpoint answers 401 with rate-limit wording. A plain fetch of the profile-info endpoint returned HTTP 401 and this body, in full: {"message":"Please wait a few minutes before you try again.","require_login":true,"igweb_rollout":true,"status":"fail"}. The message tells you to back off; the status code and the require_login flag tell you the request was never going to work without a session and an app-id header. Retrying with a longer sleep burns bandwidth on a request that is not rate limited. Branch on the flag, not the sentence. Genuine throttling on this platform looks like the pattern in our note on 429 Too Many Requests — and with rotating exits, per-IP counters do not accumulate against you in the first place, which is exactly why rotation is the right default here rather than a big pool of sticky sessions.
A redirect to /accounts/login/ is a wall, not a block. The hashtag URL did not 403 us; it answered 200 on a login page. Treat "final URL contains /accounts/login/" as its own terminal outcome in your pipeline, distinct from an error, or you will retry it forever.
What Instagram's own robots.txt says, in its own words
Before any cost math, the paragraph that decides whether this work is for you. We read instagram.com/robots.txt on 17 September 2026. It opens with a notice that automated collection of data on Instagram is prohibited unless you have express written permission, and that authorised agents must comply with Meta's Automated Data Collection Terms. It then names about twenty-two crawlers — Googlebot, Bingbot, DuckDuckBot, Applebot, Twitterbot, Discordbot, LinkedInBot, Pinterestbot, TelegramBot, facebookexternalhit and a handful of SEO spiders — and gives each of them a narrow allow-list, blocking /ajax/, /publicapi/, /query/, /direct/, comment and liked-by paths. Several AI crawlers, including GPTBot, ClaudeBot, PerplexityBot, Amazonbot, Applebot-Extended and Google-Extended, are disallowed outright, as is the Scrapy user agent by name. The final group is User-agent: * with Disallow: /. Five sitemaps are published for the crawlers that are allowed, including a profile sitemap — which is precisely why the counts sit in the meta description in the first place.
So: Instagram publishes those numbers for search engines and forbids everyone else from collecting them automatically. The legal position on reading public web pages is genuinely unsettled and varies by jurisdiction, and robots.txt is a machine-readable policy rather than a statute — but it is a clear, documented statement of what the site owner permits, and "it was public" is not the same argument as "I was allowed". If your use is account-owned data, Meta's Instagram Platform API is the sanctioned route and the one to take. If your use is research or verification on public pages, get your own legal advice on your jurisdiction and your volume, keep the volume proportionate, and do not touch anything behind the login wall. We would rather write that sentence and lose the sale than pretend the file says something else.
Cost math, with the measured page weight
All prices below are ours, published on our own pricing page; nothing here is a claim about any other vendor.
One profile document measured 835 KB decoded. Treat that as an upper bound on billed bytes, since the wire transfer is zstd-compressed. At that upper bound a gigabyte is roughly 1,285 profile fetches, so on Residential Basic at $0.80/GB one fetch costs about $0.0006 and 10,000 profiles cost about $6 of bandwidth. On mobile at $2.30/GB the same 10,000 fetches cost about $18, which is the price of a network property this job does not need. Datacenter traffic is $0.50/GB, Residential Premium is $2.20/GB, and ISP addresses are sold per IP per month rather than per gigabyte.
That $6 is the bandwidth line only. It does not include your parser, the retries, the failures — which still burn bandwidth — or the maintenance when Meta changes the meta description format again. The alternatives price that work instead of that traffic:
- Web Scraping API: $0.0002 per page on the HTTP tier, $0.001 with JavaScript rendering. Given the finding above, the HTTP tier is the one to buy for this target — five times cheaper, for the same data.
- Instagram profile collector: $0.006 per delivered profile, billed only on success. We ran it during this article on two handles: two rows in 2.5 seconds, sixteen fields each, including user_id, verified, is_private, is_business and the profile picture URL — fields that are not in the meta description at all. Ten thousand profiles is $60, against roughly $6 of raw bandwidth plus everything you would have to build and keep running.
- SEO Audit API: $0.0012 per URL for the exact no-JS versus rendered comparison used throughout this article, if you want to repeat these measurements on a different network.
The honest split: if you have the engineering to own a parser and you are reading tens of thousands of profiles, raw bandwidth is an order of magnitude cheaper. If you want rows rather than a project, per-success pricing wins, and failures cost nothing.
What this is good for, and what it is not
Legitimate work that the public surface supports: verifying that your own campaign renders correctly from the countries you bought, checking published follower and engagement counts on creators you are about to pay, monitoring your brand's public presence, and social listening on posts that are public by design. Work the public surface does not support, at any price: anything behind the login wall, follower lists, private accounts, direct messages, and the automation of engagement. Instagram's terms forbid the last category regardless of which IP it comes from, and no proxy changes that.