# Facebook Post Search Scraper - Keyword Search (`automation-lab/facebook-public-post-keyword-search-scraper`) Actor

Search public Facebook posts by keyword or hashtag. Get post text, URL, author, date, reactions by type, comments, shares, media and group for social listening. No login.

- **URL**: https://apify.com/automation-lab/facebook-public-post-keyword-search-scraper.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Social media, Marketing
- **Security:** Limited permissions
- **Stats:** 6 total users, 5 monthly users, 93.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.08 / 1,000 posts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Facebook Post Search Scraper - Keyword Search

Search **public Facebook posts by keyword or hashtag** and export one clean row per post: full text, post URL, author Page or profile, publish date, reactions by type, comments, shares, video views, photos and videos, outbound links, public group and reshare details.

The Actor runs Facebook's own post search exactly as a signed-out visitor sees it. **No Facebook login, cookies or API key** are needed, and you can search many keywords in one run, with Facebook's Top ranking or its Recent posts filter.

### What does Facebook Post Search Scraper do?

You give it a list of search queries such as `coffee`, `#blackfriday` or `plumber near me`. For each query the Actor:

1. Runs Facebook's public **Posts** search for that query, with Facebook's **Top** ranking or its **Recent posts** filter.
2. Follows the result pages (about 10-12 posts per page) until it reaches your limit or Facebook has no more pages.
3. Turns every post into a structured row with the text, author, date, engagement numbers, media and group.
4. Applies your filters (date window, words that must appear, groups vs. Pages, post type, minimum reactions) before saving, so you only pay for posts you keep.

The run's status message says how many posts were saved per query and why each query stopped, for example `"coffee": 100 of 100 (maxPostsPerQuery reached)` or `"plumber near me": 11 of 30 (Facebook returned no more result pages)`.

### Who is it for?

- **Social listening and brand teams** tracking public mentions of a brand, product or competitor on Facebook.
- **Marketing and campaign researchers** studying which public posts about a topic or hashtag get the most reactions, comments and shares.
- **Lead generation teams** finding public group posts such as "looking for a plumber" or "recommend a dentist" and the people asking.
- **Journalists and analysts** collecting public discussion about an event, a product launch or a news topic.
- **Data and AI teams** building datasets of public Facebook posts for classification, sentiment or summarisation.

### Why use this Facebook post search scraper?

- **Facebook's own post search**, not a crawl of a few Pages: results come from every public Page, profile and public group Facebook matches.
- **Every engagement number on every row**: total reactions plus the like / love / care / haha / wow / sad / angry breakdown, comments, shares, and views for videos.
- **Rich media and context**: all photos of an album with captions, video URL, duration and thumbnail, unwrapped outbound links with title and domain, public group name and URL, reshare details and hashtags.
- **Pay only for posts you keep**: posts removed by your date window, word-match, source, type or reaction filters are never saved, so they cost nothing.
- **`matchesQuery` on every row** tells you whether the post text really contains your words, because Facebook also ranks loosely related posts.
- **Many keywords per run**, searched in parallel, each with its own limit and stop reason.
- **No login**: nothing to renew, no account at risk.

### What data can you extract from Facebook posts search?

