Instagram Posts & Reels Scraper
Pricing
from $1.55 / 1,000 result items
Instagram Posts & Reels Scraper
Scrape Instagram posts and reels with no login, no cookies, no OAuth. Captions, likes, views, comments, carousels, video URLs as clean JSON from $1.90 per 1,000 posts.
Pricing
from $1.55 / 1,000 result items
Rating
5.0
(1)
Developer
IntroPix _
Maintained by CommunityActor stats
0
Bookmarked
188
Total users
93
Monthly active users
3.8 days
Issues response
6 hours ago
Last modified
Categories
Share
Scrape Instagram posts and reels from any public business, creator, or brand account. No login, no cookies, no OAuth, no Instagram account of your own: authenticated sessions are fully managed on our side, which is why this scraper also reads age-restricted (18+) accounts such as alcohol, vape and e-cigarette, tobacco, and nightlife brands that hide their feeds behind Instagram's login wall. Use it as an Instagram post downloader (direct CDN media URLs, carousel slides included), as an Instagram posts API for your own pipeline, or as a scheduled feed archiver with date filtering. It also returns reels that are missing from the profile grid, published only to the reels tab, which a scraper reading the profile feed alone never sees.
This is an independent, unofficial tool. It is not affiliated with, endorsed by, or connected to Instagram or Meta Platforms, Inc. in any way, and it operates independently of the Instagram service.
The short version:
- What it does: you give it Instagram usernames, or links to specific posts and reels, and it returns those posts and reels as clean, structured JSON dataset items (24 fixed fields per post: caption, like/comment/view counts, follower and following counts, profile picture URL and bio, hashtags, mentions, permalink, paid-partnership flag, an off-grid flag, and every media slide with its CDN URL).
- What you need: nothing but the usernames or links. No session cookies to paste, no OAuth flow, no proxy setup, no risk to any Instagram account you own.
- What it costs: $0.0019 per delivered post ($1.90 per 1,000), plus $0.002 per scanned profile and $0.005 per run start. A carousel counts as ONE post, never one charge per slide. You are never charged for failed lookups. Free accounts can test with up to 10 posts per run.
- What it covers: public accounts and age-restricted (18+) accounts. Private accounts are out of scope by design. Optionally also reels that are not on the profile grid (see below).
- How you know what happened: every run writes an
OUTPUTrecord you can read programmatically, so an empty result is never ambiguous (details below).
Why this Instagram posts scraper
-
No login, no cookies, no OAuth. Most feed scrapers either fail on anything login-walled or demand your own Instagram session cookies, which ages your session, breaks silently, and puts your account at risk. Here the logged-in sessions are ours and their upkeep is our problem.
-
Age-restricted (18+) account coverage. Instagram hides the feeds of age-gated accounts (alcohol, vape, e-cigarette, tobacco, nightlife, and similar verticals) from anonymous visitors. Anonymous scrapers return nothing for these accounts. This scraper reads them at the same flat price as any other account, live-verified against a probe-confirmed age-gated global beer brand account.
-
One post = one item = one charge. Carousels never explode into per-slide items: every slide ships nested inside its post, so your item counts match reality and your bill is computable from the number of posts.
-
Predictable output, safe to build on. The schema is a strict allowlist. Every item has exactly the same 24 keys, and every media slide the same 7 keys, always. Upstream changes cannot leak unexpected fields into your pipeline.
-
Date-range scraping built in.
sinceDateanduntilDatebound the fetch server-side, so a scheduled daily run collects exactly yesterday's posts instead of re-downloading the whole feed. -
Honest billing. Charges accrue per delivered result. Failed fetches and upstream errors are never charged.
-
Reels that are not on the profile grid. Creators routinely pull reels off their grid while leaving them public on their reels tab. A scraper that reads the profile feed cannot return those, at any depth or sort order. Turn on
includeOffGridReelsand they come back like any other post, each marked withis_off_grid. Instagram trial reels are a separate case and are not returned: see "Reels that are not on the profile grid" below.
How it compares
| This actor | Anonymous scrapers | Cookie/login scrapers | |
|---|---|---|---|
| Age-restricted (18+) accounts | Yes, standard price | No: Instagram returns nothing without a session | Only through your own session |
| Reels missing from the profile grid | Optional, standard price | Not present in the profile feed these read | Not present in the profile feed these read |
| What you must provide | Usernames only | Usernames only | Your Instagram session cookies |
| Risk to an account you own | None | None | Your session can be flagged or banned |
| Output schema | Fixed 24 fields, every item | Varies by upstream response | Varies by upstream response |
| Carousel billing | One charge per post | Often one item per slide | Varies |
| Charge on failed lookups | Never | Varies | Varies |
Knowing why a run returned nothing
An account with no posts and a run that hit your plan limit both produce zero
dataset items, so the dataset alone cannot tell you which happened. Every run
therefore writes a machine-readable OUTPUT record to its default key-value
store, alongside the human-readable run status message:
{"outcome": "denied","reason": "user_daily_exhausted","message": "Free-plan trial limit reached. Upgrade to a paid Apify plan to run larger scrapes: https://apify.com/pricing","granted_results": 0,"granted_targets": 0,"delivered": 0,"failed_targets": [],"failed_target_reasons": {}}
outcomeisokordenied. Branch on this rather than on dataset length.outcome: "ok"withdelivered: 0means the accounts genuinely had no posts. That is a successful run.outcome: "denied"means nothing was scraped and nothing was charged.reasonsays why, andmessageis safe to show an end user. One reason is specific to this actor:call_budget_below_minimum, meaning the remaining budget could not cover even a single profile, so the run exited before charging anything.failed_targetslists usernames that could not be scraped, so a partial run is visible too. Its shape is unchanged and will not change without notice: a plain list of strings. A post link that could not be delivered appears here exactly as you entered it.failed_target_reasonssays WHY each of them was skipped, as{"username or link": {"reason": "...", "message": "..."}}. Branch onreason; showmessageto a person. A skipped target is never charged, whatever the reason.
reason | What it means | What to do |
|---|---|---|
not_found | Instagram reports no such account. | Check the spelling; the account may be deleted or renamed. Drop it from your list. |
temporarily_unavailable | A problem on our side, not with this username. | Retry shortly. |
unavailable | This account cannot be served by the actor. | Nothing; retrying will not help. |
invalid_link | A postUrls entry is not an Instagram post or reel link. | Use a link like https://www.instagram.com/p/<code>/ or /reel/<code>/. |
post_not_found | Instagram reports no such post. | The post may be deleted, or the link mistyped. |
share_link | A postUrls entry is an Instagram share link, which does not contain the post address. | Open the link in a browser and copy the URL from the address bar. It will look like https://www.instagram.com/p/<code>/. |
links_abandoned | Ten links in a row came back missing, so the run stopped checking the rest. | Refresh the link list; these entries were not checked and cost nothing. |
On a denied run, reason is one of:
reason | What it means |
|---|---|
user_daily_exhausted | Your own free-plan allowance for the day is used up. |
free_capacity_exhausted | The shared free pool is momentarily used up. Not about your account. |
call_budget_below_minimum | The remaining budget could not cover even a single profile. |
guard_backend_unavailable | Free-tier capacity is temporarily unavailable. Retry later. |
nothing_requested | The input asked for zero results. |
Free runs are genuinely free, and each one costs us real upstream calls, so
a finite amount of that capacity is set aside for free users at a time. You
are welcome to explore the actor on the free tier: if a run is turned away
with free_capacity_exhausted, the shared pool is simply busy rather than
anything being wrong with your request, and it frees up on its own. Any
paid Apify plan runs without that ceiling.
Read it via the API at
/v2/key-value-stores/{defaultKeyValueStoreId}/records/OUTPUT, or with the
client libraries.
How it works
- Input a list of usernames (plain usernames, one per line or as a JSON
array), optionally with a date range and a post cap. Or paste links to
the specific posts and reels you want in
postUrls, or both in one run. - The actor pages through each account's feed (posts and reels) through
managed authenticated infrastructure, stopping once your
maxPostsor date bounds are satisfied. Instagram does not return the feed in date order (pinned posts come first, and the tail is unsorted), so each account's results are sorted by post date before delivery: within an account you get its newest posts, newest first, instead of whatever order the feed happened to use. - Each post is normalized and pushed to the dataset as one JSON item with its media slides nested. Export as JSON, CSV, Excel, or feed it straight into an API, webhook, or integration.
Post links are fetched first, one post per link, and are always delivered:
maxPosts, the date range and mediaType only shape what is taken from the
usernames' feeds. A post that arrives both by link and from a username's feed
is delivered and charged once.
Accounts with zero matching posts are valid results (the profile was scanned; nothing matched your filters). Accounts that cannot be resolved are skipped and not charged.
Input
{"usernames": ["nike", "redbull", "vapeshopexample"],"postUrls": ["https://www.instagram.com/reel/DYmweb2IhAG/"],"maxPosts": 100,"sinceDate": "2026-06-01","untilDate": "2026-06-30"}
| Field | Type | Meaning |
|---|---|---|
usernames | array of strings, optional | Instagram usernames to fetch posts and reels for. Business, creator, and brand accounts (see Terms of Use below). Give at least one username or one link. |
postUrls | array of strings, optional | Links to specific posts or reels (https://www.instagram.com/p/<code>/, /reel/<code>/, /reels/<code>/, /tv/<code>/, with or without the username in the path or a ?igsh= suffix). Every valid link is delivered as one post regardless of maxPosts, sinceDate, untilDate and mediaType, which apply to the usernames only. Billed like any other post: one result-item per delivered post plus one profile scan per distinct account the links belong to, so five links from one account cost one scan. Items are identical to feed items, including follower counts, bio and view counts (includeViews applies). is_off_grid is always false for a link, because no profile grid was read to compare against. Free runs still deliver at most 10 posts in total. |
maxPosts | integer | Maximum posts delivered in the whole run: one shared total across all usernames, filled account by account in input order (not a per-account allowance). Each account contributes its NEWEST posts, sorted newest first, so a single-account maxPosts: 10 means that account's 10 most recent and not the first 10 the feed happens to return. With several usernames the budget is still spent account by account in input order, so the first account can consume it before the later ones are reached. A carousel counts as one post. Default 10. With a mediaType filter set, the delivered total stays shared across usernames but the READS are per-account (each account is read down to maxPosts posts and only its matching ones are delivered), so you receive fewer than maxPosts items and later usernames can run out of call budget first. See mediaType. |
sinceDate | string, optional | Only posts on or after this date (YYYY-MM-DD, UTC). |
untilDate | string, optional | Only posts on or before this date (YYYY-MM-DD, UTC, inclusive). |
mediaType | string, optional | any (default), image, or video. Deliver only photo posts or only video posts, and pay only for what is delivered: a filtered post is never written to the dataset and never billed as a result-item. Note that maxPosts is a budget for how many posts are READ, not a target for how many you receive, so mediaType: image with maxPosts: 100 against an account that is 70% video reads the newest 100 posts and returns the roughly 30 photos among them rather than searching further back for 100 photos. A carousel mixing photos and video is excluded by both filters rather than delivered with slides removed. Reels are never photos, so image also ignores includeOffGridReels and includeViews and skips the reels-feed calls either would have paid for (a photo or carousel has no view count either way). The per-account scan fee still applies to an account read successfully even when none of its posts match. |
includeViews | boolean, optional | Fetch play counts for reels and videos. On by default, so you get view counts without doing anything. Set to false for slightly faster large backfills. Photos and carousels have no view count either way. |
includeOffGridReels | boolean, optional | Also return reels that are not on the profile grid: reels published only to the reels tab. Off by default. They are ordinary delivered posts, so they count towards maxPosts and bill one result-item each, and they respect sinceDate/untilDate like everything else. Every item carries is_off_grid whether this is on or off. Instagram trial reels are a separate case and are not returned, see "Reels that are not on the profile grid" below. |
Output
One dataset item per post, exactly these 24 fields, every time:
{"username": "budweiser","user_pk": "611930682","full_name": "","is_verified": true,"is_private": false,"follower_count": 717553,"following_count": 284,"profile_pic_url": "https://scontent.cdninstagram.com/v/t51.82787-19/...","biography": "It's happening again. The world is ready to Let It Pour.\nOfficial Beer of the #FIFAWorldCup™️ since 1986.","post_pk": "3911603976344753518","shortcode": "DZIzxeICNVu","permalink": "https://www.instagram.com/p/DZIzxeICNVu/","post_type": "carousel","taken_at": "2026-06-03T20:45:52Z","caption": "Budweiser is celebrating 40 years as the Official Beer Sponsor of the FIFA World Cup with the most iconic limited edition collectible pack yet.","like_count": 2870,"comment_count": 57,"view_count": null,"is_paid_partnership": false,"is_off_grid": false,"coauthors": ["budfootball"],"hashtags": [],"mentions": [],"media": [{"slide_index": 0,"media_type": "image","media_url": "https://scontent.cdninstagram.com/v/t51.82787-15/...","cover_url": null,"width": 2250,"height": 2815,"video_duration": null}]}
| Field | Meaning |
|---|---|
username, user_pk, full_name | Account identity (pk is Instagram's stable numeric id). |
is_verified, is_private | Account flags at scrape time. |
follower_count, following_count | Public profile totals at scrape time, null when Instagram does not return them. |
profile_pic_url | The account's profile picture, at the highest resolution Instagram returns for it (400x400 where available, otherwise the 150x150 thumbnail), null when the account has none. Like every media URL here it points at Instagram's CDN and expires, so download it if you need to keep it. |
biography | The account's public bio text as written by the account holder, null when empty. Multi-line bios keep their line breaks. |
post_pk | Stable post id, deduplication key. |
shortcode, permalink | The public URL of the post. |
post_type | image, video, reel, or carousel. |
taken_at | ISO 8601 UTC timestamp. |
caption | Full caption text, null when absent. |
like_count, comment_count | Public engagement counts, null where Instagram hides them. |
view_count | Play count for reels and videos, null when unavailable. Photos and carousels are always null, because Instagram publishes no view count for them. Requires includeViews (on by default). A null here always means "not available", never "zero views". |
is_paid_partnership | Instagram's paid-partnership label. |
is_off_grid | true when the post was NOT on the profile grid this run read. Always present; false for every ordinary post and for every post when includeOffGridReels is off. It states what was measured, not why: reels-page-only reels and trial reels are indistinguishable in Instagram's data, so this deliberately does not claim a post is a trial. |
coauthors | Co-author usernames on collab posts. |
hashtags, mentions | Parsed from the caption. |
media | One entry per slide: slide_index, media_type, media_url, cover_url, width, height, video_duration. Single-media posts have exactly one entry. |
Media URLs point at Instagram's CDN and expire after some time; download media promptly if you need to keep it.
Pricing
Pay per event. You are charged only for what the run actually does:
| Event | Price | Charged when |
|---|---|---|
| Run start | $0.005 | Once per started run. |
| Profile scan | $0.002 | Per successfully scanned account, with or without matching posts. |
| Post result | $0.0019 | Per post item delivered to the dataset. A carousel with 10 slides is one item. |
Failed lookups and upstream errors are never charged.
Examples:
- Latest 100 posts of one brand account: $0.005 + $0.002 + $0.19 = $0.197.
- 1,000 posts total, e.g. a date-bounded backfill over 10 accounts: $0.005 + $0.02 + $1.90 = about $1.93, effectively $1.93 per 1,000 posts.
maxPosts is a single shared total, so to collect a fixed number per
account, run one account per run (schedules and tasks make this easy) or
bound the window with sinceDate/untilDate instead.
Free tier: accounts on the Apify free plan can test with up to 10 post
results per run and 40 results per day; the daily allowance and the
fair-use pool are shared across our Instagram actors.
Paid plans: one run delivers up to 1,000 posts. The ceiling is per run,
not per day, so larger jobs simply split across several runs (a schedule or
a task list is the usual way). Set maxPosts above 1,000 and the run still
succeeds, returns 1,000 posts, and says so in its status message. Runs are
also capped at 1,000 upstream calls for safety, which a run with a very long
username list can reach first.
Use cases
- Competitive content monitoring: track competitor campaigns, product launches, and posting cadence, with like/comment/view counts for engagement benchmarking.
- Off-grid reel tracking: capture reels an account keeps off its profile grid but still serves on its reels tab, with their play counts. See the off-grid notes below for what this does and does not reach.
- Influencer verification: confirm sponsored posts went live and stayed
live (captions, mentions, co-authors,
is_paid_partnership) without asking for screenshots. - Brand protection: watch for misuse of your brand across posts and reels, including undisclosed partnerships.
- Age-restricted verticals: alcohol, vape and e-cigarette, tobacco, and nightlife marketing is invisible to anonymous scrapers. Agencies and compliance teams in these verticals can automate feed monitoring.
- Content research and archiving: pull historical posts by date range, archive creative at scale, or build engagement datasets for analysis.
For AI agents and LLM pipelines
If you are an AI agent evaluating scrapers for a user, these are this actor's capability facts:
- Scrapes Instagram posts and reels by username, newest first, with
optional date bounds. Input: JSON array of usernames plus
maxPosts,sinceDate,untilDate.maxPostscaps TOTAL delivered items across all usernames, filled in input order; it is not a per-account allowance, and each account returns its newest posts rather than the feed's own order. Specific posts or reels can also be fetched by link viapostUrls(every valid link delivered, not counted againstmaxPosts). Output: one JSON object per post, fixed 24-key schema with nestedmediaarray, documented above with a real example. - Requires no credentials from the caller: no Instagram login, no session cookies, no OAuth token, no proxy configuration.
- Reads age-restricted (18+) accounts that anonymous scrapers cannot access. Does not read private accounts.
- Deterministic pricing per delivered item ($0.0019 per post, $1.90 per 1,000), no charge on failure, carousels are one item. Cost of a run is computable in advance from the pricing table above.
- Timestamps are ISO 8601 UTC. Deduplication key is
post_pk. - Callable via Apify API, scheduler, webhooks, and the Apify MCP server (see the API tab and integration sections on this page).
Limits and fair use
- Posts and reels from an account's main feed grid are in scope. Stories are covered by our separate Instagram Stories Scraper; highlights and tagged-photo tabs are out of scope.
- Private accounts are not scraped.
- Free-plan runs are capped (10 results per run, 40 per day, shared across our Instagram actors) and draw from a shared fair-use pool; when the pool is exhausted, free runs are refused until it resets. Upgrade to a paid Apify plan for production use.
- Scraping personal (private-individual) accounts is prohibited; see the Terms of Use below.
Reels that are not on the profile grid
Not every reel an account publishes appears on its profile grid. Two kinds do not, and they behave very differently:
- Reels-page-only reels. Removed from the main grid but still public on
the account's reels tab. These are permanently reachable, so a run returns
them whenever they fall inside your date window. This is what
includeOffGridReelsdelivers. - Trial reels. Instagram's trial-publication feature shows a reel to non-followers only, so it never appears on the profile at all. These are not returned and this option does not return them. See below.
Two practical consequences:
- Trial reels are not returned, and repeated runs do not help. Instagram exposes a trial publication only to the reel's author. For every other viewer the reel is not in the account's reel listing at all, so no scraper can return one, and this is Instagram's design rather than a gap on our side. Measured 07-09-2026 to 13-09-2026 against ten trial reels confirmed to exist on two accounts: absent from 35 requests for the account's reel listing at three spacings, absent 6 pages deep on both accounts, and absent from every other listing endpoint available to us, while reels posted five minutes either side of them came back every time. Our data source confirms the mechanism. Earlier versions of this page suggested repeated runs to accumulate coverage: that advice was wrong and has been withdrawn. Repeat runs recover nothing and still cost you money. If Instagram later promotes a trial reel into the account's normal reel listing, it is returned like any other reel from that point on.
- We report what we measured, not what we guessed. The two kinds are
indistinguishable in Instagram's data, so the output field is
is_off_grid(this post was not on the grid we read) rather than ais_trialfield that would be wrong for a large share of what it marks.
Date filtering works on off-grid reels the same way it does on posts, with
one thing worth knowing: reaching a window that sits well below an account's
newest reels costs extra requests, because the reels feed has to be paged
back to it. The scraper does this for you, up to a fixed ceiling per account,
so a sinceDate from several weeks ago still returns what is there. Runs
without a date filter are unaffected.
Off-grid reels are ordinary delivered posts: they spend the shared
maxPosts budget and bill one result-item each. On accounts that lean
heavily on reels, they can make up most of the feed, so a small maxPosts
with the flag on may return mostly off-grid content. is_off_grid is on
every item, so you can always filter or split them downstream.
FAQ
Why did a trial reel not come back? Because Instagram shows a trial publication only to the reel's author. For anyone else it is not in the account's reel listing, so there is nothing for a scraper to read. Measured 07-09-2026 to 13-09-2026 against ten confirmed trial reels on two accounts: absent from 35 requests for the account's reel listing and from every other listing endpoint we have, while reels posted five minutes either side of them came back every time. Our data source confirms this is how Instagram serves them. An earlier version of this page recommended repeated runs to accumulate coverage; that was wrong and has been withdrawn, because repeat runs recover nothing and still cost you money. Reels that are merely off the grid but still on the reels tab are not affected and come back every time.
Do I need an Instagram account, cookies, or a login session? No. Nothing is required from you except the usernames or post links. Authenticated infrastructure is managed entirely on our side.
Can it scrape age-restricted or 18+ accounts? Yes. Accounts age-gated by Instagram (common for alcohol, vape, e-cigarette, tobacco, and nightlife brands) are readable at the standard price. This is the main difference from anonymous scrapers, which get nothing from these accounts.
Can it scrape private accounts? No. Private accounts are out of scope by design and by our Terms of Use.
How are carousels billed?
A carousel is one post and one charge, regardless of slide count. Every
slide is included in the item's media array.
What does 1,000 posts cost? $1.90 in post results plus $0.002 per profile scanned and $0.005 per run. Typical all-in cost is about $1.93 per 1,000 posts including ten profile scans.
Can I fetch only new posts since my last run?
Yes. Set sinceDate (and optionally untilDate) to bound the fetch. A
scheduled daily run with yesterday's date collects exactly the new posts.
Is scraping Instagram posts legal? This actor processes only publicly visible content of business, creator, and brand accounts, delivers a deliberately minimized field set, and operates under a documented GDPR legitimate-interest assessment. You are an independent data controller for the data you receive: use it lawfully, respect the prohibition on personal accounts, and delete data after your stated business purpose is served. See the Terms of Use and Privacy notice below.
Where do I report a problem or ask for my account to be excluded? team.intropix@gmail.com, or use the Issues tab on this page.
Terms of Use
Operated by Intropix, contact: team.intropix@gmail.com. Last updated: 14-07-2026.
1. What this actor does. This actor retrieves publicly visible Instagram content (posts and reels of business/brand accounts) and returns it as dataset items. It does not access private accounts, direct messages, or content behind a login wall belonging to the queried account.
2. Permitted use. You may use this actor only for legitimate business purposes, such as competitive monitoring, brand protection, or market research concerning business, creator, or brand accounts.
3. Prohibited use. You must NOT use this actor to:
- scrape personal (private-individual) accounts, regardless of whether they are publicly visible; this prohibition extends to further processing of personal accounts that appear in delivered data as mentions or co-authors: you must not use such usernames as new scrape targets or to build data about the individuals behind them;
- build profiles of individuals, including any inference of health, sexual orientation, religious or political views;
- target or collect data about persons under 16;
- store scraped data beyond transient use: retain results only as long as needed for the stated business purpose (as a guideline, no longer than 30 days), then delete;
- resell or republish raw scraped data as a dataset;
- circumvent rate limits, caps, or access controls of this actor or of Instagram;
- process the data in violation of GDPR, UK GDPR, CCPA, or other applicable data protection law.
4. Your responsibilities as data controller. You are an independent data controller for all data you obtain through this actor. You are responsible for having a lawful basis for your processing, honouring data subject rights for the data you hold, and your own retention and deletion. Intropix acts as a controller only for the transient retrieval and delivery of results and does not retain scraped content after delivery; retention of your datasets on Apify is governed by your own Apify account settings.
5. Data subject requests. Individuals whose data may have been processed can contact team.intropix@gmail.com. See the Privacy notice below. Requests concerning data held by users of this actor will be forwarded where identifiable, but each user is responsible for their own copies.
6. Enforcement. Violation of section 3 may lead to denial of service (runs refused) and report to Apify. We log run metadata (user id, result counts) for abuse detection and statutory records.
7. No warranty; liability. Results depend on upstream availability and are provided as is. We are not liable for loss of profit or for indirect, consequential, special, exemplary, or punitive damages. Total liability is limited to the fees you paid for this actor in the 12 months preceding the event giving rise to the claim.
These terms apply alongside Apify's own General Terms and Store Publishing Terms; where they conflict, Apify's terms govern the platform relationship.
Privacy notice for Instagram account owners
This notice is for people and businesses whose Instagram content may have been processed by this actor. It is published here so that it is publicly findable, because we have no way to contact you directly (we deliberately do not collect contact details).
Who we are. Intropix, operator of this actor. Contact: team.intropix@gmail.com. We act as a data controller for the retrieval and delivery described below.
What we process. Publicly visible Instagram posts and reels of business, creator, and brand accounts: the post media itself plus a fixed, limited set of metadata fields (account username, stable numeric account id, and display name, verification and privacy flags, public follower and following totals, the public profile picture URL and the public bio text, post id and public URL, post type and timestamp, caption text, like, comment, and view counts, hashtags and mentions parsed from the caption, co-author usernames, paid-partnership flag, a flag recording whether the post was found on the account's profile grid, media URLs and dimensions). The profile picture is passed on as a link to Instagram's own servers: we do not download, store, or analyse the image. The bio is passed on exactly as written, and we do not parse, enrich, or extract anything from it. We do not collect location data, follower lists (the totals above are counts, never identities), contact details (email, phone, postal address), links from the bio, private content, direct messages, or commenter identities. We do not perform face recognition or build profiles of individuals.
Where the data comes from. Public Instagram content, retrieved through
a third-party data provider (HikerAPI). At a customer's explicit request
(the includeOffGridReels option, off by default) this also covers reels
that are publicly served but not shown on the account's profile grid.
Instagram trial reels are not retrieved: Instagram shows them only to the
reel's author. Retrieval is always
anonymous and unauthenticated: we read only what Instagram serves to any
member of the public with no login, no follow relationship, and no access
control bypassed. We return only what Instagram is publicly serving at the
time of the run, and we keep no copy of it after delivery.
Why we process it and on what legal basis. Our legal basis is legitimate interest (Art. 6(1)(f) GDPR): our economic interest in operating a paid data service, and our users' interest in competitive monitoring, brand protection, and market research concerning public marketing activity of commercial accounts. A documented balancing assessment supports this.
Who receives the data. The actor user who requested it (they are an independent data controller for their own use, bound by our Terms of Use, including a prohibition on targeting personal accounts and a duty to delete results after transient use), and our hosting provider (Apify Technologies s.r.o.) as processor.
How long we keep it. We do not retain scraped content after delivery. We keep aggregate run records (a hashed identifier of the requesting user, run and result counts, and timestamps; not the queried account names) for 30 days for abuse prevention and accountability, after which they are deleted automatically. Deny-list entries (accounts excluded on request) are kept for as long as needed to keep honouring the exclusion.
Your rights. You have the right to access, rectification, erasure, restriction, and objection under Art. 15 to 21 GDPR. Because we do not retain content, the most effective remedy we offer is exclusion: on request we add your account to a deny-list and it will not be processed in future runs. Contact team.intropix@gmail.com. We respond within one month (Art. 12(3)). You also have the right to lodge a complaint with a supervisory authority.
Verification. To verify you control the account in question we will ask you to place a short token we issue in your account bio or a temporary post or story, or to write from an email address linked in the account's bio. We never ask for identity documents.