{
  "data": {
    "id": "mOLyljzUlnPCEScHZ",
    "actId": "kHf019KL2WuzR6BFE",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-10-22T17:53:59.889Z",
    "finishedAt": "2026-10-22T17:54:13.508Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 13454,
      "runTimeSecs": 13.454,
      "computeUnits": 0.014948888888888888,
      "imageSizeBytes": 354888192
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"Facebook Business Page Review Scraper Input\",\n  \"description\": \"Scrape public Facebook business page recommendations and reviews by page URL, numeric Page ID, or username. Returns review rows plus one page-summary row per page.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"startUrls\": {\n      \"title\": \"Facebook Page URLs\",\n      \"type\": \"array\",\n      \"description\": \"Facebook business page URLs or /reviews URLs (e.g. https://www.facebook.com/mcdonalds/reviews). /reviews is added automatically when missing. Invalid or dead page URLs fail fast instead of being guessed.\",\n      \"editor\": \"requestListSources\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"url\": {\n            \"title\": \"Page URL\",\n            \"type\": \"string\",\n            \"description\": \"Facebook business Page URL or /reviews URL.\"\n          }\n        },\n        \"required\": [\n          \"url\"\n        ]\n      },\n      \"default\": [],\n      \"prefill\": [\n        {\n          \"url\": \"https://www.facebook.com/mcdonalds/reviews\"\n        }\n      ]\n    },\n    \"pageIds\": {\n      \"title\": \"Facebook Page IDs or Usernames\",\n      \"type\": \"array\",\n      \"description\": \"Numeric Facebook Page IDs (e.g. 100064458773195) or page usernames (e.g. mcdonalds). Use this when you do not have a full URL.\",\n      \"editor\": \"stringList\",\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"maxItems\": {\n      \"title\": \"Max Reviews\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum number of review rows to return across all pages (1-2000). Facebook returns roughly 2-3 reviews per request (about 2.7 on average) even when a larger count is requested, so 100 reviews needs about 35-40 requests.\",\n      \"editor\": \"number\",\n      \"minimum\": 1,\n      \"maximum\": 2000,\n      \"default\": 100,\n      \"prefill\": 5\n    },\n    \"maxPerPage\": {\n      \"title\": \"Max Reviews Per Page\",\n      \"type\": \"integer\",\n      \"description\": \"Optional cap per Facebook page for multi-page runs. Leave empty to share the global Max Reviews cap across pages.\",\n      \"editor\": \"number\",\n      \"minimum\": 1,\n      \"maximum\": 2000\n    },\n    \"includeReplies\": {\n      \"title\": \"Include Comments and Owner Replies\",\n      \"type\": \"boolean\",\n      \"description\": \"Include the visible top comments and business owner replies inside each review row. When disabled, commentCount is still returned.\",\n      \"default\": true,\n      \"prefill\": false\n    },\n    \"includePageSummary\": {\n      \"title\": \"Include Page Summary Row\",\n      \"type\": \"boolean\",\n      \"description\": \"Emit one recordType=page row per page with the recommendation percentage, total review count, followers, and talking-about count. This adds no extra requests.\",\n      \"default\": true,\n      \"prefill\": true\n    },\n    \"onlyNew\": {\n      \"title\": \"Only New Reviews (Monitor Mode)\",\n      \"type\": \"boolean\",\n      \"description\": \"Return only reviews not seen in the saved state for this page. The state is stored in a named key-value store that persists across runs, so scheduled runs can monitor for new reviews.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"stateKey\": {\n      \"title\": \"Monitor State Key\",\n      \"type\": \"string\",\n      \"description\": \"Optional prefix for the key-value store key used by monitor mode. Each page's state is stored separately. Leave empty to use the page ID.\",\n      \"editor\": \"textfield\"\n    },\n    \"recommendation\": {\n      \"title\": \"Recommendation Filter\",\n      \"type\": \"string\",\n      \"description\": \"Only return reviews with the selected recommendation status. Facebook uses binary Recommended / Not Recommended, not star ratings.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"all\",\n        \"recommended\",\n        \"not\"\n      ],\n      \"enumTitles\": [\n        \"All Reviews\",\n        \"Recommended Only\",\n        \"Not Recommended Only\"\n      ],\n      \"default\": \"all\",\n      \"prefill\": \"all\"\n    },\n    \"dateFrom\": {\n      \"title\": \"Date From (YYYY-MM-DD)\",\n      \"type\": \"string\",\n      \"description\": \"Only return reviews posted on or after this date. Reviews are newest-first, so collection stops when it passes this date.\",\n      \"editor\": \"textfield\"\n    },\n    \"dateTo\": {\n      \"title\": \"Date To (YYYY-MM-DD)\",\n      \"type\": \"string\",\n      \"description\": \"Only return reviews posted on or before this date.\",\n      \"editor\": \"textfield\"\n    },\n    \"keyword\": {\n      \"title\": \"Keyword Filter\",\n      \"type\": \"string\",\n      \"description\": \"Only return reviews whose text contains this word or phrase (case-insensitive).\",\n      \"editor\": \"textfield\"\n    },\n    \"requestDelayMs\": {\n      \"title\": \"Delay Between Requests (ms)\",\n      \"type\": \"integer\",\n      \"description\": \"Pause between review requests. 500-800 ms is a polite pace and keeps long runs stable.\",\n      \"editor\": \"number\",\n      \"minimum\": 0,\n      \"maximum\": 5000,\n      \"default\": 600,\n      \"prefill\": 600\n    },\n    \"maxRuntimeSecs\": {\n      \"title\": \"Run Time Budget (seconds)\",\n      \"type\": \"integer\",\n      \"description\": \"Stop collecting after this many seconds and return what has been collected so far.\",\n      \"editor\": \"number\",\n      \"minimum\": 30,\n      \"maximum\": 7200,\n      \"default\": 1800,\n      \"prefill\": 1800\n    },\n    \"failOnEmpty\": {\n      \"title\": \"Fail When Nothing Is Found\",\n      \"type\": \"boolean\",\n      \"description\": \"Mark the run as failed when no review rows are returned. Monitor-mode runs that legitimately have no new reviews never fail.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy Configuration\",\n      \"type\": \"object\",\n      \"description\": \"Optional. Leave empty to let the actor choose automatically: it tries a direct connection first and only escalates through Apify Proxy if Facebook blocks the request. Change this only if you need a specific proxy setup.\",\n      \"editor\": \"proxy\"\n    },\n    \"cookies\": {\n      \"title\": \"Optional Facebook Cookies\",\n      \"type\": \"array\",\n      \"description\": \"Optional Facebook cookies exported from a logged-in browser. They are not required and do not increase how many reviews Facebook serves per request; the actor returns real reviews without them.\",\n      \"editor\": \"json\",\n      \"default\": []\n    }\n  }\n}",
    "readme": "# Facebook Business Page Recommendation & Review Scraper\r\n\r\nExtract **Facebook business page recommendations and reviews** from public pages without logging in. Paste a page URL, a numeric Page ID, or a username, and get review text, Recommended / Not Recommended status, author details, reactions, recommendation tags, comments and owner replies — plus a page-summary row with the recommendation percentage, review count, follower count and talking-about count. Reviews are collected newest-first, deduplicated by review ID, and can be filtered by date, keyword, or recommendation status.\r\n\r\n## What this actor does\r\n\r\n- **Two input styles:** full Facebook page or `/reviews` URLs, and numeric Page IDs or page usernames\r\n- **Deep review history:** returns up to 2,000 reviews per run; Facebook serves roughly 2–3 reviews per request, so depth comes from pagination rather than a login session\r\n- **Rich review fields:** recommendation status, full text, author name/profile/photo, reaction counts and breakdowns, recommendation tags, share and comment counts, top comments, and business owner replies\r\n- **Page-summary row:** one `recordType: page` record per page with recommend %, total review count, followers, and talking-about count\r\n- **Filters and monitor mode:** date range, keyword, Recommended / Not Recommended, and an incremental mode that returns only reviews newer than the saved state\r\n- **Empty fields are omitted:** missing values are left out instead of being returned as `null`\r\n\r\n## Output per review\r\n\r\n- `reviewId` — stable Facebook review ID\r\n- `pageId`, `pageName`, `pageUrl` — the page the review belongs to\r\n- `text` — full review text\r\n- `isRecommended` — `true` for Recommended, `false` for Not Recommended\r\n- `createdAt` — ISO-8601 UTC timestamp\r\n- `timestamp` — Unix timestamp in seconds\r\n- `authorName`, `authorProfileUrl`, `authorProfileImageUrl`, `authorIdType` — author identity; `authorIdType` is `pfbid` or `numeric`\r\n- `reactionCount`, `reactionBreakdown` — total reactions and per-type counts (Like, Love, Wow, Haha, Sad, Angry, Care)\r\n- `shareCount`, `commentCount`\r\n- `reviewTags` — structured tags such as `Disappointing food` or `Fast delivery`\r\n- `topComments` — visible comments (with attached `photos` when present), including `isOwnerReply` on business replies\r\n- `ownerReplies` — the subset of comments written by the business itself\r\n- `reviewUrl` — permalink to the review post\r\n- `reviewPhotos` — present only when Facebook exposes review media (currently rare on this surface)\r\n- `page` — page metadata object retained for compatibility\r\n- `recordType: \"review\"`, `scrapedAt`\r\n\r\n## Output per page\r\n\r\nOne row per page with `recordType: \"page\"`:\r\n\r\n- `pageId`, `pageName`, `pageUrl`\r\n- `recommendPercent` — Facebook's own recommendation percentage (not recalculated from returned reviews)\r\n- `reviewCount` — total reviews shown by Facebook for the page\r\n- `followerCount`\r\n- `talkingAboutCount`\r\n- `scrapedAt`\r\n\r\n## Error rows\r\n\r\nUnavailable pages produce a row with `recordType: \"error\"`, an `errorType`, a readable `error`, the page identity when known, and `scrapedAt`. Error types include `INVALID_INPUT`, `PAGE_UNAVAILABLE`, `PAGE_NOT_FOUND`, `BLOCKED`, `DOC_ID_UNAVAILABLE`, `REQUEST_FAILED`, `NO_REVIEWS`, `TIME_BUDGET_EXCEEDED`, and `SCRAPE_ERROR`.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `startUrls` | array | `[]` | Facebook page URLs or `/reviews` URLs. `/reviews` is added automatically when missing |\r\n| `pageIds` | array | `[]` | Numeric Page IDs or page usernames |\r\n| `maxItems` | integer | `100` | Maximum review rows across all pages (1–2000) |\r\n| `maxPerPage` | integer | – | Optional per-page cap for multi-page runs (1–2000) |\r\n| `includeReplies` | boolean | `true` | Include top comments and owner replies |\r\n| `includePageSummary` | boolean | `true` | Emit one page-summary row per page |\r\n| `onlyNew` | boolean | `false` | Monitor mode: return only reviews not in the saved state |\r\n| `stateKey` | string | – | Optional prefix for the monitor state key |\r\n| `recommendation` | string | `all` | `all` / `recommended` / `not` |\r\n| `dateFrom` | string | – | Only reviews on or after this date (`YYYY-MM-DD`) |\r\n| `dateTo` | string | – | Only reviews on or before this date (`YYYY-MM-DD`) |\r\n| `keyword` | string | – | Only reviews containing this word or phrase (case-insensitive) |\r\n| `requestDelayMs` | integer | `600` | Pause between requests in milliseconds (0–5000) |\r\n| `maxRuntimeSecs` | integer | `1800` | Stop collecting after this many seconds |\r\n| `failOnEmpty` | boolean | `false` | Fail the run when no review rows are returned |\r\n| `proxyConfiguration` | object | automatic | Optional connection override; leave empty and the actor picks a working connection, escalating only when Facebook blocks a request |\r\n| `cookies` | array | `[]` | Optional Facebook cookies; not required and not needed for depth |\r\n\r\nLegacy keys from earlier versions (`maxReviews`, `maxReviewsPerPage`, `filterByRecommendation`, `filterByDateFrom`, `filterByDateTo`, `filterByKeyword`) are still accepted and mapped internally. Business-name-plus-city search has been removed because it resolved to guessed, often dead page URLs.\r\n\r\n### Example: scrape one page\r\n\r\n```json\r\n{\r\n  \"startUrls\": [{ \"url\": \"https://www.facebook.com/mcdonalds/reviews\" }],\r\n  \"maxItems\": 200\r\n}\r\n```\r\n\r\n### Example: multiple pages by Page ID or username\r\n\r\n```json\r\n{\r\n  \"pageIds\": [\"100064458773195\", \"portosbakery\"],\r\n  \"maxItems\": 500,\r\n  \"maxPerPage\": 50,\r\n  \"includeReplies\": true\r\n}\r\n```\r\n\r\n### Example: only negative reviews from a date range\r\n\r\n```json\r\n{\r\n  \"startUrls\": [{ \"url\": \"https://www.facebook.com/IHOP/reviews\" }],\r\n  \"recommendation\": \"not\",\r\n  \"dateFrom\": \"2026-06-01\",\r\n  \"maxItems\": 100\r\n}\r\n```\r\n\r\n### Example: daily monitor for new reviews\r\n\r\n```json\r\n{\r\n  \"pageIds\": [\"100064458773195\"],\r\n  \"onlyNew\": true,\r\n  \"stateKey\": \"mcdonalds-monitor\",\r\n  \"maxItems\": 200\r\n}\r\n```\r\n\r\n## Use cases\r\n\r\n- **Reputation monitoring** — track new Recommended / Not Recommended reviews and owner replies for a brand or franchise location\r\n- **Competitor analysis** — compare recommendation percentages, review volume, and recurring complaint keywords across competing businesses\r\n- **Local business research** — pull reviews for restaurants, hotels, or service providers before choosing where to eat, stay, or book\r\n- **Customer feedback analysis** — export review text and recommendation tags for sentiment or NLP pipelines\r\n- **Franchise tracking** — scrape many location-specific Page IDs in one run and compare performance\r\n- **Market research** — measure follower and talking-about counts alongside review trends\r\n\r\n## FAQ\r\n\r\n**Does this require a Facebook account or cookies?**\r\nNo. The actor reads publicly visible reviews from public business pages without logging in. Cookies are optional. They do not increase review depth: Facebook serves the same 2–3 reviews per request either way.\r\n\r\n**How many reviews can I get?**\r\nUp to 2,000 per run. Facebook returns about 2–3 reviews per request even when asked for more, so 100 reviews typically needs around 35–40 requests. Earlier versions of this actor described a 10–15-review limit; that was a browser-UI ceiling, not a server-side cap, and no longer applies to this collection path.\r\n\r\n**Why is there no star rating?**\r\nFacebook business pages use binary Recommended / Not Recommended, so there is no per-review star rating. `isRecommended` tells you which one the reviewer chose.\r\n\r\n**Does `recommendPercent` match the reviews I received?**\r\nNo. It is Facebook's own page-level figure and is not recalculated from the returned sample, which may be a small slice of the page's full review history.\r\n\r\n**Can I get the business's replies?**\r\nYes. Visible comments appear in `topComments`, and `ownerReplies` contains only the comments written by the page itself. Both are omitted when `includeReplies` is off, while `commentCount` remains.\r\n\r\n**Can I get review photos, a language filter, or a rating distribution?**\r\nNot from this surface today. Review photos are effectively absent on current Facebook review pages, review text has no language metadata, and no rating distribution is exposed — only the recommendation percentage and total review count. The actor does not fabricate those fields.\r\n\r\n**Do I need to configure a proxy?**\r\nNo. The actor works without a proxy and selects a working connection automatically. The `proxyConfiguration` field is only for users who need a specific setup.\r\n\r\n**How does monitor mode know what is new?**\r\nIt stores the review IDs it has seen in a named key-value store that persists across runs, one key per page. Scheduled runs with `onlyNew` return only reviews that were not in that saved set. Use `stateKey` if you want separate monitor streams for the same page.\r\n\r\n**What happens for a dead or private page?**\r\nThe actor validates the page before collecting and writes a single `recordType: \"error\"` row. It does not guess a page URL from a business name, and it does not retry a dead page repeatedly.\r\n\r\n## Limitations\r\n\r\n- **2,000-review cap per run** — a deliberate ceiling that keeps one run bounded\r\n- **Public business pages only** — private pages, personal profiles, groups, and Marketplace listings are not supported\r\n- **No rating distribution or language filter** — Facebook does not expose either on the reviews surface\r\n- **Review photos are rare** — the field is kept for compatibility but is usually absent\r\n- **Reviewer identity is not always stable** — `authorIdType` reports whether the author ID is a stable numeric ID or a rotating `pfbid` token\r\n- **Facebook can change its internal review operation** — the actor detects a rotated operation identifier and refreshes it, but a major upstream change can still require an actor update\r\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "facebook-business-page-recommendation-and-review",
      "title": "Facebook Business Page Recommendation & Review Scraper",
      "description": "Extract public Facebook business page recommendations and reviews by page URL, Page ID, or username. Returns review text, recommendation status, author details, reactions, tags, comments, owner replies, and a page-summary row without login or cookies.",
      "version": "2.0",
      "buildTag": "latest",
      "dockerfile": "./Dockerfile",
      "readme": "# Facebook Business Page Recommendation & Review Scraper\r\n\r\nExtract **Facebook business page recommendations and reviews** from public pages without logging in. Paste a page URL, a numeric Page ID, or a username, and get review text, Recommended / Not Recommended status, author details, reactions, recommendation tags, comments and owner replies — plus a page-summary row with the recommendation percentage, review count, follower count and talking-about count. Reviews are collected newest-first, deduplicated by review ID, and can be filtered by date, keyword, or recommendation status.\r\n\r\n## What this actor does\r\n\r\n- **Two input styles:** full Facebook page or `/reviews` URLs, and numeric Page IDs or page usernames\r\n- **Deep review history:** returns up to 2,000 reviews per run; Facebook serves roughly 2–3 reviews per request, so depth comes from pagination rather than a login session\r\n- **Rich review fields:** recommendation status, full text, author name/profile/photo, reaction counts and breakdowns, recommendation tags, share and comment counts, top comments, and business owner replies\r\n- **Page-summary row:** one `recordType: page` record per page with recommend %, total review count, followers, and talking-about count\r\n- **Filters and monitor mode:** date range, keyword, Recommended / Not Recommended, and an incremental mode that returns only reviews newer than the saved state\r\n- **Empty fields are omitted:** missing values are left out instead of being returned as `null`\r\n\r\n## Output per review\r\n\r\n- `reviewId` — stable Facebook review ID\r\n- `pageId`, `pageName`, `pageUrl` — the page the review belongs to\r\n- `text` — full review text\r\n- `isRecommended` — `true` for Recommended, `false` for Not Recommended\r\n- `createdAt` — ISO-8601 UTC timestamp\r\n- `timestamp` — Unix timestamp in seconds\r\n- `authorName`, `authorProfileUrl`, `authorProfileImageUrl`, `authorIdType` — author identity; `authorIdType` is `pfbid` or `numeric`\r\n- `reactionCount`, `reactionBreakdown` — total reactions and per-type counts (Like, Love, Wow, Haha, Sad, Angry, Care)\r\n- `shareCount`, `commentCount`\r\n- `reviewTags` — structured tags such as `Disappointing food` or `Fast delivery`\r\n- `topComments` — visible comments (with attached `photos` when present), including `isOwnerReply` on business replies\r\n- `ownerReplies` — the subset of comments written by the business itself\r\n- `reviewUrl` — permalink to the review post\r\n- `reviewPhotos` — present only when Facebook exposes review media (currently rare on this surface)\r\n- `page` — page metadata object retained for compatibility\r\n- `recordType: \"review\"`, `scrapedAt`\r\n\r\n## Output per page\r\n\r\nOne row per page with `recordType: \"page\"`:\r\n\r\n- `pageId`, `pageName`, `pageUrl`\r\n- `recommendPercent` — Facebook's own recommendation percentage (not recalculated from returned reviews)\r\n- `reviewCount` — total reviews shown by Facebook for the page\r\n- `followerCount`\r\n- `talkingAboutCount`\r\n- `scrapedAt`\r\n\r\n## Error rows\r\n\r\nUnavailable pages produce a row with `recordType: \"error\"`, an `errorType`, a readable `error`, the page identity when known, and `scrapedAt`. Error types include `INVALID_INPUT`, `PAGE_UNAVAILABLE`, `PAGE_NOT_FOUND`, `BLOCKED`, `DOC_ID_UNAVAILABLE`, `REQUEST_FAILED`, `NO_REVIEWS`, `TIME_BUDGET_EXCEEDED`, and `SCRAPE_ERROR`.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `startUrls` | array | `[]` | Facebook page URLs or `/reviews` URLs. `/reviews` is added automatically when missing |\r\n| `pageIds` | array | `[]` | Numeric Page IDs or page usernames |\r\n| `maxItems` | integer | `100` | Maximum review rows across all pages (1–2000) |\r\n| `maxPerPage` | integer | – | Optional per-page cap for multi-page runs (1–2000) |\r\n| `includeReplies` | boolean | `true` | Include top comments and owner replies |\r\n| `includePageSummary` | boolean | `true` | Emit one page-summary row per page |\r\n| `onlyNew` | boolean | `false` | Monitor mode: return only reviews not in the saved state |\r\n| `stateKey` | string | – | Optional prefix for the monitor state key |\r\n| `recommendation` | string | `all` | `all` / `recommended` / `not` |\r\n| `dateFrom` | string | – | Only reviews on or after this date (`YYYY-MM-DD`) |\r\n| `dateTo` | string | – | Only reviews on or before this date (`YYYY-MM-DD`) |\r\n| `keyword` | string | – | Only reviews containing this word or phrase (case-insensitive) |\r\n| `requestDelayMs` | integer | `600` | Pause between requests in milliseconds (0–5000) |\r\n| `maxRuntimeSecs` | integer | `1800` | Stop collecting after this many seconds |\r\n| `failOnEmpty` | boolean | `false` | Fail the run when no review rows are returned |\r\n| `proxyConfiguration` | object | automatic | Optional connection override; leave empty and the actor picks a working connection, escalating only when Facebook blocks a request |\r\n| `cookies` | array | `[]` | Optional Facebook cookies; not required and not needed for depth |\r\n\r\nLegacy keys from earlier versions (`maxReviews`, `maxReviewsPerPage`, `filterByRecommendation`, `filterByDateFrom`, `filterByDateTo`, `filterByKeyword`) are still accepted and mapped internally. Business-name-plus-city search has been removed because it resolved to guessed, often dead page URLs.\r\n\r\n### Example: scrape one page\r\n\r\n```json\r\n{\r\n  \"startUrls\": [{ \"url\": \"https://www.facebook.com/mcdonalds/reviews\" }],\r\n  \"maxItems\": 200\r\n}\r\n```\r\n\r\n### Example: multiple pages by Page ID or username\r\n\r\n```json\r\n{\r\n  \"pageIds\": [\"100064458773195\", \"portosbakery\"],\r\n  \"maxItems\": 500,\r\n  \"maxPerPage\": 50,\r\n  \"includeReplies\": true\r\n}\r\n```\r\n\r\n### Example: only negative reviews from a date range\r\n\r\n```json\r\n{\r\n  \"startUrls\": [{ \"url\": \"https://www.facebook.com/IHOP/reviews\" }],\r\n  \"recommendation\": \"not\",\r\n  \"dateFrom\": \"2026-06-01\",\r\n  \"maxItems\": 100\r\n}\r\n```\r\n\r\n### Example: daily monitor for new reviews\r\n\r\n```json\r\n{\r\n  \"pageIds\": [\"100064458773195\"],\r\n  \"onlyNew\": true,\r\n  \"stateKey\": \"mcdonalds-monitor\",\r\n  \"maxItems\": 200\r\n}\r\n```\r\n\r\n## Use cases\r\n\r\n- **Reputation monitoring** — track new Recommended / Not Recommended reviews and owner replies for a brand or franchise location\r\n- **Competitor analysis** — compare recommendation percentages, review volume, and recurring complaint keywords across competing businesses\r\n- **Local business research** — pull reviews for restaurants, hotels, or service providers before choosing where to eat, stay, or book\r\n- **Customer feedback analysis** — export review text and recommendation tags for sentiment or NLP pipelines\r\n- **Franchise tracking** — scrape many location-specific Page IDs in one run and compare performance\r\n- **Market research** — measure follower and talking-about counts alongside review trends\r\n\r\n## FAQ\r\n\r\n**Does this require a Facebook account or cookies?**\r\nNo. The actor reads publicly visible reviews from public business pages without logging in. Cookies are optional. They do not increase review depth: Facebook serves the same 2–3 reviews per request either way.\r\n\r\n**How many reviews can I get?**\r\nUp to 2,000 per run. Facebook returns about 2–3 reviews per request even when asked for more, so 100 reviews typically needs around 35–40 requests. Earlier versions of this actor described a 10–15-review limit; that was a browser-UI ceiling, not a server-side cap, and no longer applies to this collection path.\r\n\r\n**Why is there no star rating?**\r\nFacebook business pages use binary Recommended / Not Recommended, so there is no per-review star rating. `isRecommended` tells you which one the reviewer chose.\r\n\r\n**Does `recommendPercent` match the reviews I received?**\r\nNo. It is Facebook's own page-level figure and is not recalculated from the returned sample, which may be a small slice of the page's full review history.\r\n\r\n**Can I get the business's replies?**\r\nYes. Visible comments appear in `topComments`, and `ownerReplies` contains only the comments written by the page itself. Both are omitted when `includeReplies` is off, while `commentCount` remains.\r\n\r\n**Can I get review photos, a language filter, or a rating distribution?**\r\nNot from this surface today. Review photos are effectively absent on current Facebook review pages, review text has no language metadata, and no rating distribution is exposed — only the recommendation percentage and total review count. The actor does not fabricate those fields.\r\n\r\n**Do I need to configure a proxy?**\r\nNo. The actor works without a proxy and selects a working connection automatically. The `proxyConfiguration` field is only for users who need a specific setup.\r\n\r\n**How does monitor mode know what is new?**\r\nIt stores the review IDs it has seen in a named key-value store that persists across runs, one key per page. Scheduled runs with `onlyNew` return only reviews that were not in that saved set. Use `stateKey` if you want separate monitor streams for the same page.\r\n\r\n**What happens for a dead or private page?**\r\nThe actor validates the page before collecting and writes a single `recordType: \"error\"` row. It does not guess a page URL from a business name, and it does not retry a dead page repeatedly.\r\n\r\n## Limitations\r\n\r\n- **2,000-review cap per run** — a deliberate ceiling that keeps one run bounded\r\n- **Public business pages only** — private pages, personal profiles, groups, and Marketplace listings are not supported\r\n- **No rating distribution or language filter** — Facebook does not expose either on the reviews surface\r\n- **Review photos are rare** — the field is kept for compatibility but is usually absent\r\n- **Reviewer identity is not always stable** — `authorIdType` reports whether the author ID is a stable numeric ID or a rotating `pfbid` token\r\n- **Facebook can change its internal review operation** — the actor detects a rotated operation identifier and refreshes it, but a major upstream change can still require an actor update\r\n",
      "input": {
        "title": "Facebook Business Page Review Scraper Input",
        "description": "Scrape public Facebook business page recommendations and reviews by page URL, numeric Page ID, or username. Returns review rows plus one page-summary row per page.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "startUrls": {
            "title": "Facebook Page URLs",
            "type": "array",
            "description": "Facebook business page URLs or /reviews URLs (e.g. https://www.facebook.com/mcdonalds/reviews). /reviews is added automatically when missing. Invalid or dead page URLs fail fast instead of being guessed.",
            "editor": "requestListSources",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "title": "Page URL",
                  "type": "string",
                  "description": "Facebook business Page URL or /reviews URL."
                }
              },
              "required": [
                "url"
              ]
            },
            "default": [],
            "prefill": [
              {
                "url": "https://www.facebook.com/mcdonalds/reviews"
              }
            ]
          },
          "pageIds": {
            "title": "Facebook Page IDs or Usernames",
            "type": "array",
            "description": "Numeric Facebook Page IDs (e.g. 100064458773195) or page usernames (e.g. mcdonalds). Use this when you do not have a full URL.",
            "editor": "stringList",
            "default": [],
            "prefill": []
          },
          "maxItems": {
            "title": "Max Reviews",
            "type": "integer",
            "description": "Maximum number of review rows to return across all pages (1-2000). Facebook returns roughly 2-3 reviews per request (about 2.7 on average) even when a larger count is requested, so 100 reviews needs about 35-40 requests.",
            "editor": "number",
            "minimum": 1,
            "maximum": 2000,
            "default": 100,
            "prefill": 5
          },
          "maxPerPage": {
            "title": "Max Reviews Per Page",
            "type": "integer",
            "description": "Optional cap per Facebook page for multi-page runs. Leave empty to share the global Max Reviews cap across pages.",
            "editor": "number",
            "minimum": 1,
            "maximum": 2000
          },
          "includeReplies": {
            "title": "Include Comments and Owner Replies",
            "type": "boolean",
            "description": "Include the visible top comments and business owner replies inside each review row. When disabled, commentCount is still returned.",
            "default": true,
            "prefill": false
          },
          "includePageSummary": {
            "title": "Include Page Summary Row",
            "type": "boolean",
            "description": "Emit one recordType=page row per page with the recommendation percentage, total review count, followers, and talking-about count. This adds no extra requests.",
            "default": true,
            "prefill": true
          },
          "onlyNew": {
            "title": "Only New Reviews (Monitor Mode)",
            "type": "boolean",
            "description": "Return only reviews not seen in the saved state for this page. The state is stored in a named key-value store that persists across runs, so scheduled runs can monitor for new reviews.",
            "default": false,
            "prefill": false
          },
          "stateKey": {
            "title": "Monitor State Key",
            "type": "string",
            "description": "Optional prefix for the key-value store key used by monitor mode. Each page's state is stored separately. Leave empty to use the page ID.",
            "editor": "textfield"
          },
          "recommendation": {
            "title": "Recommendation Filter",
            "type": "string",
            "description": "Only return reviews with the selected recommendation status. Facebook uses binary Recommended / Not Recommended, not star ratings.",
            "editor": "select",
            "enum": [
              "all",
              "recommended",
              "not"
            ],
            "enumTitles": [
              "All Reviews",
              "Recommended Only",
              "Not Recommended Only"
            ],
            "default": "all",
            "prefill": "all"
          },
          "dateFrom": {
            "title": "Date From (YYYY-MM-DD)",
            "type": "string",
            "description": "Only return reviews posted on or after this date. Reviews are newest-first, so collection stops when it passes this date.",
            "editor": "textfield"
          },
          "dateTo": {
            "title": "Date To (YYYY-MM-DD)",
            "type": "string",
            "description": "Only return reviews posted on or before this date.",
            "editor": "textfield"
          },
          "keyword": {
            "title": "Keyword Filter",
            "type": "string",
            "description": "Only return reviews whose text contains this word or phrase (case-insensitive).",
            "editor": "textfield"
          },
          "requestDelayMs": {
            "title": "Delay Between Requests (ms)",
            "type": "integer",
            "description": "Pause between review requests. 500-800 ms is a polite pace and keeps long runs stable.",
            "editor": "number",
            "minimum": 0,
            "maximum": 5000,
            "default": 600,
            "prefill": 600
          },
          "maxRuntimeSecs": {
            "title": "Run Time Budget (seconds)",
            "type": "integer",
            "description": "Stop collecting after this many seconds and return what has been collected so far.",
            "editor": "number",
            "minimum": 30,
            "maximum": 7200,
            "default": 1800,
            "prefill": 1800
          },
          "failOnEmpty": {
            "title": "Fail When Nothing Is Found",
            "type": "boolean",
            "description": "Mark the run as failed when no review rows are returned. Monitor-mode runs that legitimately have no new reviews never fail.",
            "default": false,
            "prefill": false
          },
          "proxyConfiguration": {
            "title": "Proxy Configuration",
            "type": "object",
            "description": "Optional. Leave empty to let the actor choose automatically: it tries a direct connection first and only escalates through Apify Proxy if Facebook blocks the request. Change this only if you need a specific proxy setup.",
            "editor": "proxy"
          },
          "cookies": {
            "title": "Optional Facebook Cookies",
            "type": "array",
            "description": "Optional Facebook cookies exported from a logged-in browser. They are not required and do not increase how many reviews Facebook serves per request; the actor returns real reviews without them.",
            "editor": "json",
            "default": []
          }
        }
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "Facebook Business Page Recommendation & Review Scraper Output",
        "description": "Review rows with recommendation status, author details, reactions, tags, comments and owner replies, plus one page-summary row per page and error rows.",
        "properties": {
          "reviews": {
            "type": "string",
            "title": "Facebook Reviews Dataset",
            "description": "Dataset containing review rows, page-summary rows (recordType=page), and error rows (recordType=error).",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "defaultRunOptions": {
        "build": "latest",
        "timeoutSecs": 3600,
        "memoryMbytes": 1024
      },
      "categories": [
        "SOCIAL_MEDIA"
      ],
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "title": "Facebook Reviews Data",
          "views": {
            "overview": {
              "title": "Reviews Overview",
              "transformation": {
                "fields": [
                  "recordType",
                  "pageName",
                  "authorName",
                  "isRecommended",
                  "text",
                  "createdAt",
                  "reactionCount",
                  "commentCount",
                  "reviewUrl"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "recordType": {
                    "label": "Record Type",
                    "format": "text"
                  },
                  "pageName": {
                    "label": "Page",
                    "format": "text"
                  },
                  "authorName": {
                    "label": "Author",
                    "format": "text"
                  },
                  "isRecommended": {
                    "label": "Recommended",
                    "format": "boolean"
                  },
                  "text": {
                    "label": "Review Text",
                    "format": "text"
                  },
                  "createdAt": {
                    "label": "Date",
                    "format": "text"
                  },
                  "reactionCount": {
                    "label": "Reactions",
                    "format": "number"
                  },
                  "commentCount": {
                    "label": "Comments",
                    "format": "number"
                  },
                  "reviewUrl": {
                    "label": "URL",
                    "format": "link"
                  }
                }
              }
            },
            "detailed": {
              "title": "Full Record Details",
              "transformation": {
                "fields": [
                  "recordType",
                  "reviewId",
                  "pageId",
                  "pageName",
                  "pageUrl",
                  "authorName",
                  "authorProfileUrl",
                  "authorProfileImageUrl",
                  "authorIdType",
                  "isRecommended",
                  "text",
                  "reviewTags",
                  "createdAt",
                  "timestamp",
                  "reactionCount",
                  "reactionBreakdown",
                  "shareCount",
                  "commentCount",
                  "topComments",
                  "ownerReplies",
                  "reviewPhotos",
                  "reviewUrl",
                  "recommendPercent",
                  "reviewCount",
                  "followerCount",
                  "talkingAboutCount",
                  "page",
                  "errorType",
                  "error",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "recordType": {
                    "label": "Record Type",
                    "format": "text"
                  },
                  "reviewId": {
                    "label": "Review ID",
                    "format": "text"
                  },
                  "pageId": {
                    "label": "Page ID",
                    "format": "text"
                  },
                  "pageName": {
                    "label": "Page",
                    "format": "text"
                  },
                  "authorName": {
                    "label": "Author",
                    "format": "text"
                  },
                  "authorProfileUrl": {
                    "label": "Profile URL",
                    "format": "link"
                  },
                  "isRecommended": {
                    "label": "Recommended",
                    "format": "boolean"
                  },
                  "text": {
                    "label": "Review Text",
                    "format": "text"
                  },
                  "reviewTags": {
                    "label": "Recommendation Tags",
                    "format": "array"
                  },
                  "createdAt": {
                    "label": "Date",
                    "format": "text"
                  },
                  "reactionCount": {
                    "label": "Reactions",
                    "format": "number"
                  },
                  "reactionBreakdown": {
                    "label": "Reaction Breakdown",
                    "format": "array"
                  },
                  "commentCount": {
                    "label": "Comments",
                    "format": "number"
                  },
                  "topComments": {
                    "label": "Top Comments",
                    "format": "array"
                  },
                  "ownerReplies": {
                    "label": "Owner Replies",
                    "format": "array"
                  },
                  "timestamp": {
                    "label": "Timestamp (Unix)",
                    "format": "number"
                  },
                  "reviewUrl": {
                    "label": "Review URL",
                    "format": "link"
                  },
                  "recommendPercent": {
                    "label": "Recommend %",
                    "format": "number"
                  },
                  "reviewCount": {
                    "label": "Page Review Count",
                    "format": "number"
                  },
                  "followerCount": {
                    "label": "Followers",
                    "format": "number"
                  },
                  "talkingAboutCount": {
                    "label": "Talking About",
                    "format": "number"
                  },
                  "errorType": {
                    "label": "Error Type",
                    "format": "text"
                  },
                  "scrapedAt": {
                    "label": "Scraped At",
                    "format": "text"
                  }
                }
              }
            }
          }
        }
      },
      "environmentVariables": {}
    },
    "buildNumber": "2.0.1",
    "imageDigest": "bad8bc32a5c7a6f1c9125ed82c18b893ce389d0260de205a0ee9cb6194538092",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "2.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.014948888888888888
    }
  }
}