Facebook Posts Search Scraper
Pricing
from $2.99 / 1,000 results
Facebook Posts Search Scraper
π Facebook Posts Search Scraper extracts public posts by keyword or URLβtext, author/page, date, link, reactions, comments, shares & media. π Ideal for social listening, brand monitoring, competitor research & trend analysis. β‘ Fast, scalable, CSV/JSON export.
Pricing
from $2.99 / 1,000 results
Rating
0.0
(0)
Developer
SimpleAPI
Maintained by CommunityActor stats
2
Bookmarked
63
Total users
18
Monthly active users
4 days ago
Last modified
Categories
Share
Facebook Scraper β Posts by Keyword, Engagement and Page Contact Data
Search Facebook for any keyword and collect every public post that matches it β no login, no Graph API access, and no Facebook Developer account. The Facebook Posts Search Scraper returns pageName, text, likes, comments, shares, time, url, and thumb for each post it finds, plus optional page contact details (email, phone, website, address) for outreach. Social listening teams, market researchers, and lead-generation agencies use it to turn a topic into a structured dataset of public conversation. Results are written to the dataset the moment each post is scraped.
What is Facebook Posts Search Scraper?
Facebook Posts Search Scraper is an Apify Actor that takes one or more search keywords, discovers matching public Facebook posts, and extracts each post's text, engagement counts, media, and page identity into a structured dataset. It does not require a Facebook account, session cookie, or Graph API token β it reads only what is publicly visible on facebook.com.
- Discovers posts by free-text keyword (
searchQueries) rather than requiring a list of Page URLs - Extracts core identity fields (
pageName,pageId,facebookUrl) and engagement counts (likes,comments,shares) for every post - Filters results to a recency window (
postTimeRange) enforced before a row is ever saved or charged - Optionally fetches each post's top-level comments into a separate, uncharged child dataset
- Optionally enriches each post's Page with public email/phone/website/address for lead generation
- Exports to JSON, CSV, Excel, or via the Apify API
What data can I extract with Facebook Posts Search Scraper?
Every scraped post is pushed as one row with the fields below (the default dataset view surfaces a 13-field subset; every field listed here is present on the underlying row).
| Field | Example Value | Use Case |
|---|---|---|
facebookUrl | https://www.facebook.com/examplepage | Link back to the Page that authored the post |
pageId | "123456789" | Stable numeric ID for de-duplicating a Page across posts |
pageName | "Example Page" | Display name of the author for reporting |
facebookId | "123456789" | Alias of pageId used in some post-page variants |
postId | "987654321" | Unique ID of the post |
postFacebookId | "987654321" | Alias of postId |
url | https://www.facebook.com/examplepage/posts/987654321 | Direct link to the post |
topLevelUrl | https://www.facebook.com/examplepage/posts/987654321 | Canonical URL used to reach the post |
time | "2026-06-01 14:32:10" | Human-readable publish date (UTC) |
timestamp | 1748788330 | Unix epoch seconds for sorting/filtering |
likes | 542 | Reaction count for engagement ranking |
comments | 38 | Comment count as reported by Facebook |
shares | 12 | Share count as a virality signal |
text | "Excited to announce our new store opening..." | Post body for keyword/sentiment analysis |
link | null | External link attached to the post, if any |
thumb | https://scontent.xx.fbcdn.net/... | Thumbnail/media URL |
searchQuery | "coffee shop" | The keyword that surfaced this row |
contact | { "email": "hello@example.com", "phone": null, "website": "https://example.com", "address": null } | Page contact details when enableContactLookup is on |
commentsFetched | 10 | Count of comments written to the child dataset for this post |
scrapedAt | "2026-07-25T10:12:03+00:00" | Timestamp of extraction for freshness checks |
Engagement and contact data
Each row carries the three core engagement counters β likes, comments, and shares β read directly from the post's own page at scrape time, giving a snapshot of how a post is performing right now. When enableContactLookup is turned on, the Actor additionally fetches the post's own Facebook Page and extracts a contact object (email, phone, website, address) from that Page's public intro/contact card. Fields that genuinely aren't published on the Page are returned as null β never guessed or filled in. A common workflow: sort scraped rows by likes descending to find the highest-performing posts on a topic, then cross-reference contact on the top results to build an outreach list without a second tool.
Keyword and time-range targeting
searchQueries and postTimeRange are the two fields that decide which posts end up in the dataset. searchQueries accepts a list of free-text topics β each one runs as its own search, so broader coverage means adding more entries rather than tuning one query. postTimeRange narrows every query to a recency window (24h, 7d, 30d, 90d, or all time) that is enforced against each post's actual publish timestamp before the row is written, so an out-of-window post never reaches the dataset or gets charged.
Why not build this yourself?
Meta's Graph API does not expose arbitrary keyword-based search over public posts β the Graph API's search endpoints were locked down years ago and today mostly serve apps already connected to a Page or user token, not open topic discovery across all of Facebook. Building keyword-based post discovery yourself means reverse-engineering Facebook's own search surface, handling its anti-bot defenses, rotating proxies for both the discovery step and the per-post fetch, and re-deriving fields like publish time and reaction counts from embedded page JSON that changes shape without notice. Facebook Posts Search Scraper already does this: it runs the discovery step through Apify's GOOGLE_SERP proxy group (required for that method to return rendered results), fetches each discovered post through your own proxyConfiguration, and normalizes the output into a consistent schema regardless of which page layout Facebook served that day.
How to use data extracted from Facebook?
Trend and topic researchers
Enter a topic as one or more searchQueries entries, set postTimeRange to 7d or 30d, and let the run populate the dataset live as each post is found. The output's text, likes, comments, and shares fields are enough to see which angles on a topic are getting traction and which pages are driving the conversation, without opening Facebook manually post by post.
Social listening agencies
Agencies running the same set of brand or client keywords on a recurring basis can schedule this Actor per client, with searchQueries set to the client's brand terms and competitor names. Each run's pageName and text fields show who is talking about the brand and what they're saying, while time/timestamp let the agency compare volume week over week without re-building a search each time.
Market intelligence teams
Running a category keyword (e.g. an industry term or product category) across targetCountry values surfaces how a topic is discussed differently across public Facebook activity in different markets. Aggregating likes and comments by searchQuery and country gives a rough engagement distribution that's useful for spotting where a topic or category is gaining traction before committing budget to it.
AI agents and automated pipelines
Because the Actor is a standard Apify Actor with a JSON input and output, it can be wired into an agent as a tool: an agent passes a topic as searchQueries, gets back structured posts with text and engagement counts, and uses that as grounding context for summarization, trend-alerting, or RAG pipelines β without the agent needing its own scraping or proxy logic.
πΌ Input sample
All 8 parameters are optional β the Actor runs with defaults if you provide nothing.
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
searchQueries | No | array | Keywords/topics to search for on Facebook. Each keyword runs its own search. Default [""] (falls back to "football" if left empty at run time). | ["digital marketing", "coffee shop"] |
maxPosts | No | integer | Max posts to collect per keyword, 1β5,000. Default 10. | 25 |
postTimeRange | No | string (enum) | Recency window enforced before rows are saved: "" (all time), 24h, 7d, 30d, 90d. Default "". | "30d" |
targetCountry | No | string (enum) | Biases the underlying Google search toward a country's results (gl param). Default "" (no bias). | "us" |
targetLanguage | No | string (enum) | Language for the search UI/results (hl param). Default "" (English). | "es" |
enableContactLookup | No | boolean | When true, fetches each post's Page and attaches a contact object (email/phone/website/address). Default false. | true |
maxCommentsPerPost | No | integer | Max top-level comments to fetch per post, 0β500, saved to an uncharged comments-<runId> dataset. Default 0 (disabled). | 10 |
proxyConfiguration | No | object | Proxy used to fetch each discovered post/Page's HTML. The keyword-discovery step always uses Apify's GOOGLE_SERP proxy group regardless of this setting. Default { "useApifyProxy": true }. | { "useApifyProxy": true } |
{"searchQueries": ["digital marketing", "coffee shop"],"maxPosts": 25,"postTimeRange": "30d","targetCountry": "us","enableContactLookup": true,"maxCommentsPerPost": 10,"proxyConfiguration": { "useApifyProxy": true }}
Common pitfall: maxPosts is a per-keyword limit, not a total β if searchQueries has 5 entries and maxPosts is 25, the run can produce up to 125 charged rows, not 25. Size maxPosts and the length of searchQueries together before starting a large run.
π½ Output sample
Output is typed, normalized JSON with a consistent schema across every row, exportable as JSON, CSV, or Excel from the dataset, or fetched via the Apify API.
{"facebookUrl": "https://www.facebook.com/examplepage","pageId": "123456789","pageName": "Example Page","facebookId": "123456789","postId": "987654321","postFacebookId": "987654321","url": "https://www.facebook.com/examplepage/posts/987654321","topLevelUrl": "https://www.facebook.com/examplepage/posts/987654321","time": "2026-06-01 14:32:10","timestamp": 1748788330,"likes": 542,"comments": 38,"shares": 12,"text": "Excited to announce our new store opening...","link": null,"thumb": "https://scontent.xx.fbcdn.net/v/example_thumb.jpg","searchQuery": "coffee shop","contact": {"email": "hello@example.com","phone": null,"website": "https://example.com","address": null},"commentsFetched": 10,"scrapedAt": "2026-07-25T10:12:03+00:00"}
When maxCommentsPerPost is above 0, a separate uncharged comments-<runId> dataset is created with one row per top-level comment (parentPostId, commentText, authorName, likesCount, commentDate, and related fields).
How do you filter and target specific posts?
Two inputs decide result precision here: searchQueries and postTimeRange. searchQueries is free-text, not a category picker β because there's no fixed taxonomy of Facebook posts, precision comes from how specific each keyword is. "coffee shop" returns broad brand chatter; "artisan coffee roastery" returns a narrower, more qualified set of posts. Running multiple related keywords in one array widens coverage without diluting any single query's relevance, since each is searched and scored independently.
Scope is narrowed on two axes: recency and market. postTimeRange is enforced against each post's real publish timestamp before the row is ever written, so a 7d run genuinely excludes older posts rather than hiding them in a post-hoc summary. targetCountry and targetLanguage bias the underlying discovery search toward a specific market, which matters when a keyword is common in more than one country and the default (unbiased, English) results skew toward the wrong audience.
There's no minimum-rating or verification-flag filter here β Facebook posts don't carry a public quality score the way reviews or listings do β so quality control means pairing a specific keyword with a tight postTimeRange rather than filtering on a threshold field afterward.
Volume is controlled with maxPosts, applied per keyword rather than per run β raise it toward the 5,000 ceiling for a deep sweep on one keyword, or keep it low while spreading a wider net across many searchQueries entries for a fast pulse-check.
{ "searchQueries": ["artisan coffee roastery"], "maxPosts": 500 }
{ "searchQueries": ["product recall"], "postTimeRange": "24h", "maxPosts": 50 }
{ "searchQueries": ["real estate agency"], "targetCountry": "gb", "targetLanguage": "en", "maxPosts": 100 }
βΆοΈ Want to try other Facebook scrapers?
| Scraper Name | What it extracts |
|---|---|
| Facebook Page Posts & Comments Scraper | Posts and their full comment threads from specific Facebook Pages |
| Facebook Comments Scraper: Sentiment & Toxicity Analysis | Comment-level sentiment and toxicity scoring for given post/video links |
| Facebook Groups Search Scraper With Group Profile Details | Discovers Facebook Groups by keyword or URL with group profile details |
| Facebook Group Profile Scraper | Full profile details for a given Facebook Group by URL/username/ID |
| Facebook Ads Library Scraper: Creative & Ad Text Details | Competitor ad creatives and ad text from the Facebook Ads Library |
| Facebook User Search Scraper: Related Profiles & Pages | Discovers related public profiles, Pages, and Groups by keyword |
How to extract Facebook data programmatically
This Actor runs as a standard Apify Actor: one API call starts the run, structured JSON comes back from the dataset β no separate scraping infrastructure to maintain.
Python example
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("SimpleAPI/facebook-posts-search-scraper").call(run_input={"searchQueries": ["digital marketing"],"maxPosts": 50,"postTimeRange": "30d",})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["pageName"], item["likes"], item["text"][:80])
Export to spreadsheets or CRM
Export the dataset directly as CSV from the Apify Console or via the API, then import into a spreadsheet or CRM. Map pageName to a Company/Contact Name column, contact.email and contact.phone to your CRM's email/phone fields, and url to a source-link column so every imported row traces back to the original post.
Is it legal to scrape Facebook posts?
Yes β this Actor collects only what is publicly visible on facebook.com, without logging in or accessing content behind an authentication wall, and public posts exist to be seen and shared. That said, scraped rows can contain personal data β a page owner's or individual's name, and when enableContactLookup is on, an email, phone number, or address. Where that applies, GDPR and CCPA govern how you may store and use it: you need a lawful basis for holding personal data and must honor deletion/access requests from the people it describes. Consult legal counsel for commercial applications involving bulk storage of personal data.
β FAQ
What happens to posts that get deleted after being scraped? The dataset holds a snapshot from scrape time β scrapedAt records when that was. Re-run the same searchQueries periodically if you need to detect posts that have since been removed or edited.
Can I get comments along with the main posts? Yes β set maxCommentsPerPost above 0 (up to 500) and each post's top-level comments are written to a separate, uncharged comments-<runId> dataset alongside the main run.
How accurate is the engagement data? The Actor returns likes, comments, and shares exactly as they appear on the post at request time. Counts change continuously on Facebook itself, so treat each row as a snapshot and re-scrape if you need current numbers.
How many posts can I get per run? maxPosts caps collection at up to 5,000 posts per keyword; with multiple searchQueries entries, the total across the run is maxPosts Γ number of keywords.
How does the country/language targeting work? targetCountry and targetLanguage bias the underlying Google-based discovery step toward a specific market's results (gl/hl search parameters) β useful when a keyword returns mostly one country's posts by default and you need coverage from another.
Does this work with Claude, ChatGPT, and AI agent frameworks? It's callable as a standard HTTP endpoint via the Apify API by any agent framework that can make an authenticated REST call β pass searchQueries as input and read structured posts back from the dataset.
Can I use this without a Facebook API key or developer account? Yes β no Facebook login, session cookie, API key, or Developer account is required. The only credential needed is your own Apify account to run the Actor.
Why does discovery always use one specific proxy group? The keyword-search step runs over Apify's GOOGLE_SERP proxy group by technical necessity β that proxy group is what returns rendered search-results HTML for this discovery method. Your own proxyConfiguration still controls the proxy used to fetch each discovered post and Page.
Can I use this for lead generation? Yes β turn on enableContactLookup and each row gets a contact object with any public email, phone, website, and address found on the post's own Page, with null for fields that genuinely aren't published.
What's the one real limitation to know before running this at scale? Discovery depends on a Google-based search of site:facebook.com, so keyword coverage is bounded by what that search surfaces rather than by Facebook's own internal search index β very niche or very new topics may return fewer posts than a broader keyword would.
Conclusion
Facebook Posts Search Scraper turns a keyword into a structured dataset of public Facebook posts β engagement counts, post text, media, and page identity, with optional comment and contact enrichment layered on top. It's built for researchers, social listening agencies, and market intelligence teams who need repeatable, filterable post data without a Graph API token or manual browsing. Start a run in Apify Console with your searchQueries to see results populate the dataset live, post by post.
