Instagram Email Scraper & Recent Posts avatar

Instagram Email Scraper & Recent Posts

Pricing

$19.99/month + usage

Go to Apify Store
Instagram Email Scraper & Recent Posts

Instagram Email Scraper & Recent Posts

πŸ“§ Instagram Email Scraper & Recent Posts finds verified emails from public profiles, bios & contact buttons fast. 🎯 Perfect for lead gen, influencer outreach & CRM enrichment. ⚑ Bulk search, filters & CSV export. βœ… Save time, grow pipelines, stay compliant.

Pricing

$19.99/month + usage

Rating

0.0

(0)

Developer

ScrapeBase

ScrapeBase

Maintained by Community

Actor stats

0

Bookmarked

18

Total users

3

Monthly active users

11 hours ago

Last modified

Share

Instagram Email Scraper & Recent Posts πŸ“§πŸ“Έ

Instagram Email Scraper & Recent Posts is a keyword-based Instagram email scraper and Instagram lead generation tool. It searches Google for public Instagram content matching your keywords, acts as an Instagram email finder on the title/snippet text of each hit, and β€” for every surviving account β€” attaches its recent public posts (date, type, caption, likes, comments) plus a dormant account filter, so you can judge niche-fit and activity before emailing instead of mailing blind off a Google snippet.

Discovery still happens entirely through Google's index (site:instagram.com <keyword>), exactly like the base actor β€” no login, no cookies needed for the email-discovery half. The instagram recent posts attachment adds one extra Instagram request per unique account (deduplicated so the same account is never looked up twice in a run) using Instagram's own public feed endpoint, which does require a valid Instagram session cookie supplied at runtime via the igSessionId secret input.

What It Does πŸ”Ž

  • Runs a Google search (site:instagram.com <keyword>) for every keyword you provide, through Apify's dedicated GOOGLE_SERP proxy group.
  • Parses each results page for genuine Google result blocks (not just keyword-matching on page text), so a normal "no results" page is never mistaken for real hits.
  • Extracts any email address present in the result's title + snippet text β€” the core instagram email extraction step.
  • Filters to only instagram.com URLs and, optionally, only specific email domains.
  • De-duplicates within the run β€” the same URL or the same email is only ever pushed once, even across pages and across keywords.
  • Paginates automatically per keyword until it collects maxEmails results or hits 5 consecutive empty pages.
  • For every surviving row, optionally looks up the account's recent public posts and its last-post date, then drops rows whose account has gone quiet for longer than a configurable window.

This makes it useful as an instagram contact finder and instagram outreach leads source for anyone who wants to build an outreach list from public Instagram activity around a topic, niche, or industry term β€” without scraping Instagram directly for discovery.

Key Features ⭐

  • πŸ”‘ Keyword-driven discovery β€” search by niche, industry, or business term (e.g. marketing, bakery, real estate agent) instead of needing a list of usernames up front.
  • πŸ“§ Email domain filtering β€” keep only @gmail.com, @outlook.com, a custom business domain, or leave it empty to keep every domain found.
  • πŸ“ Location narrowing β€” bias results toward a city/country by adding it to the query.
  • 🎯 Per-keyword result cap β€” maxEmails controls how many emails are collected for each keyword, so cost is predictable.
  • 🧹 Cross-page, cross-keyword de-duplication β€” no duplicate rows and no double-charging for the same URL or email within a run.
  • 🌐 Built-in Google-SERP proxy β€” uses Apify's GOOGLE_SERP proxy group automatically; your own residential/datacenter proxy groups are honored as-is if you explicitly set them.
  • πŸ“Έ Recent-posts attachment β€” for every surviving row, looks up the account's public post feed and attaches username, lastPostedAt, postsFetched, and recentPosts[] (post URL, shortcode, date, type, caption, likes, comments) β€” this is what makes it an instagram post scraper on top of an email finder.
  • πŸ“… Dormant account filter (postedWithinDays) β€” automatically drops accounts whose last post is older than N days, so dead leads never reach your dataset.
  • 🧒 Lookup ceiling (maxProfileLookups) β€” a hard cap on extra Instagram requests per run, so cost stays predictable even on large keyword lists.

