Request a tool
All toolsGuidesMCP serverRequest a toolPlatformsCategories
Instagram Mentions Scraper icon

Instagram Mentions Scraper

Track who tags or mentions any public Instagram account. One row per post: link, caption, author, likes, comments, date and images.

24 runs on Apify
Run this in the cloudRun on Apify →

Developer & Research Tools

How it works

  1. 1
    Open it on Apify

    Hit Run on Apify — it opens the tool in the cloud, no install.

  2. 2
    Set the inputs

    Adjust usernames, maxItems, resultsPerUsername (sensible defaults are pre-filled).

  3. 3
    Click Run

    The tool runs on Apify’s cloud and collects the data for you.

  4. 4
    Export the results

    Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.

Inputs

FieldWhat it doesType
usernamesThe accounts you want mentions of. A plain handle, @handle or a full profile URL all work. Up to 200 per run.array
maxItemsTotal posts to return across every handle. This is the number you pay for, so keep it low while testing.integer
resultsPerUsernameCap the posts returned for each handle. Leave empty and the row limit above is shared evenly between your handles.integer
onlyTaggedKeep only posts where the account is tagged in the image or credited as a co-author, and drop posts that merely name it in the caption. Filtered posts are never charged.boolean
concurrencyHow many handles to read in parallel. Raise it for a long list; lower it if you supply your own proxy servers and they are few.integer
sessionCookiesLeave this empty. Tagged posts are read without an account, and a built-in session is only used for the handles Instagram will not identify to a logged-out reader — age-restricted brand accounts are the usual case. That built-in session is shared between runs, so if you are working a long list and handles come back blocked, paste your own Instagram cookie here and this run gets a rate limit nobody else shares. In Chrome: F12 → Application → Cookies → instagram.com. The `sessionid` cookie is the one that matters; `csrftoken` alongside it is better. Paste it as `sessionid=...; csrftoken=...`, one entry per account. Cookies are used for this run's requests and nothing else — never stored, never logged, never written to the dataset.array
proxyUrlsLeave this empty. By default the run rotates a large pool of addresses that cost you nothing per gigabyte. Fill it in only if you specifically want the traffic to leave through proxy servers you already pay for, in the form http://user:pass@host:port.array

What you get

A structured dataset — each result includes fields like:

mentionedUsernamementionTypeurlownerUsernamecaptionlikesCountcommentsCounttimestamptypedisplayUrlviewsCountshortCode

Export every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.

Related tools in Developer & Research Tools

Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.

GitHub Scraper iconDeveloper & Research Tools

GitHub Scraper

Search GitHub repos or users and export clean rows: stars, forks, language, topics, license, plus user bio, company, location and follower count.

18 use cases

Stack Overflow / Stack Exchange Scraper iconDeveloper & Research Tools

Stack Overflow / Stack Exchange Scraper

Search Stack Overflow and Stack Exchange by keyword or tags. Get structured questions with score, answers, views, tags, author, and link as JSON or CSV.

2 use cases

Package Registry Scraper (npm + PyPI) iconDeveloper & Research Tools

Package Registry Scraper (npm + PyPI)

Get npm and PyPI package metadata - version, license, repo, keywords, and npm download counts. Search by keyword or look up exact names. No API key needed.

2 use cases

arXiv Scraper iconDeveloper & Research Tools

arXiv Scraper

Search arXiv and get clean JSON: titles, abstracts, authors, categories, DOI, dates and PDF links. No API key. Sort by relevance or date; push to Notion.

2 use cases

OpenAlex Scholarly Works Scraper iconDeveloper & Research Tools

OpenAlex Scholarly Works Scraper

Search 250M+ OpenAlex papers by keyword. Get titles, authors, venue, year, citations, concepts, OA links and full abstracts as structured JSON. No API key.

2 use cases

Crossref Scholarly Works Scraper iconDeveloper & Research Tools

Crossref Scholarly Works Scraper

Search 150M+ scholarly works on Crossref and export DOI, authors, journal, citation count, and abstracts as JSON or CSV. Filter by type and date.

2 use cases

See all Developer & Research Tools →

Instagram Mentions & Tagged Posts Scraper

