Paste a public Facebook page, post or reel. Web Unlocker returns it with no login: a page's exact followers and latest post with its reactions, comments and shares. $0.98 per 1,000 pages.
1,000 free requests · Pay only on success · 195+ countries · Claude ready
Facebook pages take 4 to 20 seconds. It is still working, no need to click again.
Ready for your own pages? Get an API key or book a demo.
Tell us a little about your team and get:
Public pages, with no login and no Facebook account. Brand monitoring teams, agencies and sales teams read these three kinds of page, each billed as one page.



Want to try it yourself? Take your API key with 1,000 free requests.
Web Unlocker bills a Facebook page once, with its exact followers and latest post, at $0.98 per 1,000 pages. Facebook page scrapers on Apify, Bright Data and ScrapeCreators charge more for the same page.
Apify bills $12.00 per 1,000 pages.
Here 1,000 cost $0.98.
A request that fails costs nothing. When Web Unlocker is briefly unavailable, the demo above and the code samples ask again, and only the page that comes back is billed.
What 1,000 Facebook pages cost
1,000 public pages with followers and the latest post, at published prices
Gologin: $0.98 per 1,000 pages on the Growth plan. Bright Data bills each record, $1.50 per 1,000. ScrapeCreators bills each request, $1.88 per 1,000 on its $47 plan. Apify's own Facebook Pages Scraper bills $12.00 per 1,000 pages on the free plan.
Ready to run it on your own pages? Get your API key and free requests.
Our Facebook scraping test: 20 brand pages, 14 posts through Facebook's public embed and 10 reels, each asked for up to three times.
37 of 44 came back on the first try.
6 more on the second.
Facebook's Graph API, Apify's Facebook scrapers and Bright Data's Facebook Scraper API: what each bills for the same 1,000 pages, and what it asks of you before you start.
| What it takes | ||||
|---|---|---|---|---|
| You pay for | A page | Free within limits | Each result | Each record |
| 1,000 pages | $0.98 | Free | $12.00 | $1.50 |
| App review and business check | No | Yes | No | No |
| Your own Facebook account | Not needed | A Meta app | Not needed | Not needed |
| All posts of a page from its link | The latest one | After review | Yes | Yes |
| Reactions by type | Total only | Yes | Yes | Yes |
| Free to start | 1,000 requests | After app review | $5 a month | 5,000 a month |
| The whole page in HTML | Yes | No | No | No |
Scraping more than Facebook? Web Unlocker returns any page the same way, at the same price.
One request per page brings its exact followers and latest post with reactions and comments. 100 brand pages, 100 requests, $0.098.
Facebook rounds NASA to 28M followers.
The scraper returns 28,728,835.
Facebook keeps a public page's data as JSON inside its HTML. Web Unlocker returns that HTML, and a few lines of code read the page or the post out of it. The Brand pages tab is a small Facebook page scraper for a list: page names in, a CSV out.
Fill in the form above. The key arrives by email within one business day.
A page for its followers and latest post, a post or reel for its likes, comments and shares. A post goes through Facebook's public embed.
Check that the page came with data, and ask again at a fresh address when Web Unlocker was briefly unavailable.
pip install requestsGOLOGIN_SCRAPING_API_KEY=your_key python facebook_page.pyhttps://parsing.webunlocker.gologin.com/v1/scrapeimport html
import json
import os
import re
import time
from datetime import datetime, timezone
import requests
page_url = "https://www.facebook.com/NASA/"
def scrape(url, marker):
for attempt in range(3):
address = url if attempt == 0 else f"{url}?fresh={int(time.time())}"
response = requests.get(
"https://parsing.webunlocker.gologin.com/v1/scrape",
params={"url": address, "geo": "us", "format": "json"},
headers={"apikey": os.environ["GOLOGIN_SCRAPING_API_KEY"]},
timeout=90,
)
page = response.json().get("data", {}).get("html", "") if response.ok else ""
if marker in page:
return page
time.sleep(3)
raise RuntimeError("The page came back without data, try again later")
def blocks(page):
for block in re.findall(r'<script type="application/json"[^>]*>(.*?)</script>', page, re.S):
try:
yield json.loads(block)
except json.JSONDecodeError:
pass
def find(node, key):
if isinstance(node, dict):
for name, value in node.items():
if name == key:
yield value
yield from find(value, key)
elif isinstance(node, list):
for item in node:
yield from find(item, key)
def first(node, key, field):
return next(item for item in find(node, key) if isinstance(item, dict) and field in item)
page = scrape(page_url, "talking about this")
data = list(blocks(page))
meta = dict(re.findall(r'<meta property="(og:\w+)" content="([^"]*)"', page))
about = html.unescape(meta["og:description"])
count = lambda words: int(re.search(rf"([\d,]+) {words}", about).group(1).replace(",", ""))
details = first(data, "delegate_page", "category_name")
story = first(data, "timeline_list_feed_units", "edges")["edges"][0]["node"]
feedback = first(story, "feedback", "reaction_count")
facebook_page = {
"name": html.unescape(meta["og:title"]),
"followers": count("followers"),
"talking_about_this": count("talking about this"),
"category": details["category_name"],
"intro": details["best_description"]["text"],
"websites": [
item["renderer"]["context_item"]["plaintext_title"]["text"]
for item in find(data, "timeline_context_item")
if item["renderer"]["__typename"] == "WebsiteContextItemRenderer"
],
"latest_post": {
"url": next(find(story, "permalink_url")),
"date": datetime.fromtimestamp(story["creation_time"], timezone.utc).isoformat(),
"text": first(story, "message", "text")["text"],
"reactions": feedback["reaction_count"]["count"],
"comments": first(story, "comments", "total_count")["total_count"],
"shares": feedback["share_count"]["count"],
},
}
print(json.dumps(facebook_page, indent=2, ensure_ascii=False))
print(f"{facebook_page['name']}: {facebook_page['followers']:,} followers and the latest post from one page")GOLOGIN_SCRAPING_API_KEY=your_key node facebook-posts.mjshttps://parsing.webunlocker.gologin.com/v1/scrapeimport { writeFileSync } from 'node:fs';
const posts = [
'https://www.facebook.com/NASA/posts/pfbid05YJTkWebVNj83FA2ifGfHBxTdYFWuNrAMo4yAKnbRuY9XXK8nXohgsLxADToV4vfl',
'https://www.facebook.com/Starbucks/posts/pfbid02v2F2jafXiaaRi3PAramXqszA3W5rRcJtaF8MXE1s453xiHbK9JJNmMqnuzV5i8Gxl',
'https://www.facebook.com/McDonalds/posts/pfbid04kS5YA29jgtMNfHTQCf8JthvEM71jgVJzQN6L53wU7ck5ocPBY49sdFUcmt6L8Nsl',
'https://www.facebook.com/walmart/posts/pfbid02Tcu3cY8cHDhE43MsF7qSQnUDpvMZux6P7FfFsWswowv5QJTVKMeDou73PW6M5c22l',
'https://www.facebook.com/Spotify/posts/pfbid0WmiXu2TVoUdrNDBEJepHYbrukgikHR6euuvJGuLiVNtvTbXkXFywG5rEKCZcRijhl',
'https://www.facebook.com/adidas/posts/pfbid02zsJxukrC4EagRJPwg958TiWViTm9NSCPETubYgPmazax2DKqhZwaNCHBHHaXntvl',
];
const embed = (post) => `https://www.facebook.com/plugins/post.php?${new URLSearchParams({ href: post, show_text: 'true', width: '500' })}`;
async function scrape(url) {
for (let attempt = 1; attempt <= 3; attempt++) {
const address = attempt === 1 ? url : `${url}&fresh=${Date.now()}`;
const params = new URLSearchParams({ url: address, geo: 'us', format: 'json' });
const response = await fetch(`https://parsing.webunlocker.gologin.com/v1/scrape?${params}`, {
headers: { apikey: process.env.GOLOGIN_SCRAPING_API_KEY },
});
const page = response.ok ? (await response.json()).data?.html : '';
if (page?.includes('data-testid="post_message"')) return page;
await new Promise((resolve) => setTimeout(resolve, 3000));
}
return '';
}
const count = (page, name) => page.match(new RegExp(`sx_post-plugin_${name}"></i>([^<]+)<`))?.[1] ?? '';
const plain = (html = '') =>
html
.replace(/<\/p>\s*<p>|<br\s*\/?>/g, ' ')
.replace(/<[^>]+>/g, '')
.replace(/&/g, '&')
.replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(code))
.replace(/\s+/g, ' ')
.trim();
const rows = [];
for (const post of posts) {
const page = await scrape(embed(post));
const posted = page.match(/data-utime="(\d+)"/)?.[1];
rows.push({
page: plain(page.match(/<span class="_2_79 _50f7">([^<]+)<|<a title="([^"]+)" class="_5pb8|aria-label="([^"]+)" role="img"/)?.slice(1).find(Boolean)),
date: posted ? new Date(posted * 1000).toISOString().slice(0, 10) : '',
likes: count(page, 'like'),
comments: count(page, 'comment'),
shares: count(page, 'share'),
text: plain(page.match(/data-testid="post_message"[^>]*>([\s\S]*?)<\/div>/)?.[1]).slice(0, 80),
});
}
writeFileSync('posts.csv', [Object.keys(rows[0]).join(','), ...rows.map((row) => Object.values(row).map((value) => JSON.stringify(value)).join(','))].join('\n'));
console.table(rows);
console.log(`${rows.length} posts in ${rows.length} requests: $${(rows.length * 0.00098).toFixed(4)} on the Growth plan`);GOLOGIN_SCRAPING_API_KEY=your_key node facebook-pages.mjshttps://parsing.webunlocker.gologin.com/v1/scrapeimport { writeFileSync } from 'node:fs';
const pages = ['NASA', 'Starbucks', 'nike', 'netflix', 'redbull', 'LEGO'];
async function scrape(url) {
for (let attempt = 1; attempt <= 3; attempt++) {
const address = attempt === 1 ? url : `${url}?fresh=${Date.now()}`;
const params = new URLSearchParams({ url: address, geo: 'us', format: 'json' });
const response = await fetch(`https://parsing.webunlocker.gologin.com/v1/scrape?${params}`, {
headers: { apikey: process.env.GOLOGIN_SCRAPING_API_KEY },
});
const page = response.ok ? (await response.json()).data?.html : '';
if (page?.includes('talking about this')) return page;
await new Promise((resolve) => setTimeout(resolve, 3000));
}
return '';
}
const number = (text) => (text ? Number(text.replaceAll(',', '')) : '');
const rows = [];
for (const name of pages) {
const page = await scrape(`https://www.facebook.com/${name}/`);
const about = page.match(/<meta property="og:description" content="([^"]*)"/)?.[1] ?? '';
const feed = page.slice(page.indexOf('"timeline_list_feed_units"'));
const posted = feed.match(/"creation_time":(\d+)/)?.[1];
rows.push({
page: name,
followers: number(about.match(/([\d,]+) followers/)?.[1]),
talking: number(about.match(/([\d,]+) talking about this/)?.[1]),
category: page.match(/"category_name":"([^"]+)"/)?.[1].replaceAll('\\/', '/') ?? '',
posted: posted ? new Date(posted * 1000).toISOString().slice(0, 10) : '',
reactions: number(feed.match(/"reaction_count":\{"count":(\d+)/)?.[1]),
comments: number(feed.match(/"comments":\{"total_count":(\d+)/)?.[1]),
shares: number(feed.match(/"share_count":\{"count":(\d+)/)?.[1]),
});
}
writeFileSync('pages.csv', [Object.keys(rows[0]).join(','), ...rows.map((row) => Object.values(row).map((value) => JSON.stringify(value)).join(','))].join('\n'));
console.table(rows);
console.log(`${rows.length} brand pages in ${rows.length} requests: $${(rows.length * 0.00098).toFixed(4)} on the Growth plan`);Ready to run it on your own pages? Get your API key and free requests.
One account, one proxy network, one ecosystem. Pick the product the job needs.
Scraping more sites? See the Instagram, Reddit and YouTube scrapers, or every web scraping tool.
A Facebook scraper is a tool that reads public Facebook pages and turns them into data: a page's followers, category and latest post, a post's text, likes, comments and shares. Gologin Web Unlocker is a Facebook scraper API: send it a page, post or reel address and it returns the page with that data, at $0.98 per 1,000 pages.
Send the address of a public page or reel to Web Unlocker, and a post through Facebook's public embed of it. Web Unlocker returns the page as a logged-out visitor sees it, with the data inside: followers, the latest post, reactions, comments and shares. The code above reads it in a few lines and saves it as JSON or CSV.
Send the page address to Web Unlocker with the requests library and read the data from the page. The Python tab above is a complete Facebook scraper in Python, tested on the live API: it prints a page's exact followers, category, websites and latest post with its reactions.
Yes. Pages belong to brands, organizations and public figures and load for anyone, so Web Unlocker returns them, links like facebook.com/profile.php?id=... included. Personal profiles of people show little or nothing to logged-out visitors, and this scraper does not cover them.
Yes, the Graph API, with limits. Reading other Pages' public posts takes the Page Public Content Access feature, which Meta grants after App Review and business verification. The Groups API was removed in April 2024, and CrowdTangle closed in August 2024.
Yes. Public pages, posts and reels load without a login, and Web Unlocker opens them as a logged-out visitor: you need no Facebook account and put none of yours on the line. Private profiles and private groups stay closed.
Not from the page's link alone: a logged-out visitor sees the page's latest or pinned post, and Web Unlocker returns that one with exact reactions, comments and shares. For more posts, send each post's link: one post is one request, $0.98 per 1,000.
Not with this scraper. Posts inside groups do not come back through Facebook's public embed, and private groups open only to their members. This page covers pages, posts and reels; Web Unlocker returns other public pages at the same price per page, so try yours with the 1,000 free requests.
The counts, yes: a page returns its latest post's exact reactions, comments and shares, and a reel its exact reactions and comments. A post through the embed shows likes as Facebook rounds them, like 1.4K. The full list of comments loads for logged-in users.
$0.98 per 1,000 pages, the same for every page: a page with its latest post is one page, a post or a reel is one page. A request that fails costs nothing. Plans start at $49 a month for 50,000 requests.
Web Unlocker comes with 1,000 free requests, enough for 1,000 pages or posts. Open-source libraries like facebook-scraper for Python are free: they run on your own servers, often need your Facebook cookies, and keeping them working as Facebook changes is up to you.
Yes. With one skill install, Claude Code, Cursor or any MCP client reads Facebook pages through Web Unlocker. See MCP & AI Skills.
Yes. Apify's Facebook Pages Scraper bills $12.00 per 1,000 pages on its free plan, and its Facebook Posts Scraper $5.00 per 1,000 posts. Web Unlocker returns a public page with exact followers and the latest post, or a post by its link, for $0.98 per 1,000.
No. Meta's Sharing Debugger, often called the Facebook scraper, shows how your own link looks when shared on Facebook and refreshes that preview: find it at developers.facebook.com/tools/debug/. A Facebook scraper API like Web Unlocker reads data from Facebook's public pages.
Pages, posts and reels that load without a login are public pages. In Meta v. Bright Data, in January 2024, a US federal court found that Meta's terms do not bar logged-out scraping of public data. What you collect and how you use it is your call, so check it against the rules that apply to your project.
Not with Web Unlocker: it sends each request from an address in the country you pick, out of 195+, so you rent and rotate no proxies yourself. The demo above asks from the US.
Tell us a little about your team and get: