How to export Facebook group members with pagination
Every Facebook group scraping task eventually hits the same wall: the member list is paginated in small pages, and naive collection loses people at the seams. This guide shows the exact protocol we use in production at GetSocialAPI — the same one the group members endpoint implements.
The endpoint
GET /fb/members/all/{group_id}?after=<cursor>
One page holds a fixed batch of 15 members — the size is set by the
upstream and there is no count knob. The response carries three things
you care about:
data.group.new_member_list.edges[]— member nodes of this pagedata.group.new_member_list.page_info.end_cursor— the cursor to the next pagedata.group.new_member_list.page_info.has_next_page— your loop condition
To resolve a group from its URL (facebook.com/groups/800246542990860)
use the resolve endpoint first, or pass the numeric id directly.
The walking loop
from getsocialapi_facebook import Client
fb = Client(api_key="gsa_live_...").facebook
members, cursor = [], None
while True:
page = fb.members("800246542990860", after=cursor)
conn = page["data"]["group"]["new_member_list"]
members += [e["node"] for e in conn["edges"]]
if not conn["page_info"].get("has_next_page"):
break
cursor = conn["page_info"]["end_cursor"]
print(len(members), "members exported")
Three rules that make this loop lossless:
- Pass the cursor verbatim.
end_cursoris a long base64 string; copy it as-is intoafter. Never try to decode or slice it — cursors are opaque and session-independent, but only whole. - Loop on
has_next_page, not on counting. Page size can wobble by one node at seam boundaries; the flag is the source of truth. - Deduplicate by node id if you re-run the walk — Facebook occasionally reshuffles members between pages while you paginate (joins/leaves happen live).
What a member node looks like
Each edge carries node.name, node.id, node.profile_picture and —
for searchable lists — a node.subtitle with the city. Business
accounts may include job_history entries.
Errors that matter
| HTTP | Meaning |
|---|---|
400 Invalid Cursor | you mangled or reused a cursor from another group — restart from page 1 |
404 | group id does not exist or the group is hidden |
429 | you exceeded your plan RPS — back off for Retry-After seconds |
Failed calls (everything except 200/404) are not billed — a safe property of the whole GetSocialAPI billing model.
Takeaways
Full group export is a solved problem if you respect the cursor
protocol: fixed pages, has_next_page as the loop condition, verbatim
cursors, dedupe on re-runs. The Python walker above is ~10 lines and
exports groups of any size. Open an account — the first 100 calls are
free — and try it on your own group id.
Build with GetSocialAPI
Explore Facebook API for capabilities, pricing and integration examples. Create an account to start with 100 free calls, or follow the quickstart.