| Field | What it contains |
| --- | --- |
| `postId`, `url` | Facebook post ID and public permalink |
| `text` | Full post text, never truncated |
| `publishedAt`, `timestamp` | Publish time (ISO 8601 UTC and Unix milliseconds) |
| `authorName`, `authorId`, `authorUrl`, `author` | Page or profile that posted, with profile picture |
| `reactionsCount`, `reactions` | Total reactions and the count per reaction type |
| `commentsCount`, `sharesCount`, `engagementCount` | Comments, shares, and reactions + comments + shares |
| `videoViewCount` | Views for video posts |
| `postType` | `photo`, `album`, `video`, `link`, `share`, `text` or `other` |
| `media`, `mediaCount`, `imageUrl` | Photos and videos with URL, image, size, caption and duration |
| `externalLink` | Outbound link (unwrapped from Facebook's redirect) with title, domain and preview image |
| `isGroupPost`, `groupId`, `groupName`, `groupUrl` | Public group the post was made in |
| `isReshare`, `sharedPost` | Original post of a reshare: ID, URL, text, author, date |
| `privacy` | Audience label, such as `Public` |
| `hashtags` | Hashtags parsed from the text |
| `searchQuery`, `sortBy`, `searchRank` | Which query and sort found the post, and its position in Facebook's results |
| `matchesQuery` | Whether every query word appears in the post |
| `scrapedAt` | When the row was produced |

On a 200-post test run for `coffee` and `#blackfriday`, every row had a URL, date, author, reactions with the per-type breakdown, comments and shares; 96% had an image, 19% were videos with view counts, 18% came from public groups, 62% had hashtags and 79% contained the query word.

### How much does it cost to scrape Facebook posts by keyword?

The Actor uses pay-per-event pricing. You pay a small fee per run plus a fee for every post saved to your dataset. Posts removed by your filters are free. Platform usage (compute and proxy) is included in the price.

| Event | Free / Starter (Bronze) | Scale (Silver) | Business (Gold) and higher |
| --- | --- | --- | --- |
| Run start (once per run) | $0.0005 | $0.0005 | $0.0005 |
| Post saved | $0.0026 | $0.00234 | $0.00208 |

Examples on the Starter plan:

- 20 posts for one keyword: about **$0.05**
- 100 posts for one keyword: about **$0.26**
- 5 keywords × 100 posts in one run: about **$1.30**
- 1,000 posts: about **$2.60**

With Apify's free plan credit of $5 a month you can collect roughly 1,900 posts a month. You can set a maximum cost per run in the run options; the Actor stops cleanly when it is reached.

### How to scrape Facebook posts by keyword

1. Open the Actor in Apify Console and click **Try for free**.
2. Enter your keywords or hashtags under **Search queries**, one per line.
3. Choose **Sort by**: `Top posts` for research, `Recent posts` for monitoring.
4. Set **Max posts per query**, and optionally a date window or other filters.
5. Click **Start**. Posts appear in the dataset as each page of results arrives.
6. Export the results as JSON, CSV, Excel or HTML, or connect them to your tools through the API and integrations.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `searchQueries` | array of strings | required | Keywords, phrases or hashtags, one search each. A `facebook.com/search/posts/?q=...` URL also works. |
| `sortBy` | `top` or `recent` | `top` | Facebook's relevance ranking, or its Recent posts filter (mostly recent posts; rows keep Facebook's order, which is not strictly by date). |
| `maxPostsPerQuery` | integer 1-1000 | `20` | Posts saved per query after filters. |
| `maxItems` | integer | `0` | Cap on posts across the whole run. `0` = no run-wide cap. |
| `startDate` | string | - | Keep posts published on or after this UTC date: `2026-09-01`, `7 days`, `3 weeks`, `2 months`. |
| `endDate` | string | - | Keep posts published on or before this UTC date (whole day included). |
| `mustContainQuery` | boolean | `false` | Keep only posts where every query word appears in the text, shared post text or link title. |
| `postSource` | `all`, `groups`, `pages_and_profiles` | `all` | Only public group posts, or only Page and profile posts. |
| `postType` | `all`, `photo`, `album`, `video`, `link`, `share`, `text` | `all` | Keep one kind of post. |
| `minReactions` | integer | `0` | Keep only posts with at least this many reactions. |
| `proxyConfiguration` | object | Apify datacenter (`SHADER`) | Proxy used for all requests. The default is the tested setting. If Facebook keeps rate-limiting another Apify Proxy setting or no proxy, the run switches to `SHADER`. Your own proxy URLs are never replaced. |

#### Example input

```json
{
    "searchQueries": ["coffee", "#blackfriday"],
    "sortBy": "recent",
    "startDate": "7 days",
    "maxPostsPerQuery": 100,
    "mustContainQuery": true
}
```

### Output example

One real row from a `coffee` search (image URL query strings shortened):

