Facebook Graph API Pagination: Avoiding Rate Limits When Fetching Large Feed Collections
Learn how to safely paginate through Facebook Graph API feed collections without hitting rate limits, using cursor-based pagination and practical verification techniques.
28 Jul 2025, 13:34 UTC

The Problem: Incomplete Feed Data Due to Pagination Limits
When building an application that needs to process a user's Facebook feed, you'll quickly hit a wall: the Graph API returns only 25 posts per request by default. Fetch 1000 posts? That's 40 requests. Do it naively in a loop, and you'll trigger rate limits fast.
Understanding Cursor-Based Pagination
Facebook uses cursor-based pagination through the 'paging' object in responses. Each page includes 'next' and 'previous' URLs containing opaque cursors. Unlike offset pagination, cursors handle dynamic data better but require you to follow URLs rather than construct them.
The default limit of 25 objects per request can be increased to 100 using the 'limit' parameter, but pushing this limit increases the chance of hitting rate limits. The 'summary' object, when present, provides 'total_count' to help plan your pagination strategy.
Practical Example: Safely Iterating Through Feed Pages
Here's a curl-based approach to verify pagination mechanics:
curl -s -X GET \
'https://graph.facebook.com/v18.0/me/feed?limit=50&access_token=YOUR_APP_ACCESS_TOKEN' \
| jq '.paging, .summary.total_count'
This command fetches 50 posts and shows the paging URLs plus total count. To iterate safely:
- Start with an initial request using your desired limit (e.g., 50)
- Extract the 'next' URL from the 'paging' object
- Follow that URL for subsequent requests
- Stop when 'paging.next' is absent
- Monitor response codes for 429 (rate limit) errors
A minimal Python implementation:
import requests
import time
def fetch_all_posts(token, limit=50):
url = f'https://graph.facebook.com/v18.0/me/feed?limit={limit}&access_token={token}'
all_posts = []
while url:
response = requests.get(url)
if response.status_code == 429:
time.sleep(60) # Rate limited, wait
continue
data = response.json()
all_posts.extend(data.get('data', []))
url = data.get('paging', {}).get('next')
time.sleep(0.2) # Be kind to the API
return all_posts
Trade-offs and Limitations
Increasing the limit parameter reduces request count but increases payload size and rate limit risk. The 100-object maximum is a hard ceiling. API version deprecation means v12.0 endpoints may disappear, requiring code updates.
Rate limits are enforced per app, not per user, so aggressive pagination across multiple users can quickly exhaust your quota. Always implement exponential backoff for 429 responses.
Verification Checklist
- Run the curl command and confirm 'paging.next' appears in responses
- Check that 'summary.total_count' matches your expected item count
- Verify your loop terminates when 'next' URL is missing
- Monitor for 429 responses and implement appropriate delays
Actionable Takeaway
Always use cursor-based pagination via the provided 'next' URLs, never construct pagination URLs yourself. Start with conservative limits (25-50), implement rate limit handling, and use the 'summary.total_count' field to estimate completion. This approach prevents rate limit errors while ensuring complete data retrieval.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.