Facebook pages, posts, comments, reels, photos, groups, events, Marketplace, and the Ad Library through one API key
Public Facebook data on a plain GET: page profiles and their feeds, post comment trees, reels and photo galleries, group posts, the events directory, Marketplace listings, and the full Facebook Ad Library. Nearly all of it is 1 credit, which makes Facebook one of the cheapest platforms here to crawl at volume.
Base URL: /v1/facebook/...
Reply threads do not take a comment id. /v1/facebook/post/comment/replies
needs the feedback_id and expansion_token that
/v1/facebook/post/comments returns for that comment. Neither is the
comment's own id, and there is no way to construct them. You have to make the
parent call first.
Quickstart
1. Fetch a profile
curl "https://www.socialcrawl.dev/v1/facebook/profile?url=https://www.facebook.com/Meta" \
-H "x-api-key: YOUR_API_KEY"2. Fetch their content
curl "https://www.socialcrawl.dev/v1/facebook/profile/posts?url=https://www.facebook.com/Meta" \
-H "x-api-key: YOUR_API_KEY"3. Read computed fields
When an endpoint supports a computed field and the required source inputs are present, the unified response includes that optional field. Depending on the endpoint, optional fields can include engagement_rate, language, content_category, and estimated_reach. See Computed fields for formulas, clamping rules, and null semantics. Where an endpoint supports them, list rows also carry judged labels (computed.labels, computed.relevance) by default at no extra credits; see Labels.
Pages
| Endpoint | Credits | What it returns | Key parameters |
|---|---|---|---|
GET /v1/facebook/profile | 1 | Page identity, category, contact details, and the page id | url, get_business_hours |
GET /v1/facebook/profile/full | 5 | The page, its recent posts, and computed analytics in one flat call | url, posts (1-100, default 25), include |
GET /v1/facebook/profile/posts | 1 | The page's recent posts, cursor-paged | url or pageId, cursor |
GET /v1/facebook/profile/events | 1 | One page's own upcoming and past events | url, cursor |
The profile response carries a page id. Pass it back as pageId on profile/posts instead of the url and the lookup gets faster. pageId is also what the Ad Library indexes an advertiser by, so it is worth holding.
profile/full adds two average engagement rates, posting cadence, top post, and format mix over a window of posts. avg_engagement_rate divides each post's engagement by its view count, so it is null when no post in the window has one; avg_engagement_rate_by_followers divides likes and comments by the follower count and covers posts with no view count. The profile still comes back if the posts leg fails, with the post-dependent metrics null.
Facebook keeps a post's share count, and a reel's exact view count and duration, on the permalink rather than in the feed, so on a plain profile/posts call those leaves are null. Send include=engagement and every row is joined to its own post record in the same call: 1 credit for the page plus 1 per row filled, 4 at most, with rows already in cache filled for free and anything the lookup could not fill refunded. Reach for it whenever you were about to walk the list and call post once per row. The same include pattern covers photos and both event lists; Fill the rows, or fetch them? compares it against the alternatives.
Posts and comments
| Endpoint | Credits | What it returns | Key parameters |
|---|---|---|---|
GET /v1/facebook/post | 1 | One post in full, including the reactions breakdown | url, get_comments, get_transcript |
GET /v1/facebook/post/comments | 1 | The comment list, walked by cursor | url or feedback_id, cursor, label, judgments |
GET /v1/facebook/post/comment/replies | 1 | One reply thread | feedback_id and expansion_token, label, judgments |
GET /v1/facebook/post/transcript | 10 | The spoken words of a video post, from Facebook's own captions | url |
post is the only endpoint that carries the reactions breakdown, the split between like, love, haha and the rest, rather than a single total. get_comments=true folds in the first several comments and get_transcript=true folds in a video transcript, so one call can cover a whole post when you do not need to page.
On post/comments, pass feedback_id instead of url when you have one from a prior post call: it is materially faster. That same response is where each comment's feedback_id and expansion_token come from.
Media
| Endpoint | Credits | What it returns | Key parameters |
|---|---|---|---|
GET /v1/facebook/profile/photos | 1 | A page's gallery: photo id, permalink, full-size image, thumbnail | url, next_page_id |
GET /v1/facebook/profile/reels | 1 | The cheap reel list, with the rounded public view count | url, next_page_id |
GET /v1/facebook/profile/reels/full | 5 to 25 | The same list with exact per-reel engagement merged in | url, limit (max 50) |
profile/photos also returns the accessibility caption where Facebook generated one, but the plain listing carries no author, engagement, or publish time per photo. include=details fills all of it in the same call, at 1 credit for the page plus 1 per photo filled and 9 at most, so use it instead of passing each permalink to post yourself. A photo posted inside a multi-photo post carries its own counts rather than the parent post's.
profile/reels has no likes, comments, or shares. profile/reels/full is metered: it consumes upstream pages of 10 reels and bills 5 credits per page, from 5 up to 25 for a limit=50 walk. If the walk hits its internal time budget the response carries _warnings: ["walk_deadline_reached"], the unfetched pages are refunded, and next_cursor resumes exactly where it stopped.
Groups
| Endpoint | Credits | What it returns | Key parameters |
|---|---|---|---|
GET /v1/facebook/group | 1 | Group identity: name, description, member count, privacy | url or group_id |
GET /v1/facebook/group/posts | 1 | That group's posts with reaction, comment, and share counts | url or group_id, sort_by, cursor |
Facebook serves the group feed in slices of 3 to 4 posts, so depth is a cursor walk: send pagination.next_cursor back as cursor and repeat until has_more is false. Each page is 1 credit. sort_by=CHRONOLOGICAL is the setting for keeping a busy group current; the default and TOP_POSTS mix older high-engagement posts into the first pages.
Events
| Endpoint | Credits | What it returns | Key parameters |
|---|---|---|---|
GET /v1/facebook/events | 1 | What is on in a place, from a city's Facebook Events page URL | url, time, cursor |
GET /v1/facebook/events/search | 1 | The public directory searched by keyword | query, cursor |
GET /v1/facebook/event/details | 1 | Description, start and end times, host, and RSVP counts | id or url |
Three entry points into the same event objects. events/search also returns events that have already happened, so filter on is_past yourself.
Both listings take include=details, which joins every row to its own event record in one call and fills the description, street address, coordinates, hosts, category, privacy, and RSVP counts the listing leaves out: 1 credit for the page plus 1 per event filled, 9 at most on a page's own events and 13 on a city feed, with cached rows free and unfilled rows refunded. A page's events tab carries no cover image and no RSVP counts of its own, so those arrive with include=details too. Call event/details directly when you already hold a single event id rather than a listing.
Marketplace
| Endpoint | Credits | What it returns | Key parameters |
|---|---|---|---|
GET /v1/facebook/marketplace/location/search | 1 | A city or area name turned into a lat/lng pair | query |
GET /v1/facebook/marketplace/search | 1 | Listings near those coordinates | query, lat, lng, all required, plus radius_km, min_price, max_price, condition, delivery_method, date_listed, availability, sort_by |
GET /v1/facebook/marketplace/item | 1 | One listing in full | id or url |
Marketplace search is geographic, not textual, which is why the coordinate lookup comes first.
curl "https://www.socialcrawl.dev/v1/facebook/marketplace/location/search?query=Austin" \
-H "x-api-key: YOUR_API_KEY"
curl "https://www.socialcrawl.dev/v1/facebook/marketplace/search?query=bike&lat=30.2672&lng=-97.7431&radius_km=40&max_price=500" \
-H "x-api-key: YOUR_API_KEY"De-duplicate on listing id. The ordering shifts between calls, so consecutive cursor pages occasionally repeat an item.
Ad Library
| Endpoint | Credits | What it returns | Key parameters |
|---|---|---|---|
GET /v1/facebook/adlibrary/search/companies | 5 | An advertiser name turned into a pageId | query |
GET /v1/facebook/adlibrary/company/ads | 5 | Everything that page is running | pageId or companyName, country, status, media_type, language, sort_by, start_date, end_date |
GET /v1/facebook/adlibrary/search/ads | 5 | Ad copy searched by keyword across every advertiser | query, search_type, ad_type, country, status, media_type |
GET /v1/facebook/adlibrary/ad | 5 | One ad expanded into creative, spend, impressions, and targeting | id or url, trim |
GET /v1/facebook/adlibrary/ad/transcript | 10 | What a video ad says out loud | id or url |
search_type gives exact-phrase matching, and ad_type restricts to political and issue ads. The transcript uses Facebook's captions where they exist and transcribes the video where they do not.
All endpoints
29 endpoints available.
| Endpoint | Path | Credit Tier |
|---|---|---|
| Get details for a Facebook event | /v1/facebook/event/details | standard (1cr) |
| List Facebook events for a city | /v1/facebook/events | standard (1-13cr)metered |
| Search Facebook events by keyword | /v1/facebook/events/search | standard (1cr) |
| Get a Facebook group | /v1/facebook/group | standard (1cr) |
| List Facebook group posts | /v1/facebook/group/posts | standard (1cr) |
| Get a Facebook Marketplace item | /v1/facebook/marketplace/item | standard (1cr) |
| Search Facebook Marketplace locations | /v1/facebook/marketplace/location/search | standard (1cr) |
| Search Facebook Marketplace listings | /v1/facebook/marketplace/search | standard (1cr) |
| Get Facebook post details | /v1/facebook/post | standard (1cr) |
| List replies to a Facebook post comment | /v1/facebook/post/comment/replies | standard (1-5cr)metered |
| List Facebook post comments | /v1/facebook/post/comments | standard (1-5cr)metered |
| Get Facebook page profile | /v1/facebook/profile | standard (1cr) |
| List a Facebook page's events | /v1/facebook/profile/events | standard (1-9cr)metered |
| Facebook profile, recent posts, and computed analytics in one call. | /v1/facebook/profile/full | standard (5cr) |
| List Facebook profile photos | /v1/facebook/profile/photos | standard (1-9cr)metered |
| List Facebook page posts | /v1/facebook/profile/posts | standard (1-4cr)metered |
| List Facebook profile reels | /v1/facebook/profile/reels | standard (1cr) |
| Search Facebook groups by keyword | /v1/facebook/search/groups | standard (1-15cr)metered |
| Search Facebook pages by keyword | /v1/facebook/search/pages | standard (1cr) |
| Search Facebook people by keyword | /v1/facebook/search/people | standard (1cr) |
| Search Facebook posts by keyword | /v1/facebook/search/posts | standard (1-9cr)metered |
| Search Facebook videos by keyword | /v1/facebook/search/videos | standard (1cr) |
| Get Facebook Ad Library ad details | /v1/facebook/adlibrary/ad | advanced (5cr) |
| List Facebook Ad Library company ads | /v1/facebook/adlibrary/company/ads | advanced (5-35cr)metered |
| Search Facebook Ad Library | /v1/facebook/adlibrary/search/ads | advanced (5cr) |
| Search Facebook Ad Library companies | /v1/facebook/adlibrary/search/companies | advanced (5cr) |
| Facebook profile reels with exact views, likes, comments, and shares merged in, in one call. | /v1/facebook/profile/reels/full | advanced (5-25cr)metered |
| Get a Facebook Ad Library video ad transcript | /v1/facebook/adlibrary/ad/transcript | premium (10cr) |
| Get Facebook video transcript | /v1/facebook/post/transcript | premium (10cr) |
Platform notes
author.following and author.posts_count are always null. The profile upstream does not publish those totals for a Facebook page.
country takes exactly one code. Every Ad Library endpoint that accepts country accepts a single two-letter code, not a list. It defaults to ALL.
Ad Library status defaults to ACTIVE. Historical ads are excluded unless you set status explicitly, which is a common reason a competitor sweep looks emptier than expected.
trim=true on the ad endpoints. Ad Library payloads are large. The trimmed variant carries the same rows with the heavy creative metadata dropped.
Group posts come 3 to 4 at a time. The page size is small by Facebook's design, so a day's worth of a busy group is several cursor pages rather than one call. Budget 1 credit per page and loop on has_more.
Multi-photo posts return the full media_urls array, not just the first image.
Labels
These lists label their rows by default, at no extra credit. On /v1/facebook/post/comments and /v1/facebook/post/comment/replies, each comment carries sentiment, question, purchase_intent and complaint on computed.labels. On /v1/facebook/search/posts, each row carries sponsored, intent and niche. /v1/facebook/search/posts also scores each row's relevance to your query on computed.relevance, without dropping or reordering anything; add relevance=filter to drop the rows that are about something else, still free. Send judgments=off for the page without them. See Labels for the field shapes, rows still pending, and the labels you can add with label=.
Next steps
Pagination
Cursor and page walks, and what has_more actually means.
Credits
What each tier costs and when a call is refunded.
API reference
Every parameter and response field, endpoint by endpoint.
The other Meta surface, same handle-first shape.
The other ad library plus the whole B2B profile surface.
