Facebook Page Posts Scraper: Media OCR Extraction
Pricing
Pay per usage
Facebook Page Posts Scraper: Media OCR Extraction
Retrieve posts from public Facebook pages with complete metadata. Supports analytics, sentiment research, and reporting with consistent and ready-to-use structured data.
Pricing
Pay per usage
Rating
5.0
(1)
Developer
Scrapier
Maintained by CommunityActor stats
0
Bookmarked
42
Total users
3
Monthly active users
5 days ago
Last modified
Categories
Share
Facebook Page Posts Scraper — Images, Video URLs and OCR Text
Facebook Page Posts Scraper: Media OCR Extraction pulls public posts from any Facebook page and harvests their media — full-resolution images, every image size variant, video URL variants and thumbnails — plus post text, timestamps, author details and engagement counts. It can also run in-container OCR to read text printed on post images. Every response is structured JSON, ready to pass to an LLM, load into a vector store, or feed a monitoring pipeline. Point it at a page and start pulling post and media data in minutes.
What is Facebook Page Posts Scraper: Media OCR Extraction?
Facebook Page Posts Scraper: Media OCR Extraction is an Apify Actor that reads the public timeline of one or more Facebook pages and returns each post as a JSON row, enriched with its harvested media. Its signature capability is on-image OCR: when enabled, it runs tesseract inside the Actor's own container against each post's images and writes the recognized words to images[].ocrText — a field most Facebook post scrapers don't expose at all. The Actor runs logged-out over Apify residential proxies, so no Facebook account, cookies, or login is required.
- Returns full post text, timestamps, author, and reaction/comment/reshare counts for every scanned post
- Harvests
images[],imageVariants[](every size variant, full-res to thumbnail) andvideoVariants[](HD/SD/stable URLs plus thumbnail) as URLs and metadata only — no assets are downloaded to storage - Runs opt-in, in-container OCR (tesseract) to extract on-image text into
images[].ocrText - Filters the harvest to one asset kind with
mediaType(image,video, orall) - Restricts the sweep to a posting window with
postedFrom/postedUntil(absolute dates or relative like7 days) - Scans up to 5000 recent posts per page via
postsToScan
What data can you get with Facebook Page Posts Scraper: Media OCR Extraction?
The Actor returns two kinds of dataset rows — one post row per scanned post (with its harvested media), and one page summary row per page — and every post row can carry OCR text when ocr is enabled.
| Result Type | Extracted Fields | Primary Use Case |
|---|---|---|
| Post | post_id, type, url, message, postCreatedAt, postCreatedAtUnix, author (id, name, url, profile_picture_url), reactions_count, comments_count, reshare_count, reactions (like, love, haha, wow, sad, angry, care), scrapedAt, profileUrl | Content inventory and engagement analysis |
| Harvested media | images[] (uri, width, height, ocrText), imageVariants[] (uri, width, height), videoVariants[] (quality, uri) | Creative harvesting, asset export, ML/OCR pipelines |
| Attachment context | image, video (id, uri), album_preview (count, images), video_files, video_thumbnail, external_url, attached_event (id, name, url), attached_post (post_id, url, message), attached_post_url | Understanding shares, reposts and linked events |
| Page summary | recordType, profileUrl, postsCollected, maxPostsPerProfile, startDate, endDate, error | Per-page run accounting and error tracking |
On-image OCR text extraction
When ocr is set to true, the Actor runs tesseract (via pytesseract) inside its own container against every harvested photo — no external OCR API and no image is ever uploaded elsewhere for recognition. For each entry in images[] (up to the first 10 images per post), it downloads the image bytes in memory, runs pytesseract.image_to_string, and writes the cleaned result to ocrText. This is genuinely useful for reading text baked into promo graphics, flyers, quote cards, and price/announcement banners that a page posts as an image rather than as post text. It is explicitly best-effort: if tesseract can't read usable text from an image, ocrText is null — the Actor never fabricates a guess.
{"uri": "https://scontent.xx.fbcdn.net/v/…_2048.jpg","width": 2048,"height": 1536,"ocrText": "MATCHDAY\nKICKOFF 20:00"}
Image and video variant harvesting
Alongside the primary images[] array, imageVariants[] collects every distinct image-size variant Facebook's own payload exposes for a post — from full-resolution down to thumbnail — and videoVariants[] collects every playable video URL quality (HD, SD, "stable", browser-native) plus the video's thumbnail as a labeled quality/uri pair. Use this when you need the exact source-resolution asset for reprint, or a lightweight thumbnail for a preview grid, without re-deriving sizes yourself.
How does Facebook Page Posts Scraper: Media OCR Extraction differ from the official Facebook API?
Meta's own Graph API can return page posts, but only after your app clears App Review for the Page Public Content Access feature — and until then it only sees pages you personally administer. Facebook Page Posts Scraper: Media OCR Extraction skips that setup entirely and reads any public page directly.
| Feature | Facebook Graph API (Pages API) | Facebook Page Posts Scraper: Media OCR Extraction |
|---|---|---|
| Access setup | Registered Meta app + App Review approval for Page Public Content Access | No account, app, or review — supply a page URL or handle |
| Pages you can query | Only pages you administer, until App Review is approved | Any public Facebook page |
| Image size variants | Attachment media objects; no full ladder of size variants per call | imageVariants[]: every size, full-res to thumbnail |
| Video URL variants | Video fields per endpoint/permission | videoVariants[]: HD/SD/stable + thumbnail |
| On-image text | Not extracted | images[].ocrText via in-container OCR (opt-in) |
| Date filtering | since / until on feed endpoints | postedFrom / postedUntil, absolute or relative |
| Output | Paginated JSON per call | One JSON row per post, streamed live |
Use the Graph API when you manage the page and only need first-party access. Use this Actor for media and text data from public pages you don't administer, with no app-review cycle.
How to scrape Facebook with Facebook Page Posts Scraper: Media OCR Extraction?
- Open Facebook Page Posts Scraper: Media OCR Extraction on the Apify Store and click Try for free (or Start if you already have it saved).
- Add one or more pages to Facebook pages to harvest media from (
pagesToHarvest) — a full page URL or just its handle, one per line. No field is schema-required, but the run has nothing to scan without at least one page here. - Set the real query controls you need: Posts to scan per page (
postsToScan, 1–5000), Asset kind to keep (mediaType), Read on-image text (ocr), and an optional posting window (postedFrom/postedUntil). - Start the run. It connects over Apify residential proxy by default and streams each scanned post to the dataset live.
- Download the results as JSON, CSV, or Excel from the dataset, or stream them via the Apify API while the run is still going.
{"pagesToHarvest": ["https://www.facebook.com/RealMadrid/"],"postsToScan": 20,"mediaType": "image","ocr": true}
How to run multiple queries in one job
pagesToHarvest accepts a plain list — add as many page URLs or handles as you want, one per line, and the Actor scans them all in the same run, pushing a page_summary row after each page finishes. There's no separate batch parameter; the array itself is the batching mechanism, and every page uses the same postsToScan, mediaType, ocr, and date-window settings for that run.
⬇️ Input
All 8 parameters are optional — the input schema requires none of them, though pagesToHarvest is what actually gives the run something to scan.
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
pagesToHarvest | No | array | One page per line: a full Facebook page URL or bare handle. Every post on these pages is scanned for media. | ["https://www.facebook.com/RealMadrid/"] |
postsToScan | No | integer | Depth of the media sweep — how many recent posts to open per page (1–5000). Default 20. | 20 |
includeMedia | No | boolean | Enrich each post with images, imageVariants and videoVariants. Turn off for a lean text-only crawl. Default true. | true |
mediaType | No | string | Narrow the harvest to one asset kind: image, video, or all. Default all. | "image" |
ocr | No | boolean | Run in-container OCR (tesseract) over harvested images and write results to images[].ocrText. Best-effort. Default false. | true |
postedFrom | No | string | Lower time bound — a calendar date or relative value like 7 days / 2 weeks. Empty means no start bound. | "7 days" |
postedUntil | No | string | Upper time bound — a calendar date or relative value like 0 days. Empty means no end bound. | "0 days" |
proxyConfiguration | No | object | Apify Proxy (default, residential IPs only) or your own proxy URLs with residential fallback. | {"useApifyProxy": true} |
Example JSON input
{"pagesToHarvest": ["https://www.facebook.com/RealMadrid/", "nasa"],"postsToScan": 30,"includeMedia": true,"mediaType": "all","ocr": true,"postedFrom": "30 days","postedUntil": "0 days","proxyConfiguration": { "useApifyProxy": true }}
Pitfall to avoid: ocr only touches entries already inside images[], and images[] is only populated when mediaType is image or all. Setting ocr: true together with mediaType: "video" runs a video-only harvest and never populates images[], so no OCR text is produced — set mediaType to "image" or "all" whenever ocr is on.
⬆️ Output
Results are typed, normalized JSON with a consistent schema across runs, downloadable as JSON, CSV, Excel, or other formats Apify's dataset export supports. Only post rows are billed under the row_result charged event — page_summary rows are pushed uncharged, so a dataset filter of recordType = "post" isolates exactly what you're billed for.
Scraped results
[{"recordType": "post","post_id": "1234567890123456","type": "photo","url": "https://www.facebook.com/RealMadrid/posts/1234567890123456","message": "Matchday is here! 💪","postCreatedAt": "2026-07-20T18:30:00Z","postCreatedAtUnix": 1784666200,"comments_count": 340,"reactions_count": 12000,"reshare_count": 55,"reactions": { "like": 8000, "love": 3000, "haha": 0, "wow": 0, "sad": 0, "angry": 0, "care": 0 },"author": {"id": "104958736210001","name": "Real Madrid C.F.","url": "https://www.facebook.com/RealMadrid/","profile_picture_url": "https://scontent.xx.fbcdn.net/v/…profile.jpg"},"image": { "uri": "https://scontent.xx.fbcdn.net/v/…_2048.jpg", "height": 1536, "width": 2048 },"images": [{ "uri": "https://scontent.xx.fbcdn.net/v/…_2048.jpg", "width": 2048, "height": 1536, "ocrText": "MATCHDAY\nKICKOFF 20:00" }],"imageVariants": [{ "uri": "https://scontent.xx.fbcdn.net/v/…_2048.jpg", "width": 2048, "height": 1536 },{ "uri": "https://scontent.xx.fbcdn.net/v/…_720.jpg", "width": 720, "height": 540 }],"videoVariants": [],"video": { "id": "", "uri": "" },"album_preview": { "count": 1, "images": [{ "uri": "https://scontent.xx.fbcdn.net/v/…_2048.jpg", "height": 1536, "width": 2048 }] },"video_files": {},"video_thumbnail": { "uri": "https://scontent.xx.fbcdn.net/v/…_2048.jpg", "height": 1536, "width": 2048 },"external_url": null,"attached_event": { "id": "", "name": "", "url": "" },"attached_post": { "post_id": "", "url": "", "message": "" },"attached_post_url": "","scrapedAt": "2026-07-25T09:12:44Z","profileUrl": "https://www.facebook.com/RealMadrid/"},{"recordType": "post","post_id": "1234567890123457","type": "video","url": "https://www.facebook.com/RealMadrid/posts/1234567890123457","message": "Behind the scenes from training 🎥","postCreatedAt": "2026-07-19T14:05:00Z","postCreatedAtUnix": 1784563500,"comments_count": 210,"reactions_count": 9400,"reshare_count": 40,"reactions": { "like": 6200, "love": 2900, "haha": 100, "wow": 200, "sad": 0, "angry": 0, "care": 0 },"author": {"id": "104958736210001","name": "Real Madrid C.F.","url": "https://www.facebook.com/RealMadrid/","profile_picture_url": "https://scontent.xx.fbcdn.net/v/…profile.jpg"},"image": null,"images": [],"imageVariants": [],"videoVariants": [{ "quality": "hd", "uri": "https://video.xx.fbcdn.net/v/…hd.mp4" },{ "quality": "sd", "uri": "https://video.xx.fbcdn.net/v/…sd.mp4" },{ "quality": "thumbnail", "uri": "https://scontent.xx.fbcdn.net/v/…thumb.jpg" }],"video": { "id": "987654321", "uri": "https://video.xx.fbcdn.net/v/…hd.mp4" },"album_preview": null,"video_files": { "hd": "https://video.xx.fbcdn.net/v/…hd.mp4", "sd": "https://video.xx.fbcdn.net/v/…sd.mp4" },"video_thumbnail": { "uri": "https://scontent.xx.fbcdn.net/v/…thumb.jpg", "height": 360, "width": 640 },"external_url": null,"attached_event": { "id": "", "name": "", "url": "" },"attached_post": { "post_id": "", "url": "", "message": "" },"attached_post_url": "","scrapedAt": "2026-07-25T09:12:47Z","profileUrl": "https://www.facebook.com/RealMadrid/"},{"recordType": "post","post_id": "1234567890123458","type": "photo","url": "https://www.facebook.com/RealMadrid/posts/1234567890123458","message": "New kit drop 🔥 link in bio","postCreatedAt": "2026-07-18T09:00:00Z","postCreatedAtUnix": 1784473200,"comments_count": 88,"reactions_count": 5100,"reshare_count": 12,"reactions": { "like": 3800, "love": 1200, "haha": 0, "wow": 100, "sad": 0, "angry": 0, "care": 0 },"author": {"id": "104958736210001","name": "Real Madrid C.F.","url": "https://www.facebook.com/RealMadrid/","profile_picture_url": "https://scontent.xx.fbcdn.net/v/…profile.jpg"},"image": { "uri": "https://scontent.xx.fbcdn.net/v/…kit_2048.jpg", "height": 1600, "width": 2048 },"images": [{ "uri": "https://scontent.xx.fbcdn.net/v/…kit_2048.jpg", "width": 2048, "height": 1600, "ocrText": null }],"imageVariants": [{ "uri": "https://scontent.xx.fbcdn.net/v/…kit_2048.jpg", "width": 2048, "height": 1600 },{ "uri": "https://scontent.xx.fbcdn.net/v/…kit_540.jpg", "width": 540, "height": 422 }],"videoVariants": [],"video": { "id": "", "uri": "" },"album_preview": { "count": 1, "images": [{ "uri": "https://scontent.xx.fbcdn.net/v/…kit_2048.jpg", "height": 1600, "width": 2048 }] },"video_files": {},"video_thumbnail": { "uri": "https://scontent.xx.fbcdn.net/v/…kit_2048.jpg", "height": 1600, "width": 2048 },"external_url": null,"attached_event": { "id": "", "name": "", "url": "" },"attached_post": { "post_id": "", "url": "", "message": "" },"attached_post_url": "","scrapedAt": "2026-07-25T09:12:51Z","profileUrl": "https://www.facebook.com/RealMadrid/"},{"recordType": "page_summary","profileUrl": "https://www.facebook.com/RealMadrid/","postsCollected": 20,"maxPostsPerProfile": 20,"startDate": "30 days","endDate": "0 days","error": null}]
How can I use the data extracted with Facebook Page Posts Scraper: Media OCR Extraction?
- Content and creative research teams: pull every image and video URL from a competitor's or partner's page over a date window, and read
images[].ocrTextto catalog which posts carry promo copy, price call-outs, or event dates baked into the graphic — without opening each image by hand. - Brand monitoring teams: track
message,postCreatedAt, andreactions/comments_countacross a watchlist of pages to catch new creative, campaign language, or engagement spikes as soon as a page posts. - AI engineers and LLM developers: have an agent issue a page query, receive structured JSON (post text, media URLs, and OCR'd image text) back, and pass it as grounded context to a model — for summarization, classification, or a retrieval index over a brand's visual content.
- Competitive analysis: compare posting cadence, media mix (photo vs. video share), and engagement counts across a set of competitor pages to spot which formats and messages are performing.
How do you monitor on-image messaging over time?
Monitoring on-image messaging means re-running the same page list on a schedule and diffing what's new — new posts, new media, and new text baked into those media's images — rather than reading a single snapshot. Because postedFrom / postedUntil accept relative values like 7 days, a scheduled run can always look back over a rolling window, so each run only returns what's new since the last one. The fields worth diffing between runs are post_id (to detect genuinely new posts), images[].ocrText (to catch new promotional or announcement graphics, since the same visual template with different copy still produces different OCR text), postCreatedAt, and reactions_count/comments_count (to see which new posts are gaining traction).
A practical workflow: schedule a run every few days across a fixed set of page URLs with ocr on and postedFrom set to a rolling window (e.g. 7 days); after each run, compare the set of post_id values and images[].ocrText strings against the previous run's dataset; alert when a new post appears whose OCR'd image text contains a tracked keyword (a sale, a launch date, a price). Facebook Page Posts Scraper: Media OCR Extraction has no built-in alerting of its own — pair the run with Apify's Scheduler (cron-based recurring runs) and either poll the dataset via the API or attach a webhook on the run's completion event to trigger your own diff-and-alert logic.
Integrate Facebook Page Posts Scraper: Media OCR Extraction and automate your workflow
Facebook Page Posts Scraper: Media OCR Extraction works with any language or tool that can send an HTTP request, through the standard Apify API.
REST API with Python
import requestsACTOR_ID = "Scrapier~facebook-page-posts-scraper-media-ocr-extraction"TOKEN = "YOUR_APIFY_TOKEN"resp = requests.post(f"https://api.apify.com/v2/acts/{ACTOR_ID}/run-sync-get-dataset-items?token={TOKEN}",json={"pagesToHarvest": ["https://www.facebook.com/RealMadrid/"],"postsToScan": 20,"ocr": True,},)posts = resp.json()for post in posts:if post.get("recordType") == "post":print(post["post_id"], post.get("images", []))
MCP for query-grounded AI agents
Facebook Page Posts Scraper: Media OCR Extraction is reachable through Apify's official Actors MCP Server, which exposes any Apify Actor as a callable tool:
APIFY_TOKEN=your_token npx -y @apify/actors-mcp-server --actors Scrapier/facebook-page-posts-scraper-media-ocr-extraction
An MCP-aware client (Claude, or any MCP-compatible agent framework) can then call the Actor as a tool: the agent sends a page list, waits for the run, and receives back structured JSON — including OCR'd image text — to ground its answer instead of guessing.
Scheduled monitoring and delivery
Use Apify's Console Schedules to run this Actor on a cron interval against the same page list, and either poll the dataset through the API after each run or attach a Webhook on the run's SUCCEEDED event to push results to your own endpoint as soon as a run finishes.
Is it legal to scrape Facebook page posts?
Scraping publicly accessible Facebook page posts is generally lawful — courts have found that accessing data a site makes available to any visitor, without a login, does not itself violate anti-hacking law (hiQ Labs v. LinkedIn, 9th Cir., 2019). This Actor only returns what any visitor to a public page can already see; it never bypasses a login wall or private setting. That said, author names, profile IDs, and profile pictures in author can be personal data under GDPR and CCPA, so reusing them at scale carries different obligations than a one-off lookup — and training an AI model on the data carries a different risk profile than short-term monitoring. Not legal advice — consult your legal team for bulk storage or re-publication.
Frequently asked questions
Does Facebook Page Posts Scraper: Media OCR Extraction require a Facebook login?
No. It runs logged-out over Apify residential proxies and reads only public page content — no cookies, session tokens, or Facebook account are needed.
How does the OCR text extraction actually work?
It runs tesseract, an open-source OCR engine, inside the Actor's own container via the pytesseract Python binding — there is no external OCR API call. When ocr is true, the Actor downloads each harvested image's bytes in memory (up to the first 10 images per post), runs pytesseract.image_to_string on it, and writes the cleaned text to images[].ocrText. If tesseract can't extract readable text, or the tesseract binary isn't available, ocrText is null — it is never fabricated or guessed.
Does Facebook Page Posts Scraper: Media OCR Extraction extract on-image text from every post image?
Only when ocr is set to true, and only for images already present in images[] — which requires mediaType to be image or all. OCR is applied to the first 10 images per post; any images beyond that are still returned in images[] but without ocrText.
How many posts does Facebook Page Posts Scraper: Media OCR Extraction return per page?
Up to postsToScan recent posts per page, capped at 5000 by the input schema (default 20). If a posting-date window is set via postedFrom/postedUntil, only posts inside that window count toward what's returned, so the actual number can be lower than the cap.
Can I filter posts by a date range?
Yes. postedFrom and postedUntil accept either an absolute calendar date or a relative value like 7 days or 2 weeks. Leave either empty to scan without that bound.
Can I keep only images or only videos?
Yes, via mediaType: set it to image to keep only images[]/imageVariants[], video to keep only videoVariants[], or leave it at the default all to keep both.
How do I scrape multiple Facebook pages in a single run?
Add every page URL or handle to pagesToHarvest, one per line — the Actor scans them all in the same run and pushes a page_summary row after each page.
How do I use Facebook Page Posts Scraper: Media OCR Extraction to monitor a page's media over time?
Schedule recurring runs against the same page list with a rolling postedFrom window (e.g. 7 days) and ocr on, then diff post_id and images[].ocrText between runs to spot new posts and new on-image messaging. Apify's Scheduler handles the recurring run; a webhook on run completion can trigger your own comparison logic.
Does Facebook Page Posts Scraper: Media OCR Extraction work with Claude, ChatGPT, and AI agent frameworks?
Yes. It's reachable through Apify's Actors MCP Server (npx -y @apify/actors-mcp-server --actors Scrapier/facebook-page-posts-scraper-media-ocr-extraction) for MCP-aware clients, and callable as a plain HTTP endpoint by any agent framework that can send a request and parse JSON.
Can I use Facebook Page Posts Scraper: Media OCR Extraction without managing proxies myself?
Yes. It connects over Apify's residential proxy pool by default, so you don't need to source or rotate proxies yourself; you can still supply your own proxy URLs in proxyConfiguration, and the run falls back to Apify residential if yours doesn't work.
Your feedback
Found a bug or a field that doesn't match what's documented here? Let us know through the Actor's Issues tab on Apify or the Scrapier support contact on the Apify Store listing — reports like this go straight into fixing the Actor.

