Python SDK for Facebook and Instagram public data. Drop-in replacement for facebook-scraper. REST + MCP, 200 free API calls/month, no OAuth.
Project description
socialapis — Python SDK for Facebook + Instagram public data
The modern alternative to kevinzg/facebook-scraper
and arc298/instagram-scraper —
real-time Facebook + Instagram data via REST, no OAuth dance, no app
review, no scraper maintenance. Powered by hosted infrastructure at
socialapis.io.
pip install socialapis-sdk
from socialapis import Facebook, Instagram
fb = Facebook(api_token="...")
page = fb.get_page_info("EngenSA")
print(page.name, page.likes, page.category)
ig = Instagram(api_token="...")
profile = ig.get_profile_details("instagram")
print(profile.username, profile.followers)
Get a free API token → — 200 calls/month, no credit card
One-line migration
If your code currently uses kevinzg/facebook-scraper
or arc298/instagram-scraper, the migration is
literally one import line:
# Before — kevinzg/facebook-scraper (abandoned since 2022)
from facebook_scraper import get_page_info, get_posts
# After — socialapis (alias preserves the name)
from socialapis import FacebookScraper
fb = FacebookScraper(api_token="...")
fb.get_page_info("EngenSA")
fb.get_page_posts("EngenSA")
# Same for Instagram
from socialapis import InstagramScraper
ig = InstagramScraper(api_token="...")
FacebookScraper and InstagramScraper are exact aliases of Facebook and Instagram —
identical behavior, identical type signatures. They exist purely to keep the import
line greppable during migration.
Why this exists
kevinzg/facebook-scraper has 9.5k+ GitHub stars and was the default Python library for
scraping Facebook for years. It's been abandoned since 2022. arc298/instagram-scraper
(8.5k stars) is in similar shape. Every Meta DOM change breaks them; fixes pile up in
unmerged PRs; downloads drift to forks that fix one bug and break two.
This SDK is the drop-in successor:
kevinzg/facebook-scraper (2018-era) |
socialapis (2026) |
|
|---|---|---|
| Maintenance | Abandoned 2022 | Active; we run prod for 7M+ calls/mo |
| Reliability | Breaks on every Meta HTML change | Hosted backend; we absorb breakage |
| Type hints | None | Strict throughout |
| Async support | No | Facebook + AsyncFacebook classes |
| HTTP client | requests |
httpx |
| Validation | Manual dict parsing | Pydantic v2 models |
| Auth | None (scrapes anonymously) | Single x-api-token header |
| Pagination | Generator with edge-case bugs | Cursor-based; API decides page size |
| Error handling | Generic exceptions | Typed hierarchy (RateLimitError, etc.) |
| CI / tests | Manual against live FB | Recorded HTTP fixtures, Python 3.10–3.13 |
| Coverage | Page posts, group posts only | 45+ endpoints across FB + IG |
The trade-off: instead of running a scraper yourself, you make a REST call to our hosted API. 200 calls/month free, no credit card. Paid plans start at $4.99/mo for 1,500 calls.
What's covered (v0.1)
Facebook (Facebook / AsyncFacebook)
Pages
get_page_id(page)— resolve a URL/slug to numeric IDget_page_info(page)→PageInfo— page metadata (typed model)get_page_posts(page)— recent postsget_page_reels(page)— short-form videosget_page_videos(page)— long-form videos
Groups
get_group_id(group)get_group_details(group)→GroupInfo(typed model)get_group_metadata(group)— lightweight metadata onlyget_group_posts(group)get_group_videos(group_id)
Posts
get_post_id(post)— extract numeric ID from URLget_post_details(post)— reactions, media, authorget_post_details_extended(post)— + views, video URLs, author verificationget_post_comments(post)— passinclude_reply_info="true"for reply cursorsget_comment_replies(comment_feedback_id, expansion_token)get_post_attachments(post_id)get_video_post_details(video_id)
Search
search_pages(query)— supportslocation_idfor geo-filteringsearch_people(query)search_locations(query)— returns location IDs for use in other endpointssearch_posts(query)— supports recency + location filterssearch_videos(query)
Meta Ads Library
get_ads_countries()— supported countriessearch_ads(query)— by keyword + country + activeStatusget_ads_page_details(page_id)get_ad_archive_details(ad_archive_id, page_id)search_ads_by_keywords(query)
Marketplace
search_marketplace(query)— supports lat/lng, price, condition filtersget_listing_details(listing_id)get_seller_details(seller_id)get_marketplace_categories()get_city_coordinates(city)— for lat/lng filteringsearch_vehicles()— bedrooms-style filters; lat/lng requiredsearch_rentals()
Media
download_media(url)— resolve to direct downloadable URL
Instagram (Instagram / AsyncInstagram)
Profiles
get_user_id(profile)— username/URL → numeric user_idget_profile_details(username)→ProfileInfo(typed model)get_profile_posts(username)get_profile_reels(user_id)get_profile_highlights(user_id)get_highlight_details(highlight_id)
Posts
get_post_id(post)— extract shortcode from any post URLget_post_details(shortcode)
Reels
get_reels_feed()— trending feedget_reels_by_audio(audio_id)— all reels using a specific track
Search + Locations
search(keyword)— popular results (users / hashtags / places)get_location_posts(location_id)— top or recentget_nearby_locations(location_id)
Account (Account / AsyncAccount)
Free calls — don't consume credits.
get_usage()— credit balance, plan, billing periodget_top_ups()— auto top-up settings + historyget_limits()— rate limit, concurrent-task cap, allowed packages
Pagination — no limit=N, just cursors
Every endpoint that returns a list lets the API decide page size. To paginate, take the cursor from the response body and pass it back as a kwarg on the next call:
fb = Facebook(api_token="...")
# First page
result = fb.get_page_posts("EngenSA")
posts = result["posts"]
cursor = result.get("next_cursor") # actual key varies by endpoint — check docs
# Next page
while cursor:
result = fb.get_page_posts("EngenSA", cursor=cursor)
posts.extend(result["posts"])
cursor = result.get("next_cursor")
We deliberately don't impose a uniform limit=N parameter — it would drift from the
API's actual semantics. The API's response always tells you whether there's more.
Forward-compat via **kwargs
Every method accepts arbitrary kwargs and forwards them as query params. If the API adds a new filter tomorrow, you can use it today — no SDK release required:
fb.search_ads("fitness", country="US", activeStatus="Active", some_new_filter="x")
# Sends: ?query=fitness&country=US&activeStatus=Active&some_new_filter=x
Error handling
import time
from socialapis import (
Facebook,
AuthenticationError, # 401 — bad token
InsufficientCreditsError, # 402 — out of credits
RateLimitError, # 429 — slow down
BadRequestError, # 4xx — bad input
APIServerError, # 5xx — retry safely
APIConnectionError, # network — retry with backoff
)
fb = Facebook(api_token="...")
try:
page = fb.get_page_info("EngenSA")
except RateLimitError as exc:
time.sleep(exc.retry_after_seconds or 5)
page = fb.get_page_info("EngenSA")
except InsufficientCreditsError:
print("Out of credits. Upgrade at https://socialapis.io/pricing")
except AuthenticationError:
print("Bad token. Get one at https://socialapis.io/auth/signup")
Every typed exception carries .status_code, .request_id, and .body for debugging.
The request_id is the same value our backend logs — paste it into a support email
and we can find the exact call.
Async
Same method surface; methods are coroutines.
import asyncio
from socialapis import AsyncFacebook
async def main():
async with AsyncFacebook(api_token="...") as fb:
pages = await asyncio.gather(*[
fb.get_page_info(slug)
for slug in ["EngenSA", "Microsoft", "GitHub"]
])
for page in pages:
print(page.name, page.followers)
asyncio.run(main())
Pricing
| Tier | Calls / month | Price |
|---|---|---|
| Free | 200 | $0 |
| Pro | 1,500 | $4.99 |
| Ultra | 30,000 | $49 |
| Mega | 120,000 | $179 |
| Enterprise | Custom | Contact us |
One credit per successful response. Failed calls (4xx caused by bad input) don't consume credits.
Other languages
- JavaScript / TypeScript — coming soon. Notify me →
- PHP — coming soon. Notify me →
- Go — coming soon. Notify me →
- Any language right now: hit the REST API directly with
curl/fetch/requests. Docs at docs.socialapis.io.
Support
- Docs: docs.socialapis.io
- Issues: github.com/SocialAPIsHub/socialapis-python/issues
- Email: support@socialapis.io
- Telegram (fastest): t.me/socialapis
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file
socialapis_sdk-0.1.0.tar.gz.File metadata
File hashes
0faad2b5435450858d14e7ec9b2cb4b6de8e85f8b3e782a3b6805dd2283d02dd9caaabef288bebcebeb96f55083745b13e401126ba2470727abee333e7fa4dccaee794733ad0621ebeab02c3f065bd19See more details on using hashes here.
Provenance
The following attestation bundles were made for
socialapis_sdk-0.1.0.tar.gz:Publisher:
Attestations: Values shown here reflect the state when the release was signed and may no longer be current.release.ymlon SocialAPIsHub/socialapis-python-
Statement type:
-
Predicate type:
-
Subject name:
-
Subject digest:
-
Sigstore transparency entry: 1912548982
- Sigstore integration time:
Source repository:https://in-toto.io/Statement/v1https://docs.pypi.org/attestations/publish/v1socialapis_sdk-0.1.0.tar.gz0faad2b5435450858d14e7ec9b2cb4b6de8e85f8b3e782a3b6805dd2283d02dd-
Permalink:
-
Branch / Tag:
-
Owner: https://github.com/SocialAPIsHub
-
Access:
Publication detail:SocialAPIsHub/socialapis-python@ff695b3d064d66392a5c2d2fead066e8d42679edrefs/tags/v0.1.0publichttps://token.actions.githubusercontent.comgithub-hostedrelease.yml@ff695b3d064d66392a5c2d2fead066e8d42679edpush