Give it an Instagram handle and get back the public posts that OTHER people made about it — tagged in the photo, named in the caption, or credited as a co-author. Each row is one post: the link, the caption, who posted it, likes, comments, when it went up, the image URLs and which of your accounts it mentions. No browser, and nothing for you to set up.

  • Reads Instagram's own server-side mentions index for the handle, so you are not paying to sift a profile feed for the handful of posts that happen to mention someone.
  • Tells you HOW each post mentions the account — tagged in the photo, named in the caption, or credited as a co-author — in a mentionType field you can filter on.
  • Watch many handles in one run. A post that mentions two of your handles is returned once per handle, because that is two different findings.
  • Runs with empty input return a labelled sample row, free, so you can see the shape first.
  • Nothing to configure. Handles are read without an account, and a built-in session covers the handles Instagram will not identify to a logged-out reader.
  • A handle that stays unreadable comes back as a free diagnostic row, never as a charged one.

Price

$0.44 per 1,000 mentions, plus a $0.0005 start fee per run (billed per gigabyte of run memory, so exactly that on the default 1 GB).

This is the cheapest Instagram mentions scraper on the market, and it is the same rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.

MentionsTotal cost
100$0.0445
1,000$0.4405
10,000$4.4005
100,000$44.0005

What is actually charged

  • One mention-scraped event per mention row written to the dataset. Nothing else is metered per row.
  • Free: the sample row an empty run returns, and every diagnostic row — a blocked target, a dead URL, a search that matched nothing. Those rows all carry "charged": false.
  • Duplicate posts already returned for the same handle earlier in the run are dropped before they are charged.
  • Handles that do not exist, are hidden from logged-out visitors, or have nobody tagging them produce an uncharged diagnostic row instead of a bill.
  • Posts filtered out by onlyTagged are never charged — the filter runs before billing.
  • A run that finds nothing costs the start fee and nothing more.
  • Rows never leave the dataset without a charge, and are never charged without a row. The billed event is a named one, so there is no price quietly attached to apify-default-dataset-item — the trick that makes some scrapers bill you for their own error messages.

Input

{
  "usernames": [
    "redbull",
    "gopro"
  ],
  "maxItems": 60,
  "resultsPerUsername": 30
}
FieldWhat it does
usernamesThe Instagram accounts you want mentions of. Up to 200 per run. A plain handle, @handle and a full profile URL all work — redbull, @redbull and https://www.instagram.com/redbull/ are the same input.
maxItemsTotal rows to return across every handle. Default 100, hard ceiling 10,000. This is the number you pay for, so keep it low while you are testing.
resultsPerUsernameOptional per-handle cap. Leave it empty and maxItems is shared evenly between your handles; set it and each handle stops at this many posts (still bounded by maxItems overall).
onlyTaggedOff by default. Turn it on to keep only posts where the account is tagged in the photo or credited as a co-author, and drop posts that merely name it in the caption.
concurrencyHow many handles to read at once. Default 4, maximum 8. Raise it for a long list; lower it if you are supplying your own proxy servers and they are few.
sessionCookiesLeave empty. Runs work out of the box using a built-in session for the handles that need one. That session is shared, so on a long list under heavy load some handles can come back blocked; putting your own Instagram cookie here gives the run a rate limit nobody else shares. Paste it as sessionid=...; csrftoken=... — Chrome: F12 → Application → Cookies → instagram.com. It is used for this run's requests and nothing else.
proxyUrlsLeave empty. Fill it in only if you want the traffic to leave through proxy servers you already pay for, as http://user:pass@host:port.

Run it with empty input and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.

Output

One row per mention. A real row from a real run:

{
  "ok": true,
  "charged": true,
  "recordType": "mention",
  "mentionedUsername": "redbull",
  "mentionedUserId": "476322",
  "mentionType": "caption-mention",
  "mentionTypes": [
    "caption-mention"
  ],
  "url": "https://www.instagram.com/p/B3M0F6ODksj/",
  "shortCode": "B3M0F6ODksj",
  "postId": "2147320226877688611",
  "type": "image",
  "caption": "Ducati V4R x @redbull built by @hvmotorcycles 🔥🔥@ducatiusa",
  "hashtags": [],
  "mentions": [
    "redbull",
    "hvmotorcycles",
    "ducatiusa"
  ],
  "ownerUsername": "2wheeltv",
  "ownerId": "4516500559",
  "likesCount": 5403,
  "commentsCount": 25,
  "viewsCount": null,
  "timestamp": "2019-10-04T14:49:00.405Z",
  "timestampIsApproximate": true,
  "displayUrl": "https://scontent.cdninstagram.com/v/t51.82787-15/628070032_18391485244194380_n.jpg",
  "images": [
    "https://scontent.cdninstagram.com/v/t51.82787-15/628070032_18391485244194380_n.jpg"
  ],
  "taggedUserIds": [],
  "coauthorUsernames": [],
  "isVideo": false,
  "productType": "feed",
  "carouselCount": 0,
  "dimensions": {
    "width": 1121,
    "height": 1121
  },
  "accessibilityCaption": null,
  "inputUrl": "https://www.instagram.com/redbull/tagged/",
  "scrapedAt": "2026-08-16T05:12:33.953Z"
}

