Instagram Email Scraper & Recent Posts
Pricing
$19.99/month + usage
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
Maintained by CommunityActor stats
0
Bookmarked
18
Total users
3
Monthly active users
10 hours ago
Last modified
Categories
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 dedicatedGOOGLE_SERPproxy 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.comURLs 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
maxEmailsresults 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 β
maxEmailscontrols 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_SERPproxy 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, andrecentPosts[](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
emailDomainsto 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:
- Builds a
site:instagram.com <keyword> <location>Google query. - Fetches the results page through the
GOOGLE_SERPproxy group (or your own proxy configuration, if set). - Parses real result containers (title, link, snippet) and regexes out any email address in that text.
- Keeps only rows whose URL contains
instagram.comand, if set, whose email matches youremailDomainslist. - Moves to the next results page until
maxEmailsis 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:
- Parses the account's
usernamefor free from the row's ownurlfield (no extra request). Non-profile URLs (posts/p/..., reels/reel/..., hashtag/explore pages) are skipped βpostsFetched=0,lastPostedAt=null. - 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.
- Makes one
GET /api/v1/feed/user/{username}/username/?count=Nrequest to Instagram's own public feed endpoint, authenticated with theigSessionIdruntime input's session cookie. This request always goes direct (no proxy) β theGOOGLE_SERPproxy group is Google-search-specific and would not route Instagram traffic correctly. - Sorts whatever items came back by post date descending and computes
lastPostedAtas the maximum post date across them β never just the first item, because Instagram's feed is not strictly chronological (pinned posts can sort first). - Truncates to
recentPostsCountposts forrecentPosts[], and applies thepostedWithinDaysdormant-account filter if enabled. - Stops issuing new lookups once
maxProfileLookupsunique 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}
| Field | Type | Required | Description |
|---|---|---|---|
keywords | array (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. |
platform | string (select) | β | Social platform to search. Currently only Instagram is offered β a fixed single value. Default: Instagram. |
location | string | β | Narrows results to a place (e.g. London, New York). Leave blank for worldwide results. Default: "". |
emailDomains | array (stringList) | β | Keep only emails from these domains (e.g. @gmail.com). Empty = keep every domain found. Default: ["@gmail.com"] (prefill). |
maxEmails | integer (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. |
engine | string (select) | β | Fetch engine for the Google search. Currently only legacy (the GOOGLE_SERP proxy path) is offered β a fixed single value. Default: legacy. |
fetchRecentPosts | boolean | β | 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. |
recentPostsCount | integer (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. |
postedWithinDays | integer (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. |
maxProfileLookups | integer (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. |
igSessionId | string (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: "". |
proxyConfiguration | object (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}]}]
| Field | Type | Description |
|---|---|---|
network | string | Source label, always Instagram.com (fixed capitalization β kept as-is for backward compatibility with the base actor). |
keyword | string | The keyword that produced this result. |
title | string | The Google result's title text (usually the profile/post name and handle). |
description | string | The Google result's snippet text β this is where the email is usually found. |
url | string | The matching instagram.com URL (profile or post). |
email | string | The email address extracted from the title/snippet text. |
username | string | null | Instagram username parsed from url β null for non-profile URLs (posts/reels/hashtag pages). |
lastPostedAt | string (ISO8601 UTC) | null | Max post date across whatever the feed returned β null if not looked up (recent posts off, non-profile URL, private/blocked account, or past maxProfileLookups). |
postsFetched | integer | Count of posts actually returned by the lookup (0 distinguishes "no posts"/"private"/"skipped"/"capped" from a real lookup that found nothing). |
recentPosts | array | Up 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. platformandenginecurrently 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.proxyConfigurationhas 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.networkis emitted asInstagram.com(capital "I", literal.comsuffix) rather than lowercaseinstagram.com, because it's built directly from theplatforminput 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 π
igSessionIdsecret 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 β theGOOGLE_SERPproxy 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: 0if your keyword list includes private accounts you still want to keep. - Instagram's feed is not chronological.
lastPostedAtis computed as the maximum post date across whatever came back, not the first item β pinned posts can otherwise make a dormant account look active. recentPostsCountis 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.