```json
{
    "postId": "122181808466805270",
    "url": "https://www.facebook.com/reel/1819617662436200/",
    "searchQuery": "coffee",
    "sortBy": "top",
    "searchRank": 4,
    "postType": "video",
    "text": "Honey butter latte 🍯🧈✨\nCreamy and delicious 😋 \n\nRecipe :\nPiece of butter \n1 tbsp of honey \nPinch of sea salt \n2 shots of espresso \n5 oz of milk\nIce and shake it \nSalted honey cold foam :\n3 tbsp of heavy cream + 2 tbsp of milk + 1/2 tbsp of honey + pinch of sea salt, froth it until thick \n\n#honeylatte #homecafe #coffee #saltedhoneylatte #honeybutter",
    "publishedAt": "2026-11-01T19:01:36.000Z",
    "timestamp": 1793559696000,
    "authorName": "Rafa Coffee",
    "authorId": "61574158104501",
    "authorUrl": "https://www.facebook.com/people/Rafa-Coffee/61574158104501/",
    "author": {
        "id": "61574158104501",
        "name": "Rafa Coffee",
        "url": "https://www.facebook.com/people/Rafa-Coffee/61574158104501/",
        "profilePictureUrl": "https://scontent-sjc6-1.xx.fbcdn.net/v/t39.30808-1/697792868_122165764160805270_267460172165753330_n.jpg"
    },
    "reactionsCount": 639,
    "reactions": {
        "like": 592,
        "love": 40,
        "care": 4,
        "haha": 0,
        "wow": 3,
        "sad": 0,
        "angry": 0
    },
    "commentsCount": 4,
    "sharesCount": 45,
    "videoViewCount": 14246,
    "engagementCount": 688,
    "imageUrl": "https://scontent-sjc6-1.xx.fbcdn.net/v/t51.71878-10/886224517_2025997718082461_2009185281563289073_n.jpg",
    "media": [
        {
            "type": "video",
            "id": "1819617662436200",
            "url": "https://www.facebook.com/reel/1819617662436200/",
            "imageUrl": "https://scontent-sjc6-1.xx.fbcdn.net/v/t51.71878-10/886224517_2025997718082461_2009185281563289073_n.jpg",
            "width": 1080,
            "height": 1920,
            "caption": null,
            "durationSeconds": 29.7
        }
    ],
    "mediaCount": 1,
    "externalLink": null,
    "isGroupPost": false,
    "groupId": null,
    "groupName": null,
    "groupUrl": null,
    "isReshare": false,
    "sharedPost": null,
    "privacy": "Public",
    "hashtags": [
        "honeylatte",
        "homecafe",
        "coffee",
        "saltedhoneylatte",
        "honeybutter"
    ],
    "matchesQuery": true,
    "scrapedAt": "2026-11-04T07:54:28.454Z"
}
```

### Tips and limits

- **Use one keyword or short phrase per query.** Facebook matches loosely and also ranks related posts. Single words usually match well; long phrases rarely appear verbatim. Turn on `mustContainQuery` when every row must contain your words.
- **Use `recent` for monitoring and `top` for research.** `top` returns popular posts of any age; `recent` switches on Facebook's Recent posts filter, which favours fresh posts. Rows keep Facebook's own order, which is roughly but not strictly newest-first, so sort by `publishedAt` yourself if you need exact date order. Schedule a `recent` run with `startDate: "1 day"` for a daily feed of fresh mentions.
- **How many posts per query?** With `top`, broad terms easily return 100+ posts (100 of 100 for `coffee` and `#blackfriday` in our tests). With `recent`, Facebook serves fewer pages: about 60-90 posts per query in our tests (65 for `electric vehicles`, 75 for `tesla`). Niche terms and narrow date windows return fewer. The run stops when Facebook has no more pages or a per-query page limit is reached, and says which in the status message. A narrow date window or strict filters can hit the page limit before Facebook runs out of pages.
- **Date windows are exact.** The window is sent to Facebook's own date filter and checked again on every post.
- **Public content only.** The Actor sees what a signed-out visitor sees: public Pages, public profiles and public groups. Private groups and friends-only posts are never included.
- **No location filter.** Facebook's tagged-location filter is not available to signed-out visitors, so the Actor does not offer it.
- **Comments are counts only.** Use a comments scraper on the post URLs when you need the comment texts.
- **Failures are reported, not hidden.** If Facebook refuses a query after several fresh sessions, that query is marked failed in the status message; the run fails only when no posts were saved and every query failed. Posts already saved are always kept.

### Integrations

- **Google Sheets or Excel**: export the dataset, or use the Apify Google Sheets integration to append new posts after each scheduled run.
- **Slack, email and webhooks**: trigger a webhook when a run finishes and send new posts with high `engagementCount` to a channel.
- **Make, Zapier and n8n**: start the Actor from a workflow and route posts into a CRM or ticketing tool, for example group posts asking for a service.
- **Data warehouses and BI**: load the JSON or CSV into BigQuery, Snowflake or your BI tool and chart reactions and shares over time.
- **AI pipelines**: feed `text`, `reactions` and `hashtags` to an LLM for sentiment, topic or intent classification.

### Use the Actor through the API

Start a run and wait for the results with cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/automation-lab~facebook-public-post-keyword-search-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries": ["coffee"], "maxPostsPerQuery": 20}'
```

JavaScript (`npm install apify-client`):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/facebook-public-post-keyword-search-scraper').call({
    searchQueries: ['coffee', '#blackfriday'],
    sortBy: 'recent',
    maxPostsPerQuery: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]?.url);
```