Use Cases 🎯

  • Instagram lead generation β€” build an outreach list of businesses and creators active around a keyword or niche, straight from public Instagram activity.
  • Influencer outreach β€” find contact emails for accounts posting about a topic, then check their recent posts before reaching out for collaborations.
  • B2B prospecting β€” search by industry term (e.g. real estate agent, personal trainer, bakery) to source niche-specific leads at scale.
  • Cold-email list hygiene β€” use the dormant account filter so an outreach list never includes accounts that stopped posting a year ago.
  • Market & competitor research β€” see which public Instagram profiles and posts surface for a keyword, what contact info they expose, and how recently active they are.
  • Domain-targeted campaigns β€” use emailDomains to collect only business-domain emails (e.g. a specific company domain) instead of generic free-mail addresses.

How It Works βš™οΈ

This actor is a Google search scraper for discovery, not an Instagram login-based crawler. For each keyword it:

  1. Builds a site:instagram.com <keyword> <location> Google query.
  2. Fetches the results page through the GOOGLE_SERP proxy group (or your own proxy configuration, if set).
  3. Parses real result containers (title, link, snippet) and regexes out any email address in that text.
  4. Keeps only rows whose URL contains instagram.com and, if set, whose email matches your emailDomains list.
  5. Moves to the next results page until maxEmails is reached or 5 pages in a row return nothing new.

Because it relies on Google's index of public Instagram content, coverage reflects what Google has crawled and shown for that keyword β€” not a live, exhaustive scan of Instagram itself.

For each surviving row (when fetchRecentPosts is on), the actor additionally:

  1. Parses the account's username for free from the row's own url field (no extra request). Non-profile URLs (posts /p/..., reels /reel/..., hashtag/explore pages) are skipped β€” postsFetched=0, lastPostedAt=null.
  2. Skips the lookup entirely if that username was already looked up earlier in the same run (dedup on username, before any request is made) β€” the cached result is reused instead.
  3. Makes one GET /api/v1/feed/user/{username}/username/?count=N request to Instagram's own public feed endpoint, authenticated with the igSessionId runtime input's session cookie. This request always goes direct (no proxy) β€” the GOOGLE_SERP proxy group is Google-search-specific and would not route Instagram traffic correctly.
  4. Sorts whatever items came back by post date descending and computes lastPostedAt as the maximum post date across them β€” never just the first item, because Instagram's feed is not strictly chronological (pinned posts can sort first).
  5. Truncates to recentPostsCount posts for recentPosts[], and applies the postedWithinDays dormant-account filter if enabled.
  6. Stops issuing new lookups once maxProfileLookups unique accounts have been checked in the run β€” later rows still ship with every base field intact, only the recent-posts fields are null/0/empty.

Input Parameters 🧩

πŸ“¦ Example Input (JSON)