Field notes

  • mentionedUsername — which of YOUR handles this post is about. It is the join key when you watch several accounts in one run.
  • mentionType — why the post is in the index: photo-tag (the account is tagged in the image), caption-mention (the caption names it with an @), coauthor (the account is a credited co-author), or tagged when Instagram put the post in the index but the public payload does not say which of the three applies. mentionTypes carries all that apply.
  • ownerUsername — the account that PUBLISHED the post — the person talking about you, not you.
  • caption — the full caption as written, newlines and emoji intact. hashtags and mentions are parsed out of it for convenience.
  • likesCount / commentsCount — a snapshot at read time, not at publication. They keep moving.
  • viewsCount — video view count where Instagram publishes one for a logged-out viewer. It is often null, including on videos — see the limitations.
  • timestamp — when the post went up, in ISO 8601 UTC, derived from the post id. It is accurate to the minute for most posts and always lands on the correct calendar date; timestampIsApproximate is true on every row to keep that explicit.
  • displayUrl / images — the largest still image Instagram serves for the post. A carousel lists one image per slide in images; a video or reel gives its cover frame. These are Instagram CDN links and they expire after a while, so download what you need promptly.
  • taggedUserIds — the numeric ids of every account tagged in the media, when the public payload carries them. Ids only — this surface does not publish their handles.
  • url — the canonical post link. Reels get a /reel/ link, everything else /p/.

Every real row carries "charged": true. Sample rows carry "_sample": true and diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.

How it works

  • Instagram keeps a server-side index of the posts that tag or mention an account — the same one behind the Tagged tab on a profile. This Actor asks that index directly, so the work is proportional to the mentions you want rather than to the size of anybody's feed.
  • A handle is first resolved to its numeric account id through Instagram's own public profile card, with the fuller public profile record as a fallback for the rare handle the card will not serve.
  • Results are read a page at a time and followed with the cursor Instagram hands back, until your row limit is reached or the index runs out.
  • Requests leave through a large pool of rotating datacenter addresses. Instagram meters these surfaces per address, so a refusal is answered by moving to another address immediately rather than by waiting, and addresses are retired before they hit their limit.
  • Nothing is rendered in a browser — it is plain HTTP against public endpoints, which is what keeps the price where it is.
  • Every handle is tried logged-out first, because the Tagged tab is part of a public profile page and normally answers an anonymous reader on the first attempt. A built-in session is the fallback for the two cases that measurement showed no address can reach: a handle Instagram will not identify anonymously, and an index that refused every address the run tried.

What people use it for

  • Brand monitoring: run your own handle daily and see every public post that tagged or named you since yesterday, with the engagement each one got.
  • Finding creators and advocates: sort a run by likesCount and you have the accounts putting your brand in front of the biggest audiences, ranked, with links to the posts.
  • User-generated content sourcing: mentionType: "photo-tag" plus images gives you a clean shortlist of photos featuring your product, with the author handle to ask permission.
  • Campaign and event reporting: pull mentions of the campaign account for a date range and total the likes and comments to get earned reach without a social suite subscription.
  • Competitive research on public accounts: watch several handles at once and compare who is being tagged more, by whom, and with what engagement.
  • Influencer verification: check that a creator actually tagged the brand they invoiced for, and see what the post did.

Reading the output

Every run writes three kinds of row, and they are easy to tell apart:

  • Real rows carry "charged": true and "recordType": "mention". These are the rows you paid for, one billed event each.
  • The sample row carries "_sample": true and "charged": false. There is exactly one, it only appears when the input had no usernames, and it exists so you can look at the shape of the output before you spend anything.
  • Diagnostic rows carry "_diagnostic": true, "charged": false, the handle they belong to in mentionedUsername, and an errorCode you can switch on: NOT_FOUND when a handle cannot be read without an account, NO_RESULTS when nobody has publicly tagged or mentioned it, RATE_LIMITED or BLOCKED when Instagram refused the index from every address the run tried, TIME_BUDGET when the run ran out of time before reaching a handle, and BAD_INPUT when the whole list turned out to be unreadable.

If you only want the data, filter on charged == true. The count of those rows always equals the number of events you were billed for, so the dataset is its own invoice.

How this differs from a profile posts scraper

A profile scraper answers "what did this account post". This one answers the opposite question — "what did everyone else post about this account" — and the two barely overlap. If you tried to get mentions by pulling a brand's own feed and searching the captions, you would read hundreds of rows to find none of them, because the posts you want were written by other people entirely. That is the whole reason this Actor exists as its own thing: it reads the index Instagram already keeps for exactly this question, so you pay for mentions rather than for the search.

Limitations

  • Public accounts only. A private account's tagged posts are not public, and nothing here logs in to see them.
  • Some public accounts are hidden from logged-out visitors entirely — age-restricted brands are the usual case, and a handful of others behave the same way. Those handles are retried with the built-in session; the ones it does not open either return an uncharged NOT_FOUND diagnostic row rather than data. Measured logged-out on an 80-handle sample, this affected roughly one handle in eleven, and it is a property of the account rather than of the run, so a plain retry will not change it.
  • The built-in session is shared, and Instagram rate-limits per account rather than per caller, so it is not unlimited throughput. Under heavy concurrent load supply your own cookie in sessionCookies for a rate limit that is yours alone. If the built-in session runs out mid-run, the run finishes with what it collected and says so on its status line rather than failing.
  • An account can hide its own tagged tab, and its owner can remove individual posts from it. Anything removed there is invisible here too — this reflects what Instagram publishes, not everything ever posted.
  • Timestamps are derived from the post id, not read from a publish clock. Measured against Instagram's own value on 48 posts: half were within 33 seconds, nine in ten within two and a half minutes, the worst was just under nine minutes, and every one landed on the correct date. Use them for ordering and for date filtering; do not use them to prove a post went up at an exact second.
  • No video files. This surface publishes cover images for videos and reels, not the MP4, so images holds stills only. viewsCount is frequently null for the same reason.
  • Author details are the handle and the numeric id. Follower counts, display names and verification badges are not part of this payload — run a profile scraper over ownerUsername if you need them.
  • Comments are counted, not returned.
  • Image URLs are signed Instagram CDN links and stop working after a while. Download anything you intend to keep during or shortly after the run.
  • The index is ordered by Instagram, not strictly by date, and it mixes recent and old posts. Ask for more rows and sort on timestamp yourself if you need a strict window.
  • Hard ceilings are 10,000 rows and 200 handles per run. Split larger jobs across runs.
  • Instagram meters these endpoints per address. A very large run can hit a stretch where every address is refused; that produces uncharged RATE_LIMITED rows for the affected handles and the run still finishes as succeeded.

Questions

Does this find posts that only mention the account in a comment?

No. It covers posts that tag the account in the image, name it with an @ in the caption, or credit it as a co-author — the same set Instagram itself shows on the Tagged tab. Comments are a different surface and are out of scope.

What happens if a handle has no mentions at all?

You get one uncharged diagnostic row for that handle with errorCode: "NO_RESULTS", and the run carries on to your other handles. You are never billed for a handle that returned nothing.

Do I need an Instagram account or cookies?

No. Runs work out of the box with nothing filled in. Handles are read the way an anonymous visitor reads a Tagged tab, and the handles Instagram will not identify that way fall back to a built-in session.

Then what is sessionCookies for?

A private rate limit. The built-in session is shared between runs, and Instagram counts requests per account rather than per caller, so a busy hour is a slower hour for everyone using it. Paste your own Instagram cookie into sessionCookies and this run uses only that — its own quota, nobody else's. It is used for the run's requests and nothing else: never stored, never logged, never written into the dataset. Optional, and most runs never need it.

Do I need a proxy?

No. The run brings its own egress and its cost is already inside the price you see. The proxyUrls field exists only for callers who specifically want traffic to leave through servers they already own.

Will the run fail if Instagram blocks it?

No. A blocked, empty or unreadable handle produces an uncharged diagnostic row explaining what happened, and the run still finishes as succeeded. A failed run would still bill you the start fee, which would mean paying to be told something went wrong.

Can I run this on a schedule?

Yes, and that is the main way people use it. Nothing is held between runs, so the same input is safe to repeat. Diff on postId to see only what is new since last time.

How do I get exactly the rows I paid for?

Filter the dataset on "charged": true. Sample and diagnostic rows are always false, and the number of charged rows always equals the number of billed events.

Why is the same post in my results twice?

It is not — check mentionedUsername. If a post tags two of the handles you asked about, you get one row per handle, because for reporting purposes that is a mention of each. Within a single handle, duplicates are removed before anything is charged.