Python (`pip install apify-client`):

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/facebook-public-post-keyword-search-scraper").call(
    run_input={"searchQueries": ["coffee"], "sortBy": "top", "maxPostsPerQuery": 50}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["publishedAt"], item["authorName"], item["reactionsCount"], item["url"])
```

### Use with AI agents through MCP

Connect the Actor to Claude, Cursor or another MCP client with the Apify MCP server. For Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/facebook-public-post-keyword-search-scraper"
```

**Claude Desktop**: open Settings → Developer → Edit Config and add:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com?tools=automation-lab/facebook-public-post-keyword-search-scraper"
        }
    }
}
```

**Cursor**: add the same `mcpServers` block to `~/.cursor/mcp.json` (or the project's `.cursor/mcp.json`).

**VS Code**: add the server to `.vscode/mcp.json`:

```json
{
    "servers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com?tools=automation-lab/facebook-public-post-keyword-search-scraper"
        }
    }
}
```

The Actor-specific URL also adds Apify's run and dataset helper tools. A safe agent workflow:

1. **Start once and keep the run ID.** Use a small limit for chat answers, for example `maxPostsPerQuery: 20` and `maxItems: 50`. A run of that size usually finishes in under a minute.
2. **Poll that same run** with `get-actor-run` (waits of 2, 4, 8, then 10 seconds) with a total deadline of 3 minutes. If the deadline passes, do not start a new run: tell the user the run is still going, give the run ID, and check the same run again later. A second run would bill the same search twice.
3. **Read with a context budget.** Call `get-dataset-items` with `fields` limited to what you need (for example `url,text,publishedAt,reactionsCount,authorName`) in pages of 20 rows, and stop at about 100 rows or 60 KB of UTF-8 text in total. Post texts can be long, so cut each `text` to about 300 characters in your answer.
4. **Say when the answer is partial.** If the dataset has more rows than you read, say how many you used out of the total and give the dataset link (`https://console.apify.com/storage/datasets/<datasetId>`) or a CSV/JSON export URL (`https://api.apify.com/v2/datasets/<datasetId>/items?format=csv`) for the rest, instead of pasting everything into the chat.
5. **Check the status message** of the finished run: it gives the posts delivered against the requested number and the stop reason for every query.

Example prompts:

- "Find the 50 most recent public Facebook posts mentioning our brand and summarise the main complaints."
- "Search Facebook posts for #blackfriday from the last 3 days and list the 10 with the most shares."
- "Find public group posts asking for a plumber in the last week and give me the post links."

### Is it legal to scrape Facebook posts?

The Actor collects only public posts that Facebook shows to any signed-out visitor; it does not log in, bypass privacy settings or access private groups. Public posts can still contain personal data. You are responsible for using the data lawfully: follow GDPR, CCPA and other privacy laws, respect Facebook's terms where they apply to you, collect only what you need, and do not use the data for spam or harassment. If you are unsure, ask a lawyer. This Actor is not affiliated with or endorsed by Meta or Facebook.

When a run or a query fails, the Actor sends sanitized diagnostic data (the exception, your input with secret fields and URL query strings removed, and the Actor, build and run IDs) to our private GlitchTip error-tracking service so we can repair it. Reports are retained for 30 days.

### FAQ

**Do I need a Facebook account or cookies?**
No. The Actor uses Facebook's public post search as a signed-out visitor.

**Why do some posts not contain my keyword?**
Facebook's search also returns related posts, for example posts whose author or attached content matches. Every row has `matchesQuery`; turn on `mustContainQuery` to keep only posts that contain every query word. Words are matched as parts of text, not as whole words, so `car` also matches `Scarcity`; use a longer or more specific word when that matters.

**Why did I get fewer posts than I asked for?**
Facebook served no more result pages for that query, or your filters removed the rest. The status message shows the stop reason for every query. Try `top` instead of `recent`, a wider date window or broader keywords.

**A query failed. What can I do?**
Facebook sometimes refuses a request; the Actor retries with fresh sessions. If Facebook keeps rate-limiting your proxy setting, the run switches to the default `SHADER` proxy, and the status message says so. Your own proxy URLs are never replaced, so if they are rate-limited, use the default proxy instead. If a query still fails, run it again later. If it keeps failing, open an issue on the Actor page with the run link.

**Can I get the comments of each post?**
This Actor returns comment counts. Pass the post URLs to a Facebook comments scraper for the comment texts.