{
"keywords": ["bakery", "marketing agency"],
"platform": "Instagram",
"location": "",
"emailDomains": [],
"maxEmails": 20,
"engine": "legacy",
"fetchRecentPosts": true,
"recentPostsCount": 3,
"postedWithinDays": 365,
"maxProfileLookups": 200
}
FieldTypeRequiredDescription
keywordsarray (stringList)βœ…Search terms used to find Instagram content, e.g. marketing, founder, bakery. Each keyword runs its own Google search β€” this is the input that makes the actor keyword-based rather than username-based.
platformstring (select)–Social platform to search. Currently only Instagram is offered β€” a fixed single value. Default: Instagram.
locationstring–Narrows results to a place (e.g. London, New York). Leave blank for worldwide results. Default: "".
emailDomainsarray (stringList)–Keep only emails from these domains (e.g. @gmail.com). Empty = keep every domain found. Default: ["@gmail.com"] (prefill).
maxEmailsinteger (1–5000)–Emails to collect per keyword. Run total β‰ˆ number of keywords Γ— maxEmails (e.g. 10 keywords Γ— 20 = up to 200 billed rows) β€” size it deliberately for multi-keyword runs. Duplicate URLs/emails are skipped and never double-charged. Default: 20.
enginestring (select)–Fetch engine for the Google search. Currently only legacy (the GOOGLE_SERP proxy path) is offered β€” a fixed single value. Default: legacy.
fetchRecentPostsboolean–When ON, looks up each account's public post feed and attaches username/lastPostedAt/postsFetched/recentPosts[]. Non-profile result URLs (posts, reels, hashtag pages) are skipped automatically. Default: true.
recentPostsCountinteger (1–12)–How many of an account's most recent posts to attach to recentPosts[]. A hint, not a hard contract β€” whatever Instagram's feed returns is sorted newest-first and truncated to this count. Default: 3.
postedWithinDaysinteger (0–3650)–Drop a row if the account's last post (lastPostedAt) is older than this many days β€” the dormant account filter. 0 disables it and keeps every row. Rows with no post data to evaluate (non-profile URL, lookup off, private account, or past maxProfileLookups) are never dropped by this filter. Default: 365.
maxProfileLookupsinteger (0–5000)–Hard ceiling on how many unique Instagram accounts get a recent-posts lookup in this run β€” a safety valve, since each lookup roughly doubles request volume per row on top of the base's Google requests. Rows past the cap still ship with every base field intact. Default: 200.
igSessionIdstring (secret)β€“πŸ”’ Instagram sessionid cookie, supplied at runtime only β€” never baked into the Docker image, never logged, never written to the dataset. Required only for the πŸ“Έ Recent Posts lookup. Leave blank to skip recent-posts lookups gracefully (base email fields are unaffected). Default: "".
proxyConfigurationobject (proxy)–Proxy for the Google search requests only (recent-posts Instagram lookups always go direct). Left at default: the actor automatically uses Apify's GOOGLE_SERP proxy group. If you explicitly enable your own Apify Proxy groups here, that configuration is used exactly as set β€” there is no automatic datacenterβ†’residential fallback.

Output Format πŸ“€

Each result is one row: the Google hit, its keyword, the email found in it, and (when the recent-posts lookup ran and succeeded) the account's recent activity.

πŸ“ Example Output (JSON)

[
{
"network": "Instagram.com",
"keyword": "bakery",
"title": "Craft Gourmet Bakery (@craftbakerypensacola) β€’ Instagram photos and videos",
"description": "1,204 Followers, 312 Following, 187 Posts - Craft Gourmet Bakery ... Contact us: sales@craftgourmetbakery.com for custom orders.",
"url": "https://www.instagram.com/craftbakerypensacola/",
"email": "sales@craftgourmetbakery.com",
"username": "craftbakerypensacola",
"lastPostedAt": "2026-07-30T16:00:32Z",
"postsFetched": 3,
"recentPosts": [
{
"postUrl": "https://www.instagram.com/p/DbbEbbjDskb/",
"shortCode": "DbbEbbjDskb",
"postedAt": "2026-07-30T16:00:32Z",
"postType": "Carousel",
"caption": "Fresh sourdough today!",
"likeCount": 671,
"commentCount": 13
}
]
}
]
FieldTypeDescription
networkstringSource label, always Instagram.com (fixed capitalization β€” kept as-is for backward compatibility with the base actor).
keywordstringThe keyword that produced this result.
titlestringThe Google result's title text (usually the profile/post name and handle).
descriptionstringThe Google result's snippet text β€” this is where the email is usually found.
urlstringThe matching instagram.com URL (profile or post).
emailstringThe email address extracted from the title/snippet text.
usernamestring | nullInstagram username parsed from url β€” null for non-profile URLs (posts/reels/hashtag pages).
lastPostedAtstring (ISO8601 UTC) | nullMax post date across whatever the feed returned β€” null if not looked up (recent posts off, non-profile URL, private/blocked account, or past maxProfileLookups).
postsFetchedintegerCount of posts actually returned by the lookup (0 distinguishes "no posts"/"private"/"skipped"/"capped" from a real lookup that found nothing).
recentPostsarrayUp to recentPostsCount posts, newest first. Each item: postUrl, shortCode, postedAt (ISO8601 UTC), postType (Image/Video/Carousel), caption, likeCount, commentCount.

