Facebook Page Posts Scraper: Media OCR Extraction avatar

Facebook Page Posts Scraper: Media OCR Extraction

Pricing

Pay per usage

Go to Apify Store
Facebook Page Posts Scraper: Media OCR Extraction

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

Scrapier

Maintained by Community

Actor stats

0

Bookmarked

42

Total users

3

Monthly active users

5 days ago

Last modified

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) and videoVariants[] (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, or all)
  • Restricts the sweep to a posting window with postedFrom / postedUntil (absolute dates or relative like 7 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 TypeExtracted FieldsPrimary Use Case
Postpost_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, profileUrlContent inventory and engagement analysis
Harvested mediaimages[] (uri, width, height, ocrText), imageVariants[] (uri, width, height), videoVariants[] (quality, uri)Creative harvesting, asset export, ML/OCR pipelines
Attachment contextimage, 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_urlUnderstanding shares, reposts and linked events
Page summaryrecordType, profileUrl, postsCollected, maxPostsPerProfile, startDate, endDate, errorPer-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.

FeatureFacebook Graph API (Pages API)Facebook Page Posts Scraper: Media OCR Extraction
Access setupRegistered Meta app + App Review approval for Page Public Content AccessNo account, app, or review — supply a page URL or handle
Pages you can queryOnly pages you administer, until App Review is approvedAny public Facebook page
Image size variantsAttachment media objects; no full ladder of size variants per callimageVariants[]: every size, full-res to thumbnail
Video URL variantsVideo fields per endpoint/permissionvideoVariants[]: HD/SD/stable + thumbnail
On-image textNot extractedimages[].ocrText via in-container OCR (opt-in)
Date filteringsince / until on feed endpointspostedFrom / postedUntil, absolute or relative
OutputPaginated JSON per callOne 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?

  1. 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).
  2. 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.
  3. 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).
  4. Start the run. It connects over Apify residential proxy by default and streams each scanned post to the dataset live.
  5. 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.

ParameterRequiredTypeDescriptionExample Value
pagesToHarvestNoarrayOne 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/"]
postsToScanNointegerDepth of the media sweep — how many recent posts to open per page (1–5000). Default 20.20
includeMediaNobooleanEnrich each post with images, imageVariants and videoVariants. Turn off for a lean text-only crawl. Default true.true
mediaTypeNostringNarrow the harvest to one asset kind: image, video, or all. Default all."image"
ocrNobooleanRun in-container OCR (tesseract) over harvested images and write results to images[].ocrText. Best-effort. Default false.true
postedFromNostringLower time bound — a calendar date or relative value like 7 days / 2 weeks. Empty means no start bound."7 days"
postedUntilNostringUpper time bound — a calendar date or relative value like 0 days. Empty means no end bound."0 days"
proxyConfigurationNoobjectApify 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[].ocrText to 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, and reactions/comments_count across 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 requests
ACTOR_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.

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.