{
  "data": {
    "id": "wCZFF2vROhTOg2WsB",
    "actId": "MBGiwo5b4i8oo7LJo",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-10-22T17:57:44.933Z",
    "finishedAt": "2026-10-22T17:58:18.331Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 33282,
      "runTimeSecs": 33.282,
      "computeUnits": 0.03698,
      "imageSizeBytes": 3140229632
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"Facebook Business Page Finder Input\",\n  \"description\": \"Find Facebook business pages by keyword and city, or enrich page URLs and IDs with public contact details. Keyword search uses Facebook's own page search and needs a Facebook session; page enrichment runs without cookies.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"startUrls\": {\n      \"title\": \"Facebook Page URLs\",\n      \"type\": \"array\",\n      \"description\": \"Direct Facebook page URLs to enrich, for example https://www.facebook.com/ozonecoffeeuk. Can be combined with pageIds and searchTerms.\",\n      \"editor\": \"requestListSources\",\n      \"items\": {\n        \"type\": \"object\",\n        \"required\": [\n          \"url\"\n        ],\n        \"properties\": {\n          \"url\": {\n            \"type\": \"string\",\n            \"title\": \"Page URL\",\n            \"description\": \"A Facebook Page URL.\"\n          }\n        }\n      },\n      \"default\": [],\n      \"prefill\": [\n        {\n          \"url\": \"https://www.facebook.com/nike\"\n        }\n      ]\n    },\n    \"pageIds\": {\n      \"title\": \"Page IDs or Usernames\",\n      \"type\": \"array\",\n      \"description\": \"Facebook numeric Page IDs, usernames, or page URLs. Numeric IDs are fetched through https://www.facebook.com/<id>.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"searchTerms\": {\n      \"title\": \"Search Terms\",\n      \"type\": \"array\",\n      \"description\": \"Keywords for Facebook page discovery, for example Coffee Shop or Dentist. Each term is combined with each location as a text query. Facebook keyword search requires a cookie containing both c_user and xs.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"locations\": {\n      \"title\": \"Locations\",\n      \"type\": \"array\",\n      \"description\": \"City or region names added to the search query as a soft hint. Facebook does not expose a reliable city filter, so always verify the enriched address. Use strictLocation to drop rows whose address does not contain the location.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"strictLocation\": {\n      \"title\": \"Strict Location Post-Filter\",\n      \"type\": \"boolean\",\n      \"description\": \"Drop pages whose enriched address does not contain the search location. This is a best-effort post-filter, not an exact city boundary.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"categoryFilter\": {\n      \"title\": \"Category Filter\",\n      \"type\": \"array\",\n      \"description\": \"Keep pages whose enriched category contains any of these terms (case-insensitive). Filtering happens after enrichment.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"default\": [],\n      \"prefill\": []\n    },\n    \"minFollowers\": {\n      \"title\": \"Minimum Followers\",\n      \"type\": \"integer\",\n      \"description\": \"Keep pages with at least this many followers. Pages with no follower count are dropped when this is above 0.\",\n      \"default\": 0,\n      \"minimum\": 0,\n      \"maximum\": 100000000,\n      \"prefill\": 0\n    },\n    \"verifiedOnly\": {\n      \"title\": \"Verified Pages Only\",\n      \"type\": \"boolean\",\n      \"description\": \"Keep only pages whose public payload explicitly marks them as verified.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"contactFilter\": {\n      \"title\": \"Contact Filter\",\n      \"type\": \"string\",\n      \"description\": \"Keep only lead-ready pages that expose the selected contact field.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"any\",\n        \"email\",\n        \"phone\",\n        \"website\"\n      ],\n      \"enumTitles\": [\n        \"Any page\",\n        \"Has email\",\n        \"Has phone\",\n        \"Has website\"\n      ],\n      \"default\": \"any\",\n      \"prefill\": \"any\"\n    },\n    \"includeReviews\": {\n      \"title\": \"Include Reviews\",\n      \"type\": \"boolean\",\n      \"description\": \"Fetch the public reviews tab and include reviews when Facebook exposes them. Adds one request per page. Review coverage is partial.\",\n      \"default\": true,\n      \"prefill\": false\n    },\n    \"includeFailedPages\": {\n      \"title\": \"Include Failed Pages\",\n      \"type\": \"boolean\",\n      \"description\": \"Emit diagnostic rows with errorCode, detailsError, and fieldsFound for pages that cannot be enriched. This prevents silent empty runs.\",\n      \"default\": true,\n      \"prefill\": true\n    },\n    \"failOnEmpty\": {\n      \"title\": \"Fail When Empty\",\n      \"type\": \"boolean\",\n      \"description\": \"Fail the run when zero page rows are produced. Leave off to finish successfully with diagnostic rows explaining why nothing was found.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"maxItems\": {\n      \"title\": \"Maximum Pages\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum number of successful page rows. Failed rows do not consume this limit.\",\n      \"default\": 100,\n      \"minimum\": 1,\n      \"maximum\": 5000,\n      \"prefill\": 1\n    },\n    \"cookies\": {\n      \"title\": \"Facebook Session Cookies\",\n      \"type\": \"string\",\n      \"description\": \"Optional. Needed only for keyword discovery. c_user and xs are enough. Accepts a JSON array of cookie objects or a raw name=value; name2=value2 Cookie header. Page enrichment works without cookies.\",\n      \"editor\": \"textfield\",\n      \"isSecret\": true,\n      \"prefill\": \"\",\n      \"sectionCaption\": \"Discovery authentication\",\n      \"sectionDescription\": \"Cookies are used only for Facebook page search. They are never sent when enriching public page URLs.\"\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy Configuration\",\n      \"type\": \"object\",\n      \"description\": \"Used only for keyword discovery. Defaults to Apify residential proxy because Facebook search blocks datacenter IPs. Public page enrichment does not use it.\",\n      \"editor\": \"proxy\",\n      \"default\": {\n        \"useApifyProxy\": true,\n        \"apifyProxyGroups\": [\n          \"RESIDENTIAL\"\n        ]\n      },\n      \"prefill\": {\n        \"useApifyProxy\": true,\n        \"apifyProxyGroups\": [\n          \"RESIDENTIAL\"\n        ]\n      }\n    }\n  }\n}",
    "readme": "# Facebook Business Page Finder by Keyword & City\r\n\r\nFind Facebook business Pages by keyword and location, or enrich a list of Page URLs, and get back the identity, contact details, social links, follower count, recommendation percentage, open status, price range, services, Page Transparency date, ad status, images, and real review objects that Facebook exposes publicly.\r\n\r\nThe actor is built for local lead generation and page research. It discovers Pages through Facebook's own page search, then reads each Page's public root and About tabs without cookies. No Facebook login is needed to enrich URLs; a `c_user` + `xs` session cookie is required only for keyword discovery.\r\n\r\n## What this actor does\r\n\r\n- **Two ways in:** paste Facebook Page URLs, `pageIds` (numeric IDs or usernames), or run keyword + location discovery with `searchTerms` + `locations`.\r\n- **Cookie-aware discovery:** Facebook's `/search/pages/` endpoint returns results only to a logged-in session. The actor validates that the supplied cookie contains `c_user` and `xs`, replays the page's own search cursor for up to 10 results per request, and stops at `maxItems`.\r\n- **Cookieless enrichment:** Page root and About tabs are fetched with browser-compatible requests, and cookies are never sent to Page or About URLs.\r\n- **Efficient About reads:** the actor stops reading each About tab after the useful public data (about 560–650 KB) instead of downloading the full ~20 MB response.\r\n- **Lead-ready output:** identity, category, address and coordinates, phone, email, website, Messenger link, Instagram/social links, followers (raw and parsed), recommendation percentage, review count, open status, price range, services, verified flag, creation date, ad status, Ad Library link, profile/cover images, and reviews.\r\n- **Post-fetch filters:** `strictLocation`, `categoryFilter`, `minFollowers`, `verifiedOnly`, and `contactFilter`.\r\n- **Explicit failure rows:** `includeFailedPages` emits diagnostic rows with a stable `errorCode` and `detailsError` instead of silently dropping pages. `failOnEmpty` turns a zero-page run into a failed run.\r\n- **Omit-empty output:** fields Facebook does not expose for a Page are left out of that record, never emitted as `null`, `\"\"`, or `[]`.\r\n\r\n## Output per page\r\n\r\n- `pageId` — Facebook Page ID, when exposed by the public payload\r\n- `pageName`, `username`, `title` — Page identity\r\n- `facebookUrl`, `pageUrl`, `resolvedUrl` — requested canonical URL and final resolved URL\r\n- `pageType` — always `page`\r\n- `isVerified` — `true` / `false` when Facebook exposes the flag; omitted when unknown\r\n- `category` — primary Page category\r\n- `address`, `city`, `region`, `postalCode`, `country` — parsed from the public address\r\n- `latitude`, `longitude`, `addressUrl` — coordinates and a Google Maps link\r\n- `phone`, `email`, `website`, `messenger` — public contact details and `https://m.me/<pageId>`\r\n- `socialLinks` — Instagram and other linked accounts exposed on the Page\r\n- `followers`, `followersText` — parsed follower count and the raw label (`9.1K followers`)\r\n- `recommendPercentage`, `reviewCount`, `ratingText` — the real Facebook recommendation metrics; no synthetic star rating\r\n- `openStatus` — `Open now`, `Closed now`, `Always open`, `Opening soon`, and similar\r\n- `priceRange`, `services`, `about` — business details and the About text\r\n- `creationDate`, `adStatus` — Page Transparency values\r\n- `pageAdLibraryUrl` — constructed Meta Ad Library URL for the Page\r\n- `profilePictureUrl`, `coverPhotoUrl` — Page images\r\n- `reviews[]` — review objects with `reviewerName`, `recommends`, `reviewText`, `reviewDate`, plus optional `reviewId`, `authorProfileUrl`, `reactions`, `commentCount`\r\n- `searchTerm`, `searchLocation` — the discovery query that produced the row\r\n- `inputUrl` — the URL or ID supplied or discovered\r\n- `dataSource` — `facebook_search+public_page` or `facebook_public_page`\r\n- `fieldsFound` — number of populated data fields\r\n- `detailsError` — why optional detail tabs were skipped, when partial\r\n- `reviewsError` — why the optional reviews tab was empty or skipped\r\n- `scrapedAt` — ISO 8601 UTC timestamp\r\n\r\nEmpty fields are omitted at every depth. A record with no reviews has no `reviews` key; a Page with no public email has no `email` key.\r\n\r\n### Error rows\r\n\r\nWhen `includeFailedPages` is on, a failed target or discovery query produces a diagnostic row instead of disappearing:\r\n\r\n```json\r\n{\r\n  \"url\": \"https://www.facebook.com/this-page-does-not-exist-zz9x7\",\r\n  \"errorCode\": \"not_found\",\r\n  \"detailsError\": \"This Facebook page is unavailable or was removed.\",\r\n  \"httpStatus\": 200,\r\n  \"fieldsFound\": 0,\r\n  \"dataSource\": \"facebook_public_page\",\r\n  \"scrapedAt\": \"2026-10-22T09:30:00+00:00\"\r\n}\r\n```\r\n\r\nStable `errorCode` values: `search_login_required`, `search_empty`, `blocked`, `timeout`, `not_found`, `login_wall`, `brand_redirect`, `not_a_page`, `http_error`, `no_data`, `parse_empty`.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n| --- | --- | --- | --- |\r\n| `startUrls` | array of `{url}` | `[]` | Direct Facebook Page URLs to enrich. |\r\n| `pageIds` | array of strings | `[]` | Numeric Page IDs, usernames, or Page URLs. Numeric IDs are fetched through `facebook.com/<id>`. |\r\n| `searchTerms` | array of strings | `[]` | Keywords for page discovery, e.g. `Coffee Shop` or `Dentist`. Requires a `c_user` + `xs` cookie. |\r\n| `locations` | array of strings | `[]` | City or region names added to each search query as a **soft hint**. Facebook does not expose a reliable city filter; verify the enriched address. |\r\n| `strictLocation` | boolean | `false` | Drop pages whose enriched address does not contain the location. Best-effort post-filter, not a city boundary. |\r\n| `categoryFilter` | array of strings | `[]` | Keep pages whose enriched category contains any of these terms (case-insensitive). Applied after enrichment. |\r\n| `minFollowers` | integer | `0` | Keep pages with at least this many followers. Pages with no follower count are dropped when this is above 0. |\r\n| `verifiedOnly` | boolean | `false` | Keep only pages whose public payload explicitly marks them as verified. |\r\n| `contactFilter` | select | `any` | Keep pages with `email`, `phone`, or `website`. Options: `any`, `email`, `phone`, `website`. |\r\n| `includeReviews` | boolean | `true` | Fetch the public reviews tab. Adds one request per page. Coverage is partial (Facebook exposes reviews for some pages only). |\r\n| `includeFailedPages` | boolean | `true` | Emit diagnostic rows for pages that cannot be enriched. Failed rows do not consume `maxItems`. |\r\n| `failOnEmpty` | boolean | `false` | Fail the run when zero page rows are produced. Useful for scheduled jobs that must not silently succeed with an empty dataset. |\r\n| `maxItems` | integer | `100` | Maximum successful page rows (1–5,000). Discovery over-collects candidates to absorb failures. |\r\n| `cookies` | string | empty | Optional. Only used for keyword discovery. Needs both `c_user` and `xs`. Accepts a JSON cookie array or a raw `name=value; ...` header. |\r\n| `proxyConfiguration` | proxy | Apify residential | Used only for keyword discovery. Facebook blocks search from datacenter IPs, so the default is Apify residential proxy. Set `useApifyProxy: false` to try a direct connection. |\r\n\r\n### Example: enrich known pages (cookieless)\r\n\r\n```json\r\n{\r\n  \"startUrls\": [\r\n    { \"url\": \"https://www.facebook.com/ozonecoffeeuk\" },\r\n    { \"url\": \"https://www.facebook.com/curatorscoffee\" }\r\n  ],\r\n  \"maxItems\": 2,\r\n  \"includeReviews\": true\r\n}\r\n```\r\n\r\n### Example: find coffee shops in London\r\n\r\n```json\r\n{\r\n  \"searchTerms\": [\"Coffee Shop\"],\r\n  \"locations\": [\"London\"],\r\n  \"strictLocation\": true,\r\n  \"categoryFilter\": [\"Coffee\"],\r\n  \"maxItems\": 100,\r\n  \"cookies\": \"c_user=1000...; xs=...\",\r\n  \"includeReviews\": false\r\n}\r\n```\r\n\r\n### Example: lead-ready pages only\r\n\r\n```json\r\n{\r\n  \"searchTerms\": [\"Dentist\", \"Hair Salon\"],\r\n  \"locations\": [\"Manchester\", \"Leeds\"],\r\n  \"contactFilter\": \"email\",\r\n  \"minFollowers\": 100,\r\n  \"maxItems\": 250,\r\n  \"cookies\": \"c_user=1000...; xs=...\"\r\n}\r\n```\r\n\r\n`searchTerms` examples always include a `cookies` value because Facebook keyword\r\nsearch requires a `c_user` + `xs` session; without it the run fails with a clear\r\nmessage (or, when direct targets are also supplied, emits a\r\n`search_login_required` diagnostic row and enriches the direct targets).\r\n\r\n## Cookies and Facebook search\r\n\r\nFacebook's own page search (`/search/pages/?q=...`) returns HTTP 404 with an empty body to anonymous requests, even after warming a `datr`/`sb` session. A session containing `c_user` and `xs` returns the search page and its results. Other cookies add nothing for this endpoint.\r\n\r\n- Cookies are used **only** for discovery.\r\n- Keyword discovery uses the `proxyConfiguration` input (Apify residential by default) because Facebook returns the login wall for datacenter IPs. You can set `useApifyProxy: false` to try a direct connection.\r\n- Page and About enrichment works better without cookies; the actor never sends them to Page URLs or through the discovery proxy.\r\n- If `searchTerms` are supplied without `c_user` + `xs`:\r\n  - with direct `startUrls`/`pageIds`, the run continues with cookieless enrichment and emits a `search_login_required` diagnostic row when `includeFailedPages` is on;\r\n  - without direct targets, the run fails with a clear message.\r\n- A cookie never becomes part of the output.\r\n\r\n## Honest limits\r\n\r\n- **City is a query hint, not a filter.** Facebook's internal place filter exists in some UI paths, but every public place UID tested returned zero results. The actor therefore appends the location to the keyword and offers `strictLocation` as a post-filter. A London query can return pages from The Hague, Amsterdam, Mexico, or Azerbaijan; `strictLocation` removes rows whose enriched address does not contain the location.\r\n- **No likes count.** Facebook does not expose a like count on public Page payloads. The actor returns followers and recommendation metrics only.\r\n- **No structured weekly hours.** Public payloads expose only a status string (`Open now`, `Closed now`, `Always open`), not a day-by-day grid.\r\n- **No 5-star rating.** Facebook retired Page star ratings. `recommendPercentage` and `reviewCount` are the real metrics; no rating is synthesized.\r\n- **Reviews are partial.** Facebook exposes reviews for some pages only. Treat `reviews` as \"reviews when public\", not a guarantee.\r\n- **Email is the scarcest field.** Across the discovery sample, phone was present on roughly 84% of pages, address on 79%, website on 84%, and email on 68%. Missing fields mean the Page owner did not publish them.\r\n- **Some pages are not pages.** Search can return personal profiles, groups, and other surfaces. The actor filters known non-page categories and classifies the rest in error rows (`not_a_page`, `no_data`, `brand_redirect`).\r\n\r\n## Scaling\r\n\r\n- `maxItems` defaults to 100 and supports up to 5,000.\r\n- Discovery over-collects about 2× the requested count, because some candidates turn out to be unavailable, login-walled, or filtered out.\r\n- Multiple `searchTerms` × `locations` multiply the candidate pool. For 1,000+ rows, use several specific terms and cities rather than one generic query.\r\n- Page enrichment runs two requests at a time with polite jitter. About tabs are read only up to the useful public data, keeping bandwidth low.\r\n\r\n## Use cases\r\n\r\n- **Local lead generation** — collect dentists, cafés, salons, or contractors by keyword and city with public phone/email/website contacts.\r\n- **CRM enrichment** — append category, address, followers, and social links to a list of known Facebook Pages.\r\n- **Franchise and multi-location mapping** — compare follower counts and recommendation percentages across locations.\r\n- **Market research** — size a category in a region and inspect price ranges, services, and Page creation dates.\r\n- **Trust and ad checks** — use `isVerified`, `creationDate`, `adStatus`, and `pageAdLibraryUrl` to qualify a Page.\r\n- **Review monitoring** — pull public review text and recommendation verdicts for pages that expose them.\r\n\r\n## FAQ\r\n\r\n### Do I need a Facebook account or cookies?\r\n\r\nOnly for keyword discovery. Page URL and Page ID enrichment is cookieless. To use `searchTerms`, add a cookie header containing both `c_user` and `xs` from a logged-in browser session. Cookies are never required for `startUrls` or `pageIds`.\r\n\r\n### Why did a search return zero results?\r\n\r\nFacebook search needs a valid logged-in session. Check that the cookie contains `c_user` and `xs` and has not expired. If you also supplied direct URLs, the run continues with them and emits a `search_login_required` diagnostic row when `includeFailedPages` is on.\r\n\r\n### Why is the city not exact?\r\n\r\nFacebook's public page search is keyword-ranked, not location-filtered. The location is appended to the query as a hint. Use `strictLocation: true` to drop rows whose enriched address does not contain the location, and expect lower result counts.\r\n\r\n### Why are email or phone missing from some records?\r\n\r\nFacebook only exposes contact fields that the Page owner made public. Across typical business pages, email is the least available field. A missing field is omitted from the record rather than returned as `null`.\r\n\r\n### Why are there no likes or weekly opening hours?\r\n\r\nFacebook's public payload does not include a likes count or a structured day-by-day hours grid. The actor returns followers, `recommendPercentage`, `reviewCount`, and the current `openStatus` instead of inventing values.\r\n\r\n### Why do some Pages have no reviews?\r\n\r\nFacebook exposes reviews only for pages that have them and make them public. `includeReviews` adds one request per page; coverage is partial.\r\n\r\n### What does `fieldsFound` mean?\r\n\r\nIt is the number of populated data fields in the row. Combined with `detailsError`, it distinguishes \"Facebook did not publish this field\" from \"the actor failed to read it\".\r\n\r\n### What happens when a Page is unavailable or redirects?\r\n\r\nWith `includeFailedPages` (default), the actor emits a row with an `errorCode` such as `not_found`, `brand_redirect`, `not_a_page`, or `no_data`. Set `failOnEmpty: true` if a scheduled run should fail when no page rows are produced.\r\n\r\n### Is this affiliated with Facebook or Meta?\r\n\r\nNo. This is an independent third-party actor that reads publicly accessible Facebook Pages. It is not affiliated with, endorsed by, or operated by Meta Platforms, Inc.\r\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "facebook-business-page-finder-by-keyword-and-city",
      "title": "Facebook Business Page Finder by Keyword & City",
      "description": "Find Facebook business Pages by keyword and location, or enrich Page URLs and IDs. Returns contact details, social links, followers, recommendation %, open status, price range, services, Page Transparency data, images, and reviews. Search needs c_user + xs cookies; URL enrichment is cookieless.",
      "version": "1.1",
      "buildTag": "latest",
      "readme": "# Facebook Business Page Finder by Keyword & City\r\n\r\nFind Facebook business Pages by keyword and location, or enrich a list of Page URLs, and get back the identity, contact details, social links, follower count, recommendation percentage, open status, price range, services, Page Transparency date, ad status, images, and real review objects that Facebook exposes publicly.\r\n\r\nThe actor is built for local lead generation and page research. It discovers Pages through Facebook's own page search, then reads each Page's public root and About tabs without cookies. No Facebook login is needed to enrich URLs; a `c_user` + `xs` session cookie is required only for keyword discovery.\r\n\r\n## What this actor does\r\n\r\n- **Two ways in:** paste Facebook Page URLs, `pageIds` (numeric IDs or usernames), or run keyword + location discovery with `searchTerms` + `locations`.\r\n- **Cookie-aware discovery:** Facebook's `/search/pages/` endpoint returns results only to a logged-in session. The actor validates that the supplied cookie contains `c_user` and `xs`, replays the page's own search cursor for up to 10 results per request, and stops at `maxItems`.\r\n- **Cookieless enrichment:** Page root and About tabs are fetched with browser-compatible requests, and cookies are never sent to Page or About URLs.\r\n- **Efficient About reads:** the actor stops reading each About tab after the useful public data (about 560–650 KB) instead of downloading the full ~20 MB response.\r\n- **Lead-ready output:** identity, category, address and coordinates, phone, email, website, Messenger link, Instagram/social links, followers (raw and parsed), recommendation percentage, review count, open status, price range, services, verified flag, creation date, ad status, Ad Library link, profile/cover images, and reviews.\r\n- **Post-fetch filters:** `strictLocation`, `categoryFilter`, `minFollowers`, `verifiedOnly`, and `contactFilter`.\r\n- **Explicit failure rows:** `includeFailedPages` emits diagnostic rows with a stable `errorCode` and `detailsError` instead of silently dropping pages. `failOnEmpty` turns a zero-page run into a failed run.\r\n- **Omit-empty output:** fields Facebook does not expose for a Page are left out of that record, never emitted as `null`, `\"\"`, or `[]`.\r\n\r\n## Output per page\r\n\r\n- `pageId` — Facebook Page ID, when exposed by the public payload\r\n- `pageName`, `username`, `title` — Page identity\r\n- `facebookUrl`, `pageUrl`, `resolvedUrl` — requested canonical URL and final resolved URL\r\n- `pageType` — always `page`\r\n- `isVerified` — `true` / `false` when Facebook exposes the flag; omitted when unknown\r\n- `category` — primary Page category\r\n- `address`, `city`, `region`, `postalCode`, `country` — parsed from the public address\r\n- `latitude`, `longitude`, `addressUrl` — coordinates and a Google Maps link\r\n- `phone`, `email`, `website`, `messenger` — public contact details and `https://m.me/<pageId>`\r\n- `socialLinks` — Instagram and other linked accounts exposed on the Page\r\n- `followers`, `followersText` — parsed follower count and the raw label (`9.1K followers`)\r\n- `recommendPercentage`, `reviewCount`, `ratingText` — the real Facebook recommendation metrics; no synthetic star rating\r\n- `openStatus` — `Open now`, `Closed now`, `Always open`, `Opening soon`, and similar\r\n- `priceRange`, `services`, `about` — business details and the About text\r\n- `creationDate`, `adStatus` — Page Transparency values\r\n- `pageAdLibraryUrl` — constructed Meta Ad Library URL for the Page\r\n- `profilePictureUrl`, `coverPhotoUrl` — Page images\r\n- `reviews[]` — review objects with `reviewerName`, `recommends`, `reviewText`, `reviewDate`, plus optional `reviewId`, `authorProfileUrl`, `reactions`, `commentCount`\r\n- `searchTerm`, `searchLocation` — the discovery query that produced the row\r\n- `inputUrl` — the URL or ID supplied or discovered\r\n- `dataSource` — `facebook_search+public_page` or `facebook_public_page`\r\n- `fieldsFound` — number of populated data fields\r\n- `detailsError` — why optional detail tabs were skipped, when partial\r\n- `reviewsError` — why the optional reviews tab was empty or skipped\r\n- `scrapedAt` — ISO 8601 UTC timestamp\r\n\r\nEmpty fields are omitted at every depth. A record with no reviews has no `reviews` key; a Page with no public email has no `email` key.\r\n\r\n### Error rows\r\n\r\nWhen `includeFailedPages` is on, a failed target or discovery query produces a diagnostic row instead of disappearing:\r\n\r\n```json\r\n{\r\n  \"url\": \"https://www.facebook.com/this-page-does-not-exist-zz9x7\",\r\n  \"errorCode\": \"not_found\",\r\n  \"detailsError\": \"This Facebook page is unavailable or was removed.\",\r\n  \"httpStatus\": 200,\r\n  \"fieldsFound\": 0,\r\n  \"dataSource\": \"facebook_public_page\",\r\n  \"scrapedAt\": \"2026-10-22T09:30:00+00:00\"\r\n}\r\n```\r\n\r\nStable `errorCode` values: `search_login_required`, `search_empty`, `blocked`, `timeout`, `not_found`, `login_wall`, `brand_redirect`, `not_a_page`, `http_error`, `no_data`, `parse_empty`.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n| --- | --- | --- | --- |\r\n| `startUrls` | array of `{url}` | `[]` | Direct Facebook Page URLs to enrich. |\r\n| `pageIds` | array of strings | `[]` | Numeric Page IDs, usernames, or Page URLs. Numeric IDs are fetched through `facebook.com/<id>`. |\r\n| `searchTerms` | array of strings | `[]` | Keywords for page discovery, e.g. `Coffee Shop` or `Dentist`. Requires a `c_user` + `xs` cookie. |\r\n| `locations` | array of strings | `[]` | City or region names added to each search query as a **soft hint**. Facebook does not expose a reliable city filter; verify the enriched address. |\r\n| `strictLocation` | boolean | `false` | Drop pages whose enriched address does not contain the location. Best-effort post-filter, not a city boundary. |\r\n| `categoryFilter` | array of strings | `[]` | Keep pages whose enriched category contains any of these terms (case-insensitive). Applied after enrichment. |\r\n| `minFollowers` | integer | `0` | Keep pages with at least this many followers. Pages with no follower count are dropped when this is above 0. |\r\n| `verifiedOnly` | boolean | `false` | Keep only pages whose public payload explicitly marks them as verified. |\r\n| `contactFilter` | select | `any` | Keep pages with `email`, `phone`, or `website`. Options: `any`, `email`, `phone`, `website`. |\r\n| `includeReviews` | boolean | `true` | Fetch the public reviews tab. Adds one request per page. Coverage is partial (Facebook exposes reviews for some pages only). |\r\n| `includeFailedPages` | boolean | `true` | Emit diagnostic rows for pages that cannot be enriched. Failed rows do not consume `maxItems`. |\r\n| `failOnEmpty` | boolean | `false` | Fail the run when zero page rows are produced. Useful for scheduled jobs that must not silently succeed with an empty dataset. |\r\n| `maxItems` | integer | `100` | Maximum successful page rows (1–5,000). Discovery over-collects candidates to absorb failures. |\r\n| `cookies` | string | empty | Optional. Only used for keyword discovery. Needs both `c_user` and `xs`. Accepts a JSON cookie array or a raw `name=value; ...` header. |\r\n| `proxyConfiguration` | proxy | Apify residential | Used only for keyword discovery. Facebook blocks search from datacenter IPs, so the default is Apify residential proxy. Set `useApifyProxy: false` to try a direct connection. |\r\n\r\n### Example: enrich known pages (cookieless)\r\n\r\n```json\r\n{\r\n  \"startUrls\": [\r\n    { \"url\": \"https://www.facebook.com/ozonecoffeeuk\" },\r\n    { \"url\": \"https://www.facebook.com/curatorscoffee\" }\r\n  ],\r\n  \"maxItems\": 2,\r\n  \"includeReviews\": true\r\n}\r\n```\r\n\r\n### Example: find coffee shops in London\r\n\r\n```json\r\n{\r\n  \"searchTerms\": [\"Coffee Shop\"],\r\n  \"locations\": [\"London\"],\r\n  \"strictLocation\": true,\r\n  \"categoryFilter\": [\"Coffee\"],\r\n  \"maxItems\": 100,\r\n  \"cookies\": \"c_user=1000...; xs=...\",\r\n  \"includeReviews\": false\r\n}\r\n```\r\n\r\n### Example: lead-ready pages only\r\n\r\n```json\r\n{\r\n  \"searchTerms\": [\"Dentist\", \"Hair Salon\"],\r\n  \"locations\": [\"Manchester\", \"Leeds\"],\r\n  \"contactFilter\": \"email\",\r\n  \"minFollowers\": 100,\r\n  \"maxItems\": 250,\r\n  \"cookies\": \"c_user=1000...; xs=...\"\r\n}\r\n```\r\n\r\n`searchTerms` examples always include a `cookies` value because Facebook keyword\r\nsearch requires a `c_user` + `xs` session; without it the run fails with a clear\r\nmessage (or, when direct targets are also supplied, emits a\r\n`search_login_required` diagnostic row and enriches the direct targets).\r\n\r\n## Cookies and Facebook search\r\n\r\nFacebook's own page search (`/search/pages/?q=...`) returns HTTP 404 with an empty body to anonymous requests, even after warming a `datr`/`sb` session. A session containing `c_user` and `xs` returns the search page and its results. Other cookies add nothing for this endpoint.\r\n\r\n- Cookies are used **only** for discovery.\r\n- Keyword discovery uses the `proxyConfiguration` input (Apify residential by default) because Facebook returns the login wall for datacenter IPs. You can set `useApifyProxy: false` to try a direct connection.\r\n- Page and About enrichment works better without cookies; the actor never sends them to Page URLs or through the discovery proxy.\r\n- If `searchTerms` are supplied without `c_user` + `xs`:\r\n  - with direct `startUrls`/`pageIds`, the run continues with cookieless enrichment and emits a `search_login_required` diagnostic row when `includeFailedPages` is on;\r\n  - without direct targets, the run fails with a clear message.\r\n- A cookie never becomes part of the output.\r\n\r\n## Honest limits\r\n\r\n- **City is a query hint, not a filter.** Facebook's internal place filter exists in some UI paths, but every public place UID tested returned zero results. The actor therefore appends the location to the keyword and offers `strictLocation` as a post-filter. A London query can return pages from The Hague, Amsterdam, Mexico, or Azerbaijan; `strictLocation` removes rows whose enriched address does not contain the location.\r\n- **No likes count.** Facebook does not expose a like count on public Page payloads. The actor returns followers and recommendation metrics only.\r\n- **No structured weekly hours.** Public payloads expose only a status string (`Open now`, `Closed now`, `Always open`), not a day-by-day grid.\r\n- **No 5-star rating.** Facebook retired Page star ratings. `recommendPercentage` and `reviewCount` are the real metrics; no rating is synthesized.\r\n- **Reviews are partial.** Facebook exposes reviews for some pages only. Treat `reviews` as \"reviews when public\", not a guarantee.\r\n- **Email is the scarcest field.** Across the discovery sample, phone was present on roughly 84% of pages, address on 79%, website on 84%, and email on 68%. Missing fields mean the Page owner did not publish them.\r\n- **Some pages are not pages.** Search can return personal profiles, groups, and other surfaces. The actor filters known non-page categories and classifies the rest in error rows (`not_a_page`, `no_data`, `brand_redirect`).\r\n\r\n## Scaling\r\n\r\n- `maxItems` defaults to 100 and supports up to 5,000.\r\n- Discovery over-collects about 2× the requested count, because some candidates turn out to be unavailable, login-walled, or filtered out.\r\n- Multiple `searchTerms` × `locations` multiply the candidate pool. For 1,000+ rows, use several specific terms and cities rather than one generic query.\r\n- Page enrichment runs two requests at a time with polite jitter. About tabs are read only up to the useful public data, keeping bandwidth low.\r\n\r\n## Use cases\r\n\r\n- **Local lead generation** — collect dentists, cafés, salons, or contractors by keyword and city with public phone/email/website contacts.\r\n- **CRM enrichment** — append category, address, followers, and social links to a list of known Facebook Pages.\r\n- **Franchise and multi-location mapping** — compare follower counts and recommendation percentages across locations.\r\n- **Market research** — size a category in a region and inspect price ranges, services, and Page creation dates.\r\n- **Trust and ad checks** — use `isVerified`, `creationDate`, `adStatus`, and `pageAdLibraryUrl` to qualify a Page.\r\n- **Review monitoring** — pull public review text and recommendation verdicts for pages that expose them.\r\n\r\n## FAQ\r\n\r\n### Do I need a Facebook account or cookies?\r\n\r\nOnly for keyword discovery. Page URL and Page ID enrichment is cookieless. To use `searchTerms`, add a cookie header containing both `c_user` and `xs` from a logged-in browser session. Cookies are never required for `startUrls` or `pageIds`.\r\n\r\n### Why did a search return zero results?\r\n\r\nFacebook search needs a valid logged-in session. Check that the cookie contains `c_user` and `xs` and has not expired. If you also supplied direct URLs, the run continues with them and emits a `search_login_required` diagnostic row when `includeFailedPages` is on.\r\n\r\n### Why is the city not exact?\r\n\r\nFacebook's public page search is keyword-ranked, not location-filtered. The location is appended to the query as a hint. Use `strictLocation: true` to drop rows whose enriched address does not contain the location, and expect lower result counts.\r\n\r\n### Why are email or phone missing from some records?\r\n\r\nFacebook only exposes contact fields that the Page owner made public. Across typical business pages, email is the least available field. A missing field is omitted from the record rather than returned as `null`.\r\n\r\n### Why are there no likes or weekly opening hours?\r\n\r\nFacebook's public payload does not include a likes count or a structured day-by-day hours grid. The actor returns followers, `recommendPercentage`, `reviewCount`, and the current `openStatus` instead of inventing values.\r\n\r\n### Why do some Pages have no reviews?\r\n\r\nFacebook exposes reviews only for pages that have them and make them public. `includeReviews` adds one request per page; coverage is partial.\r\n\r\n### What does `fieldsFound` mean?\r\n\r\nIt is the number of populated data fields in the row. Combined with `detailsError`, it distinguishes \"Facebook did not publish this field\" from \"the actor failed to read it\".\r\n\r\n### What happens when a Page is unavailable or redirects?\r\n\r\nWith `includeFailedPages` (default), the actor emits a row with an `errorCode` such as `not_found`, `brand_redirect`, `not_a_page`, or `no_data`. Set `failOnEmpty: true` if a scheduled run should fail when no page rows are produced.\r\n\r\n### Is this affiliated with Facebook or Meta?\r\n\r\nNo. This is an independent third-party actor that reads publicly accessible Facebook Pages. It is not affiliated with, endorsed by, or operated by Meta Platforms, Inc.\r\n",
      "input": {
        "title": "Facebook Business Page Finder Input",
        "description": "Find Facebook business pages by keyword and city, or enrich page URLs and IDs with public contact details. Keyword search uses Facebook's own page search and needs a Facebook session; page enrichment runs without cookies.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "startUrls": {
            "title": "Facebook Page URLs",
            "type": "array",
            "description": "Direct Facebook page URLs to enrich, for example https://www.facebook.com/ozonecoffeeuk. Can be combined with pageIds and searchTerms.",
            "editor": "requestListSources",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "Page URL",
                  "description": "A Facebook Page URL."
                }
              }
            },
            "default": [],
            "prefill": [
              {
                "url": "https://www.facebook.com/nike"
              }
            ]
          },
          "pageIds": {
            "title": "Page IDs or Usernames",
            "type": "array",
            "description": "Facebook numeric Page IDs, usernames, or page URLs. Numeric IDs are fetched through https://www.facebook.com/<id>.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "default": [],
            "prefill": []
          },
          "searchTerms": {
            "title": "Search Terms",
            "type": "array",
            "description": "Keywords for Facebook page discovery, for example Coffee Shop or Dentist. Each term is combined with each location as a text query. Facebook keyword search requires a cookie containing both c_user and xs.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "default": [],
            "prefill": []
          },
          "locations": {
            "title": "Locations",
            "type": "array",
            "description": "City or region names added to the search query as a soft hint. Facebook does not expose a reliable city filter, so always verify the enriched address. Use strictLocation to drop rows whose address does not contain the location.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "default": [],
            "prefill": []
          },
          "strictLocation": {
            "title": "Strict Location Post-Filter",
            "type": "boolean",
            "description": "Drop pages whose enriched address does not contain the search location. This is a best-effort post-filter, not an exact city boundary.",
            "default": false,
            "prefill": false
          },
          "categoryFilter": {
            "title": "Category Filter",
            "type": "array",
            "description": "Keep pages whose enriched category contains any of these terms (case-insensitive). Filtering happens after enrichment.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "default": [],
            "prefill": []
          },
          "minFollowers": {
            "title": "Minimum Followers",
            "type": "integer",
            "description": "Keep pages with at least this many followers. Pages with no follower count are dropped when this is above 0.",
            "default": 0,
            "minimum": 0,
            "maximum": 100000000,
            "prefill": 0
          },
          "verifiedOnly": {
            "title": "Verified Pages Only",
            "type": "boolean",
            "description": "Keep only pages whose public payload explicitly marks them as verified.",
            "default": false,
            "prefill": false
          },
          "contactFilter": {
            "title": "Contact Filter",
            "type": "string",
            "description": "Keep only lead-ready pages that expose the selected contact field.",
            "editor": "select",
            "enum": [
              "any",
              "email",
              "phone",
              "website"
            ],
            "enumTitles": [
              "Any page",
              "Has email",
              "Has phone",
              "Has website"
            ],
            "default": "any",
            "prefill": "any"
          },
          "includeReviews": {
            "title": "Include Reviews",
            "type": "boolean",
            "description": "Fetch the public reviews tab and include reviews when Facebook exposes them. Adds one request per page. Review coverage is partial.",
            "default": true,
            "prefill": false
          },
          "includeFailedPages": {
            "title": "Include Failed Pages",
            "type": "boolean",
            "description": "Emit diagnostic rows with errorCode, detailsError, and fieldsFound for pages that cannot be enriched. This prevents silent empty runs.",
            "default": true,
            "prefill": true
          },
          "failOnEmpty": {
            "title": "Fail When Empty",
            "type": "boolean",
            "description": "Fail the run when zero page rows are produced. Leave off to finish successfully with diagnostic rows explaining why nothing was found.",
            "default": false,
            "prefill": false
          },
          "maxItems": {
            "title": "Maximum Pages",
            "type": "integer",
            "description": "Maximum number of successful page rows. Failed rows do not consume this limit.",
            "default": 100,
            "minimum": 1,
            "maximum": 5000,
            "prefill": 1
          },
          "cookies": {
            "title": "Facebook Session Cookies",
            "type": "string",
            "description": "Optional. Needed only for keyword discovery. c_user and xs are enough. Accepts a JSON array of cookie objects or a raw name=value; name2=value2 Cookie header. Page enrichment works without cookies.",
            "editor": "textfield",
            "isSecret": true,
            "prefill": "",
            "sectionCaption": "Discovery authentication",
            "sectionDescription": "Cookies are used only for Facebook page search. They are never sent when enriching public page URLs."
          },
          "proxyConfiguration": {
            "title": "Proxy Configuration",
            "type": "object",
            "description": "Used only for keyword discovery. Defaults to Apify residential proxy because Facebook search blocks datacenter IPs. Public page enrichment does not use it.",
            "editor": "proxy",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            },
            "prefill": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            }
          }
        }
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "Facebook Business Page Finder by Keyword & City Output",
        "description": "One record per Facebook business Page with identity, public contact details, social links, followers, recommendation metrics, open status, business details, Page Transparency data, images, and reviews.",
        "properties": {
          "pages": {
            "type": "string",
            "title": "Facebook Page Data",
            "description": "Dataset containing discovered Facebook Page rows with structured public metadata and diagnostic error rows.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "dockerfile": "../Dockerfile",
      "defaultMemoryMbytes": 2048,
      "minMemoryMbytes": 2048,
      "categories": [
        "SOCIAL_MEDIA"
      ],
      "meta": {
        "templateId": "python-playwright"
      },
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "title": "Facebook Page Discovery Data",
          "views": {
            "overview": {
              "title": "Page Overview",
              "transformation": {
                "fields": [
                  "pageName",
                  "category",
                  "address",
                  "followers",
                  "recommendPercentage",
                  "facebookUrl"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "pageName": {
                    "label": "Page Name",
                    "format": "text"
                  },
                  "category": {
                    "label": "Category",
                    "format": "text"
                  },
                  "address": {
                    "label": "Address",
                    "format": "text"
                  },
                  "followers": {
                    "label": "Followers",
                    "format": "number"
                  },
                  "recommendPercentage": {
                    "label": "Recommend %",
                    "format": "number"
                  },
                  "facebookUrl": {
                    "label": "Facebook URL",
                    "format": "link"
                  }
                }
              }
            },
            "detailed": {
              "title": "Detailed View",
              "transformation": {
                "fields": [
                  "facebookUrl",
                  "pageUrl",
                  "pageName",
                  "pageId",
                  "category",
                  "address",
                  "city",
                  "phone",
                  "email",
                  "website",
                  "messenger",
                  "followers",
                  "recommendPercentage",
                  "reviewCount",
                  "openStatus",
                  "priceRange",
                  "services",
                  "isVerified",
                  "creationDate",
                  "adStatus",
                  "profilePictureUrl",
                  "coverPhotoUrl",
                  "fieldsFound",
                  "detailsError",
                  "errorCode"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "facebookUrl": {
                    "label": "Facebook URL",
                    "format": "link"
                  },
                  "pageUrl": {
                    "label": "Page URL",
                    "format": "link"
                  },
                  "pageName": {
                    "label": "Page Name",
                    "format": "text"
                  },
                  "pageId": {
                    "label": "Page ID",
                    "format": "text"
                  },
                  "category": {
                    "label": "Category",
                    "format": "text"
                  },
                  "address": {
                    "label": "Address",
                    "format": "text"
                  },
                  "city": {
                    "label": "City",
                    "format": "text"
                  },
                  "phone": {
                    "label": "Phone",
                    "format": "text"
                  },
                  "email": {
                    "label": "Email",
                    "format": "text"
                  },
                  "website": {
                    "label": "Website",
                    "format": "link"
                  },
                  "messenger": {
                    "label": "Messenger",
                    "format": "link"
                  },
                  "followers": {
                    "label": "Followers",
                    "format": "number"
                  },
                  "recommendPercentage": {
                    "label": "Recommend %",
                    "format": "number"
                  },
                  "reviewCount": {
                    "label": "Review Count",
                    "format": "number"
                  },
                  "openStatus": {
                    "label": "Open Status",
                    "format": "text"
                  },
                  "priceRange": {
                    "label": "Price Range",
                    "format": "text"
                  },
                  "services": {
                    "label": "Services",
                    "format": "text"
                  },
                  "isVerified": {
                    "label": "Verified",
                    "format": "boolean"
                  },
                  "creationDate": {
                    "label": "Creation Date",
                    "format": "text"
                  },
                  "adStatus": {
                    "label": "Ad Status",
                    "format": "text"
                  },
                  "profilePictureUrl": {
                    "label": "Profile Picture",
                    "format": "link"
                  },
                  "coverPhotoUrl": {
                    "label": "Cover Photo",
                    "format": "link"
                  },
                  "fieldsFound": {
                    "label": "Fields Found",
                    "format": "number"
                  },
                  "detailsError": {
                    "label": "Details Error",
                    "format": "text"
                  },
                  "errorCode": {
                    "label": "Error Code",
                    "format": "text"
                  }
                }
              }
            }
          }
        }
      },
      "environmentVariables": {}
    },
    "buildNumber": "1.1.2",
    "imageDigest": "6e3955964dd0f042336a307d9d04b34118360847b2d60f4add21741d0bf609a9",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.1"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.03698
    }
  }
}