SocialCrawl

Facebook

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
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
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

EndpointCreditsWhat it returnsKey parameters
GET /v1/facebook/profile1Page identity, category, contact details, and the page idurl, get_business_hours
GET /v1/facebook/profile/full5The page, its recent posts, and computed analytics in one flat callurl, posts (1-100, default 25), include
GET /v1/facebook/profile/posts1The page's recent posts, cursor-pagedurl or pageId, cursor
GET /v1/facebook/profile/events1One page's own upcoming and past eventsurl, 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

EndpointCreditsWhat it returnsKey parameters
GET /v1/facebook/post1One post in full, including the reactions breakdownurl, get_comments, get_transcript
GET /v1/facebook/post/comments1The comment list, walked by cursorurl or feedback_id, cursor, label, judgments
GET /v1/facebook/post/comment/replies1One reply threadfeedback_id and expansion_token, label, judgments
GET /v1/facebook/post/transcript10The spoken words of a video post, from Facebook's own captionsurl

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

EndpointCreditsWhat it returnsKey parameters
GET /v1/facebook/profile/photos1A page's gallery: photo id, permalink, full-size image, thumbnailurl, next_page_id
GET /v1/facebook/profile/reels1The cheap reel list, with the rounded public view counturl, next_page_id
GET /v1/facebook/profile/reels/full5 to 25The same list with exact per-reel engagement merged inurl, 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

EndpointCreditsWhat it returnsKey parameters
GET /v1/facebook/group1Group identity: name, description, member count, privacyurl or group_id
GET /v1/facebook/group/posts1That group's posts with reaction, comment, and share countsurl 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

EndpointCreditsWhat it returnsKey parameters
GET /v1/facebook/events1What is on in a place, from a city's Facebook Events page URLurl, time, cursor
GET /v1/facebook/events/search1The public directory searched by keywordquery, cursor
GET /v1/facebook/event/details1Description, start and end times, host, and RSVP countsid 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

EndpointCreditsWhat it returnsKey parameters
GET /v1/facebook/marketplace/location/search1A city or area name turned into a lat/lng pairquery
GET /v1/facebook/marketplace/search1Listings near those coordinatesquery, lat, lng, all required, plus radius_km, min_price, max_price, condition, delivery_method, date_listed, availability, sort_by
GET /v1/facebook/marketplace/item1One listing in fullid or url

Marketplace search is geographic, not textual, which is why the coordinate lookup comes first.

cURL
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

EndpointCreditsWhat it returnsKey parameters
GET /v1/facebook/adlibrary/search/companies5An advertiser name turned into a pageIdquery
GET /v1/facebook/adlibrary/company/ads5Everything that page is runningpageId or companyName, country, status, media_type, language, sort_by, start_date, end_date
GET /v1/facebook/adlibrary/search/ads5Ad copy searched by keyword across every advertiserquery, search_type, ad_type, country, status, media_type
GET /v1/facebook/adlibrary/ad5One ad expanded into creative, spend, impressions, and targetingid or url, trim
GET /v1/facebook/adlibrary/ad/transcript10What a video ad says out loudid 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.

EndpointPathCredit Tier
Get details for a Facebook event/v1/facebook/event/detailsstandard (1cr)
List Facebook events for a city/v1/facebook/eventsstandard (1-13cr)metered
Search Facebook events by keyword/v1/facebook/events/searchstandard (1cr)
Get a Facebook group/v1/facebook/groupstandard (1cr)
List Facebook group posts/v1/facebook/group/postsstandard (1cr)
Get a Facebook Marketplace item/v1/facebook/marketplace/itemstandard (1cr)
Search Facebook Marketplace locations/v1/facebook/marketplace/location/searchstandard (1cr)
Search Facebook Marketplace listings/v1/facebook/marketplace/searchstandard (1cr)
Get Facebook post details/v1/facebook/poststandard (1cr)
List replies to a Facebook post comment/v1/facebook/post/comment/repliesstandard (1-5cr)metered
List Facebook post comments/v1/facebook/post/commentsstandard (1-5cr)metered
Get Facebook page profile/v1/facebook/profilestandard (1cr)
List a Facebook page's events/v1/facebook/profile/eventsstandard (1-9cr)metered
Facebook profile, recent posts, and computed analytics in one call./v1/facebook/profile/fullstandard (5cr)
List Facebook profile photos/v1/facebook/profile/photosstandard (1-9cr)metered
List Facebook page posts/v1/facebook/profile/postsstandard (1-4cr)metered
List Facebook profile reels/v1/facebook/profile/reelsstandard (1cr)
Search Facebook groups by keyword/v1/facebook/search/groupsstandard (1-15cr)metered
Search Facebook pages by keyword/v1/facebook/search/pagesstandard (1cr)
Search Facebook people by keyword/v1/facebook/search/peoplestandard (1cr)
Search Facebook posts by keyword/v1/facebook/search/postsstandard (1-9cr)metered
Search Facebook videos by keyword/v1/facebook/search/videosstandard (1cr)
Get Facebook Ad Library ad details/v1/facebook/adlibrary/adadvanced (5cr)
List Facebook Ad Library company ads/v1/facebook/adlibrary/company/adsadvanced (5-35cr)metered
Search Facebook Ad Library/v1/facebook/adlibrary/search/adsadvanced (5cr)
Search Facebook Ad Library companies/v1/facebook/adlibrary/search/companiesadvanced (5cr)
Facebook profile reels with exact views, likes, comments, and shares merged in, in one call./v1/facebook/profile/reels/fulladvanced (5-25cr)metered
Get a Facebook Ad Library video ad transcript/v1/facebook/adlibrary/ad/transcriptpremium (10cr)
Get Facebook video transcript/v1/facebook/post/transcriptpremium (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