# Facebook Posts Search Scraper: Content Calendar Analysis (`api-empire/facebook-posts-search-scraper`) Actor

Scrape Facebook posts from search results with text, authors, dates, media, reactions, comments, and shares. Analyze posting frequency, content themes, engagement trends, and publishing patterns to optimize content calendars and social media strategies.

- **URL**: https://apify.com/api-empire/facebook-posts-search-scraper.md
- **Developed by:** [API Empire](https://apify.com/api-empire) (community)
- **Categories:** Social media, Developer tools, Automation
- **Stats:** 10 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Facebook Posts Scraper — Extract Posts, Page Rollups and Rankings

Facebook Posts Search Scraper: Content Calendar Analysis discovers public Facebook posts by keyword or competitor name and returns three linked outputs: matching posts, a per-page engagement rollup, and a competitor ranking table. Every response is typed, normalized JSON — no HTML, no selectors, no parsing. Point it at a topic, brand, or rival page name, and it finds matching posts, groups them by the Facebook Page that published them, and ranks any competitors you list by likes, comments, and shares.

### What is Facebook Posts Search Scraper: Content Calendar Analysis?

Facebook Posts Search Scraper: Content Calendar Analysis is an Apify Actor that finds public Facebook posts matching one or more search keywords, brand names, or competitor page names — no Facebook account or login required. It then automatically rolls up the matching posts per Facebook Page (post count, average engagement, top-performing post) and, when you list pages to compare, ranks them side by side on engagement. Optional add-ons enrich pages with follower/category data, page contact details, and post comments.

- Discover posts by keyword, brand, or competitor/page name across public Facebook
- Roll up matching posts per Facebook Page: post count, average likes/comments/shares, top post
- Rank a custom list of competitor pages side by side on engagement
- Optionally enrich pages with followers/category, page contact details, or post comments
- Export as JSON or CSV, or read results via the Apify API

### What data does Facebook Posts Search Scraper: Content Calendar Analysis collect?

The Actor returns four distinct data types from a single run: the discovered posts themselves, a per-page rollup, an optional competitor ranking, and optional child datasets for comments and contact details.

| Data Type | Key Fields | JSON Field Names |
| --- | --- | --- |
| Posts | page, engagement, caption text, media, timestamp | `pageName`, `likes`, `comments`, `shares`, `text`, `thumb`, `timestamp` |
| Page Summary (rollup) | post count, average engagement, top post, optional followers/category | `postCount`, `avgLikes`, `avgComments`, `topPostUrl`, `followersCount`, `pageCategory` |
| Comparison Ranking | rank, posts found, engagement score per competitor | `rank`, `engagementScore`, `avgLikes`, `postsFound` |
| Comments (child dataset) | comment text, author, likes, replies | `commentText`, `authorName`, `likesCount`, `repliesCount` |
| Page Contact (lead data) | email, phone, website, address | `contact.email`, `contact.phone`, `contact.website`, `contact.address` |

#### Need more Facebook data?

If you need a deep dive on one Page's content strategy rather than keyword discovery across many pages, **Facebook Posts Scraper: Content Strategy Insights** classifies every post's content type, hashtags, and calls-to-action for a single Page's timeline. If you need full comment threads rather than the top-level comments this Actor collects, **Facebook Comments Scraper With Author Lead Enrichment** pulls deeper comment data with commenter profile enrichment.

### How does Facebook Posts Search Scraper differ from the official Facebook API?

Meta's Graph API requires a registered Meta app, App Review, and — for most Page-content permissions — Business Verification before it returns any Page posts, and it has no endpoint for keyword search across arbitrary public pages; access is scoped to Pages and accounts your app has been explicitly granted. Facebook Posts Search Scraper instead discovers public posts directly from a keyword or page name, with no app review and no per-page permission grant.

| Feature | Facebook Graph API | Facebook Posts Search Scraper |
| --- | --- | --- |
| Access setup | Meta App Review + Business Verification | No account, no app registration |
| Keyword search across pages | Not supported — no public post-search endpoint | Core feature: search by keyword or competitor name |
| Scope of accessible posts | Pages/accounts your app is granted access to | Any public Facebook post discoverable via search |
| Page/competitor rollups | Not provided — build it yourself from raw responses | Built-in per-page rollup and competitor ranking |
| Setup time | Review process required before first call | Fill in input, run |
| Output consistency | Raw Graph API JSON, versioned per endpoint | Stable typed JSON schema, same fields every run |

The Graph API is the right choice if you manage the Pages in question and need officially permissioned access to your own Page analytics. Facebook Posts Search Scraper is the practical choice when you need to discover and compare posts from pages you don't manage, without going through an app review process.

### Why do developers and teams scrape Facebook?

#### For marketers and brand teams

Marketers use `comparePages` to list a handful of competitor page names or search queries and get back a ranked `COMPARISON-RANKING` table sorted by `engagementScore` — the fastest way to see whose posts about a topic are landing best this week. Combined with the per-page `PAGE-SUMMARY` rollup, a brand team can track its own page's `avgLikes`/`avgComments`/`avgShares` against named rivals without manually opening each competitor's Page and counting reactions by hand. Re-running the same `competitorQueries` on a schedule turns this into ongoing competitor-monitoring rather than a one-off snapshot, feeding a recurring content or campaign review.

#### For researchers and analysts

Researchers studying public discourse around a topic, event, or brand can search by keyword rather than by page, so the dataset isn't limited to accounts they already know about. Each post row carries `timestamp`, `text`, and engagement counts, giving a public, citation-ready sample of how a topic is being discussed across different Facebook Pages — useful for tracking sentiment or reach trends without accessing any private profile or gated group content. The `postRecencyWindow` filter lets a study scope its sample to a fixed recent window, and `searchQuery` on every row records which term produced each post for later cross-tabulation.

#### For AI engineers and agent builders

Agent builders can wire `competitorQueries` as a tool parameter so an LLM agent decides what to search for, then pass the returned `text`, `likes`, `comments`, and `shares` fields directly into a RAG index or a summarization prompt — no HTML cleanup step. Because output is stable typed JSON with the same keys on every run, an agent can reliably parse `PAGE-SUMMARY` records to answer questions like "which page posts about this topic gets the most engagement?" without brittle scraping logic.

#### For developers building data products

Developers building a competitor-monitoring product or a lead-gen tool can schedule this Actor on a recurring basis, pass different `competitorQueries` per customer, and store the resulting posts, page rollups, and optional `contact` records in their own database. The optional `enableContactLookup` and `maxCommentsPerPost` fields let a data product add email/phone/website leads and comment-level detail on top of the base post-and-rollup pipeline, all from the same run. Because every field name and type stays fixed between runs, downstream ingestion code can be written once and left alone as the underlying scrape logic evolves.

### How to scrape Facebook (step by step)

1. Open Facebook Posts Search Scraper: Content Calendar Analysis on its Apify Store listing and start a new run.
2. Provide `competitorQueries` — the keywords, brand names, or competitor page names to search for (none are strictly required; the Actor defaults to `football` if left empty).
3. Set filters: `maxPostsPerQuery` to cap results per query, `postRecencyWindow` to limit by recency, and `comparePages` if you want a ranked comparison table.
4. Start the run.
5. Download the post dataset as JSON or CSV, and read the `PAGE-SUMMARY` / `COMPARISON-RANKING` records from the run's Key-Value Store for the rollups.

#### What to do when Facebook changes its structure

Facebook Posts Search Scraper is actively maintained, and its output schema is kept stable — field names and types don't change on your end even when the underlying extraction logic needs updates on ours. No specific turnaround time is promised for any given fix.

### ⬇️ Input

Required per the input schema: none — every field below is optional, and the Actor runs with sensible defaults if you provide nothing.

| Parameter | Required | Type | Description | Example Value |
| --- | --- | --- | --- | --- |
| `competitorQueries` | No | array | Search keywords or competitor/page names to discover posts for. Each entry runs as a separate search. | `["nike", "adidas"]` |
| `maxPostsPerQuery` | No | integer | Posts to collect per keyword/competitor. Range 1–5000; leave empty for the default of 50. | `20` |
| `postRecencyWindow` | No | string (enum) | Recency filter: `""` (all time, default), `24h`, `7d`, `30d`, `90d`. | `"7d"` |
| `enablePageSummary` | No | boolean | Group discovered posts by page and emit one summary record per page (post count, avg engagement, top post) to Key-Value Store record `PAGE-SUMMARY`. Default: on (code default `true`). | `true` |
| `enablePageProfileEnrichment` | No | boolean | Fetch each distinct page's public profile once to add follower count and category to the page summary. Default: off. | `false` |
| `comparePages` | No | array | Page names, page URLs, or queries to rank side by side on engagement in Key-Value Store record `COMPARISON-RANKING`. Leave empty to disable. | `["nike", "adidas"]` |
| `targetCountry` | No | string (enum) | Bias the discovery search toward a country's results (SERP `gl` param). Blank = no bias (default). | `"us"` |
| `targetLanguage` | No | string (enum) | Language for the discovery search (SERP `hl` param). Blank = English (default). | `"en"` |
| `enableContactLookup` | No | boolean | Fetch each post's Facebook Page and extract public email/phone/website/address into `contact`. Missing fields are `null`, never fabricated. Default: `false`. | `false` |
| `maxCommentsPerPost` | No | integer | Top-level comments to fetch per post (0–500), saved to an uncharged `comments-<runId>` dataset. `0` (default) disables it. | `0` |
| `proxyConfiguration` | No | object | Proxy settings for Facebook requests. Default: `{ "useApifyProxy": true }`. | `{ "useApifyProxy": true }` |

**Example input:**

```json
{
  "competitorQueries": ["nike", "adidas"],
  "maxPostsPerQuery": 20,
  "postRecencyWindow": "",
  "enablePageSummary": true,
  "enablePageProfileEnrichment": false,
  "comparePages": ["nike", "adidas"],
  "targetCountry": "",
  "targetLanguage": "",
  "enableContactLookup": false,
  "maxCommentsPerPost": 0,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

The most common input mistake is listing the same names in both `competitorQueries` and `comparePages` expecting two separate result sets — the Actor de-duplicates any `comparePages` entry that already appears in `competitorQueries`, so put every page/query you want ranked into `comparePages` and leave `competitorQueries` for the ones you only want discovered.

### ⬆️ Output

Every run produces typed, normalized JSON exported as JSON or CSV from the dataset, plus two optional rollups written to the run's Key-Value Store. Only post rows in the primary dataset are charged (`row_result`); the `PAGE-SUMMARY` and `COMPARISON-RANKING` records and the child comments dataset add no extra charge.

#### Scraped Posts (primary dataset)

```json
{
  "facebookUrl": "https://www.facebook.com/nike",
  "pageId": "15087023444",
  "pageName": "Nike",
  "facebookId": "15087023444",
  "postId": "826453901928374",
  "postFacebookId": "826453901928374",
  "url": "https://www.facebook.com/nike/posts/826453901928374",
  "topLevelUrl": "https://www.facebook.com/nike/posts/826453901928374",
  "time": "2026-07-18 14:32:05",
  "timestamp": 1784385125,
  "likes": 18420,
  "comments": 612,
  "shares": 340,
  "text": "New drop. Just do it.",
  "link": "https://www.facebook.com/nike/posts/826453901928374",
  "thumb": "https://scontent.fxyz1-1.fna.fbcdn.net/v/example.jpg",
  "contact": { "email": null, "phone": null, "website": null, "address": null },
  "commentsFetched": 0,
  "scrapedAt": "2026-07-25T09:12:44.109384+00:00",
  "searchQuery": "nike",
  "isComparisonTarget": true
}
```

#### Page Summary (Key-Value Store record `PAGE-SUMMARY`)

```json
{
  "pageId": "15087023444",
  "pageName": "Nike",
  "facebookUrl": "https://www.facebook.com/nike",
  "postCount": 20,
  "avgLikes": 15230.45,
  "avgComments": 480.2,
  "avgShares": 265.8,
  "totalLikes": 304609,
  "totalComments": 9604,
  "totalShares": 5316,
  "topPostUrl": "https://www.facebook.com/nike/posts/826453901928374",
  "topPostLikes": 18420,
  "searchQueries": ["nike"],
  "followersRaw": "42M",
  "followersCount": 42000000,
  "pageCategory": "Sportswear store",
  "likesFromProfile": 41000000
}
```

#### Comparison Ranking (Key-Value Store record `COMPARISON-RANKING`)

```json
{
  "query": "nike",
  "postsFound": 20,
  "avgLikes": 15230.45,
  "avgComments": 480.2,
  "avgShares": 265.8,
  "totalLikes": 304609,
  "totalComments": 9604,
  "totalShares": 5316,
  "engagementScore": 15976.45,
  "matchedPageNames": ["Nike"],
  "rank": 1
}
```

#### Post Comments (uncharged child dataset `comments-<runId>`, when `maxCommentsPerPost` > 0)

```json
{
  "parentPostId": "826453901928374",
  "parentPostUrl": "https://www.facebook.com/nike/posts/826453901928374",
  "commentId": "Y29tbWVudDoxMjM0NTY3ODk=",
  "feedbackId": "ZmVlZGJhY2s6ODI2NDUzOTAxOTI4Mzc0",
  "commentUrl": "https://www.facebook.com/nike/posts/826453901928374?comment_id=123456789",
  "commentDate": "2026-07-18T15:02:11+00:00",
  "commentText": "Love these!",
  "authorName": "Jordan Smith",
  "authorId": "100004455667788",
  "authorProfileUrl": "https://www.facebook.com/jordan.smith",
  "authorProfilePicture": "https://scontent.fxyz1-1.fna.fbcdn.net/v/profile.jpg",
  "likesCount": 12,
  "repliesCount": 2,
  "threadingDepth": 0,
  "facebookCommentId": "123456789",
  "keyword": "nike",
  "isChild": true,
  "type": "comment",
  "scrapedAt": "2026-07-25T09:13:02.552112+00:00"
}
```

### How many results can you scrape with Facebook Posts Search Scraper?

`maxPostsPerQuery` caps results at up to 5,000 posts per search query, with a default of 50 if left blank; there is no hard cap on the number of queries you can list in `competitorQueries` or `comparePages`, so total posts scale with however many queries you run. Internally, discovery paginates Google search result pages (10 Facebook URLs per page) up to a capped number of pages per query, stopping early once the target count is reached or after three consecutive empty result pages. `maxCommentsPerPost` separately caps top-level comments fetched per post at up to 500, written to an uncharged child dataset. Facebook itself does not publish a documented limit on how many of its posts are indexable through search, so the practical ceiling for any one query is whatever the discovery search surfaces. No benchmark run time is published — actual duration depends on how many optional enrichments (comments, contact lookup, profile enrichment) are enabled alongside the post count.

### Integrate Facebook Posts Search Scraper and automate your workflow

Facebook Posts Search Scraper works with any language or tool that can send an HTTP request, since it runs as a standard Apify Actor.

#### REST API integration

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_API_TOKEN>")
run = client.actor("<owner>/facebook-posts-search-scraper-content-calendar-analysis").call(
    run_input={
        "competitorQueries": ["nike", "adidas"],
        "maxPostsPerQuery": 20,
        "comparePages": ["nike", "adidas"],
    }
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["pageName"], item["likes"], item["comments"])
```

Works in Python, Node.js, Go, Ruby, cURL.

#### MCP for AI agents

Apify's MCP server (`mcp.apify.com`) exposes Apify Actors — including this one — as callable tools for MCP-compatible clients such as Claude Desktop, Cursor, and Windsurf. Add the Actor's name (as shown on its Apify Store page) to the server's actor list to make it callable as an agent tool without writing custom integration code.

#### Automation platforms (n8n, Make, LangChain)

In **n8n**, the community Apify node's "Run Actor" operation can call Facebook Posts Search Scraper by Actor ID and pass `competitorQueries`/`maxPostsPerQuery` as JSON, then feed the resulting dataset items and `PAGE-SUMMARY` record into downstream nodes. In **Make**, the Apify app's "Run an Actor or Task" module runs the same Actor and lets you map each returned post row into another scenario step, such as a spreadsheet row or a Slack alert when a competitor's `engagementScore` changes. Any LangChain agent that can call an HTTP tool can invoke the Actor through the Apify API and consume its dataset items directly as typed JSON, without a parsing step.

### Is it legal to scrape Facebook?

Scraping publicly accessible Facebook data is generally lawful, and Facebook Posts Search Scraper only returns posts and page information visible to a logged-out visitor — no private profiles, no login-gated groups. Most output (post text, engagement counts, page name/category) is business or organizational data governed primarily by Facebook's Terms of Service rather than personal-data law. Two optional features do return personal data: `enableContactLookup` can surface a Page's public contact details, and `maxCommentsPerPost` returns commenters' names, IDs, and profile URLs — this is personal data subject to GDPR/CCPA-style requirements around a lawful basis for storage and use. Consult legal counsel for commercial use cases involving bulk personal data.

### Frequently asked questions

#### Does Facebook Posts Search Scraper work without a Facebook account?

Yes. It discovers posts through public search and fetches each post's public page HTML directly — no Facebook login or account is required.

#### Is "content calendar analysis" a real posting-cadence feature?

Not in the sense of computed posting-frequency or day/hour scheduling patterns — the Actor does not bucket posts by day of week, time of day, or posting interval. What it does compute, from the real scraped rows, is a per-page rollup (`postCount`, `avgLikes`, `avgComments`, `avgShares`, `topPostUrl`) and a competitor engagement ranking. Every post row also carries a `timestamp`, so you can build your own cadence analysis on top of the output, but that bucketing isn't done for you today.

#### How often is the scraped data updated?

Every run performs a live search and live page fetch — nothing is served from a cache. Re-run the Actor to get current engagement counts and newly published posts.

#### What happens if a post is removed or a query returns no results?

If a post becomes unavailable mid-run, the fetch is skipped and logged as a warning; other posts in the same run are unaffected. If a query returns zero discoverable Facebook URLs (for example, if the search provider blocks the request), the Actor logs a warning and returns an empty result for that query rather than failing the whole run.

#### Can I scrape private or login-gated Facebook content?

No. Only content visible to a logged-out visitor is returned — private profiles and login-gated groups are out of scope.

#### Does Facebook Posts Search Scraper work for AI agent workflows and LLM pipelines?

Yes. It's callable as an HTTP endpoint from any agent framework, and it's reachable through Apify's MCP server for MCP-compatible clients. Every response is typed JSON with stable field names — no HTML, no parsing step before passing results into an LLM context or a RAG index.

#### How does Facebook Posts Search Scraper handle Facebook's anti-bot measures?

Discovery requests route through Apify's `GOOGLE_SERP` proxy group, page fetches use Apify Proxy (datacenter/residential as configured) with browser-like request headers, and each HTML fetch retries up to three times with exponential backoff on transient errors. Comment fetches use a residential proxy session when available.

#### Does Facebook Posts Search Scraper return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with stable field names on every run — pass it directly into an LLM context window, index it into a vector store, or route it through an agent tool without a parsing step.

#### Can I use Facebook Posts Search Scraper without managing proxies?

Yes. Apify Proxy is enabled by default (`useApifyProxy: true`), and the search-discovery step always uses Apify's `GOOGLE_SERP` proxy group regardless of your `proxyConfiguration` setting.

#### What happens when Facebook changes its structure or blocks the scraper?

The Actor is actively maintained, and its output schema stays stable — field names and types don't change on your end when the underlying extraction logic is updated. No numeric turnaround time is promised for any given fix.

### Your feedback

Found a bug or missing a field? We want to know. Reach out through the Actor's Apify Store page or issue tracker so we can look into it — active maintenance is how this Actor stays reliable as Facebook's page structure evolves.

# Actor input Schema

## `competitorQueries` (type: `array`):

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💡 Enter topics or competitor names you want to explore!

Examples: football • cricket • Nike • Adidas

🎯 Each entry = a separate search → more posts discovered

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

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📈 How many posts to collect per keyword/competitor?

🎚️ Range: 1 → 5,000 posts. **Leave empty** for the default of 50.

## `postRecencyWindow` (type: `string`):

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📅 Filter by recency—get only fresh content!

⏳ **Leave empty** for all time • 24h • 7d • 30d • 90d

## `enablePageSummary` (type: `boolean`):

🪄 **Leave ON** (code default) to group every discovered post by pageId and emit one summary record per page: post count, average likes/comments/shares, and the top post URL. Adds no extra network requests. Uncheck to skip (matches base, which has no page summary).

## `enablePageProfileEnrichment` (type: `boolean`):

🔍 When ON, fetches each distinct page's public profile once to add follower count and page category to the page summary (light extra request per unique page). **Leave unchecked** for the default (off, matches base).

## `comparePages` (type: `array`):

📋 One entry per line — page names, page URLs, or search queries. Each is searched like a normal query, then ranked against the others by average engagement (likes+comments+shares) in a separate Key-Value Store output (record COMPARISON-RANKING). Leave empty to disable.

## `targetCountry` (type: `string`):

Bias the search toward a country's results (SERP `gl` param). Leave blank for no country bias (default).

## `targetLanguage` (type: `string`):

Language for the search UI/results (SERP `hl` param). Leave blank to use the default (English).

## `enableContactLookup` (type: `boolean`):

When ON, fetches each post's Facebook Page and extracts public email / phone / website / address from the page's own intro/contact card, attached as `contact` on the row. Off by default (no extra page fetches). Missing fields are `null`, never fabricated.

## `maxCommentsPerPost` (type: `integer`):

Maximum number of top-level comments to fetch per post, saved to a separate `comments-<runId>` dataset (not charged). Set to 0 (default) to disable comment fetching entirely.

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

Optional proxy settings for Facebook requests.

## Actor input object example

```json
{
  "competitorQueries": [
    "football"
  ],
  "targetCountry": "",
  "targetLanguage": "",
  "enableContactLookup": false,
  "maxCommentsPerPost": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped items in the Actor's default dataset.

## `pageSummary` (type: `string`):

Discovered posts rolled up per Facebook page — post count, average engagement, top post — as one JSON record in the key-value store (record PAGE-SUMMARY). Present when page-level summary is enabled.

## `comparisonRanking` (type: `string`):

Competitor pages/queries from comparePages ranked side by side by engagement score, as one JSON record in the key-value store (record COMPARISON-RANKING). Present only when comparePages is non-empty.

# 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 = {
    "competitorQueries": [
        "football"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("api-empire/facebook-posts-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 = {
    "competitorQueries": ["football"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("api-empire/facebook-posts-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 '{
  "competitorQueries": [
    "football"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call api-empire/facebook-posts-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,api-empire/facebook-posts-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/b6iTzu7ow5txLjI1d/builds/gYAG3KcyKw6q16vJc/openapi.json