Limitations & Honest Notes ⚠️

  • This is a Google-search scraper for discovery, not an Instagram API client. It only ever sees what Google has indexed for site:instagram.com <keyword> β€” it never logs in to find candidates, so it cannot find content Google hasn't crawled, and coverage varies by keyword the same way any Google search does.
  • platform and engine currently accept one value each. They are real, functioning inputs (they drive the query and the fetch path) β€” this build simply doesn't yet offer alternate platforms or fetch engines, so no other value is available to select.
  • proxyConfiguration has no automatic fallback. If you set your own proxy groups and they get blocked, the run does not silently retry on a different tier β€” it uses exactly what you configured.
  • network is emitted as Instagram.com (capital "I", literal .com suffix) rather than lowercase instagram.com, because it's built directly from the platform input value. This is a known, intentional quirk kept for backward compatibility with the base actor β€” not a bug to expect fixed.
  • The extracted email comes from the search-result text block, not a verified fetch of the profile's own bio β€” on rare results the block's text can include an email that belongs to something else quoted in the same snippet, rather than the profile/post owner.
  • De-duplication is scoped to a single run. The same URL/email won't repeat within one run, but two separate runs (even with the same keyword) are not de-duplicated against each other.
  • A keyword with a genuinely low hit-rate can legitimately return 0 emails after 5 pages β€” this is expected search behavior, not a failure.
  • Recent-posts lookup needs a valid Instagram session cookie, supplied per-run via the πŸ”’ igSessionId secret input (never baked into the image). Leave it blank or let it expire and every account simply gets null/0 recent-posts fields β€” base email fields are entirely unaffected.
  • Recent-posts lookups always go direct (no proxy). They're unaffected by proxyConfiguration, which only applies to the Google-search half β€” the GOOGLE_SERP proxy group is Google-specific and would not correctly route Instagram traffic.
  • The dormant account filter cannot see private accounts' posts. A private account returns 0 items, which looks identical to "genuinely dormant" β€” set postedWithinDays: 0 if your keyword list includes private accounts you still want to keep.
  • Instagram's feed is not chronological. lastPostedAt is computed as the maximum post date across whatever came back, not the first item β€” pinned posts can otherwise make a dormant account look active.
  • recentPostsCount is a hint, not a guarantee. Instagram's feed may return slightly more or fewer items than requested; the actor takes whatever arrives, sorts it, and truncates.
  • Captions are not truncated β€” dataset row size grows with caption length.

FAQ ❓

What does this actor actually scrape β€” Instagram or Google? Discovery scrapes Google search results for site:instagram.com <keyword> queries β€” no login, no Instagram-side rate limits involved. The recent-posts enrichment step, on the other hand, does contact Instagram directly (one request per unique account), using a session cookie supplied at runtime via the igSessionId secret input.

Is this a good instagram email scraper for cold outreach lists? It's built for exactly that: keyword-based instagram lead generation that returns an email plus enough recent-activity context (via the instagram recent posts attachment and dormant account filter) to skip accounts that have gone quiet.

Can it find private Instagram profiles? No, for discovery. Google only ever surfaces what's publicly indexed β€” private profiles and non-indexed content are never reachable via the email-search half. The recent-posts lookup on a private account also returns 0 posts, which is treated the same as "no accessible posts."

How many emails will a run return? Up to maxEmails per keyword. A run with several keywords bills up to keywords Γ— maxEmails rows, minus any duplicate URLs/emails, which are skipped and never double-charged.

Why does platform only let me pick "Instagram"? This build's engine is built specifically around the site:instagram.com Google query β€” the field is a real, working selector, it just doesn't yet have another platform wired up.

Does it retry on a different proxy if Google blocks the request? It retries automatically on the built-in GOOGLE_SERP proxy group. If you supply your own proxy configuration instead, it's used exactly as set, with no automatic escalation to a different proxy tier. Recent-posts lookups against Instagram always go direct regardless of this setting.

How does the dormant account filter decide what's "dormant"? It compares lastPostedAt (the max post date the feed returned) against postedWithinDays days ago. If the account's last post is older than that window, the row is dropped. Set postedWithinDays: 0 to disable the filter and keep every row, including ones with no post data to evaluate.

Why is network shown as Instagram.com instead of instagram.com? It's derived directly from the platform input and kept in that exact casing for compatibility with the base actor's existing output field.

Will turning on fetchRecentPosts slow down or increase the cost of a run? Yes, moderately β€” it adds one extra direct Instagram request per unique account (deduplicated, so the same account is never looked up twice). maxProfileLookups caps how many of those extra requests happen per run.