**Can I search posts of one Page or group only?**
Use [Facebook Pages Posts Scraper](https://apify.com/automation-lab/facebook-pages-posts-scraper) or [Facebook Group Posts Scraper](https://apify.com/automation-lab/facebook-group-posts-scraper) for that.

### Related Actors

- [Facebook Pages Posts Scraper](https://apify.com/automation-lab/facebook-pages-posts-scraper) - all posts of specific Facebook Pages.
- [Facebook Group Posts Scraper](https://apify.com/automation-lab/facebook-group-posts-scraper) - posts of specific public groups.
- [Facebook Pages Scraper](https://apify.com/automation-lab/facebook-pages-scraper) - Page details such as category, followers and contact info for the authors you find.
- [Facebook People Search Scraper](https://apify.com/automation-lab/facebook-people-search-scraper) - search public Facebook profiles by name.
- [Facebook Public Video Search Results](https://apify.com/automation-lab/facebook-public-video-search-results) - search public Facebook videos and reels by keyword.
- [Facebook Ads Library Scraper](https://apify.com/automation-lab/facebook-ads-library) - ads a brand runs on Facebook and Instagram.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/facebook-public-post-keyword-search-scraper/changelog.md

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords, phrases or hashtags to search Facebook posts for, one per line (for example `coffee`, `#blackfriday`, `iphone 17 battery`). Each query is searched separately with Facebook's own post search. A pasted facebook.com/search/posts/?q=... URL also works. Facebook matches loosely: single words match most precisely; use `mustContainQuery` to keep only posts that contain every word.

## `sortBy` (type: `string`):

`top` uses Facebook's relevance ranking (popular posts of any age). `recent` turns on Facebook's Recent posts filter, which favours fresh posts and suits monitoring. Rows keep Facebook's own order, which is not strictly by date.

## `maxPostsPerQuery` (type: `integer`):

Maximum number of posts saved for each search query, after filters. Facebook serves about 10-12 posts per page and usually up to a few hundred posts per query; the run stops earlier when Facebook has no more pages.

## `maxItems` (type: `integer`):

Hard cap on posts saved across all queries in this run. `0` means no run-wide cap (each query still stops at Max posts per query).

## `startDate` (type: `string`):

Keep only posts published on or after this UTC date. Use `YYYY-MM-DD` or a relative window such as `7 days`, `3 weeks` or `2 months`. The date is sent to Facebook's date filter and also checked on every post, so posts outside the window are never saved or charged.

## `endDate` (type: `string`):

Keep only posts published on or before this UTC date (whole day included). Same formats as the start date.

## `mustContainQuery` (type: `boolean`):

When on, a post is kept only if every word of the query (case- and accent-insensitive; `#` ignored) appears in its text, its shared post text or its link title. Words are matched as parts of text (`car` also matches `Scarcity`), not as whole words or an exact phrase. Every row has `matchesQuery` either way.

## `postSource` (type: `string`):

`groups` keeps only posts made in public groups; `pages_and_profiles` keeps only posts on Pages and profiles. Applied to each result after Facebook returns it.

## `postType` (type: `string`):

Keep only one kind of post: `photo` (one photo), `album` (several photos/videos), `video`, `link` (outbound link), `share` (reshare of another post) or `text`. Applied after Facebook returns each result.

## `minReactions` (type: `integer`):

Keep only posts with at least this many reactions. `0` keeps everything.

## `proxyConfiguration` (type: `object`):

Apify datacenter proxies (SHADER group) serve every request by default and are the tested setting. Change only if you know you need a different proxy. If Facebook keeps rate-limiting another Apify Proxy setting or no proxy, the run switches to SHADER. Your own proxy URLs are never replaced.

## Actor input object example

```json
{
  "searchQueries": [
    "coffee"
  ],
  "sortBy": "top",
  "maxPostsPerQuery": 20,
  "maxItems": 0,
  "mustContainQuery": false,
  "postSource": "all",
  "postType": "all",
  "minReactions": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "SHADER"
    ]
  }
}
```

# Actor output Schema

## `posts` (type: `string`):

All saved posts with text, author, date, engagement and media (Posts view).

## `engagement` (type: `string`):

The same posts with reactions by type, comments, shares and video views (Engagement view).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "coffee"
    ],
    "maxPostsPerQuery": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "SHADER"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/facebook-public-post-keyword-search-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["coffee"],
    "maxPostsPerQuery": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["SHADER"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/facebook-public-post-keyword-search-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "coffee"
  ],
  "maxPostsPerQuery": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "SHADER"
    ]
  }
}' |
apify call automation-lab/facebook-public-post-keyword-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/facebook-public-post-keyword-search-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/q2Ycgypun8FuRxrve/builds/M92cAcCiHvngFHE9d/openapi.json
