Facebook Reels Scraper - $0.35 per 1,000 Reels avatar

Facebook Reels Scraper - $0.35 per 1,000 Reels

Pricing

from $0.35 / 1,000 reels

Go to Apify Store
Facebook Reels Scraper - $0.35 per 1,000 Reels

Facebook Reels Scraper - $0.35 per 1,000 Reels

The Reels tab on a Page shows ten reels and a cursor to the rest. This follows the cursor, up to 200 per Page. Reel link, video URL, thumbnails, caption, hashtags, duration, posting time, plus counts: reactions and comments exact, views and shares rounded. $0.35/1k.

Pricing

from $0.35 / 1,000 reels

Rating

0.0

(0)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

1

Monthly active users

2 days ago

Last modified

Share

Facebook Reels Scraper

The Reels tab on a Page renders ten reels and an end cursor to the rest. This Actor follows that cursor, so a run goes as deep as 200 reels per Page instead of stopping at the tab's first screen. Public Page URLs go in, and their newest Reels come back one row each: the reel permalink, a video URL, two thumbnails, the caption with its hashtags split into their own array, the exact posting time, the length, the frame size, and the view, reaction, comment and share counts. The Page's name, id and verified flag ride along on every row.

You don't supply a login. A run reads the logged-out Reels tab first, and when Facebook answers that with a wall it falls back to an account session that ships inside the Actor. That session is shared by everyone using the Actor, so if you're pulling a long list and Pages start coming back blocked, paste your own Facebook cookie into sessionCookies and the run uses your rate limit instead of the shared one.

  • Up to 50 Pages per run, up to 200 reels from each — not just the handful the Page shows on its front tab.
  • A video URL and two thumbnails on every row.
  • Reaction and comment counts are exact integers. Views and shares are not, because Facebook only publishes those rounded — see the field notes.
  • Date filtering is a plain input field, not a paid add-on. Reels it drops are never charged.
  • Empty input returns one labelled sample row, free, so you can look at the shape before spending anything.
  • A Page that is blocked, private, misspelled or simply has no reels produces an uncharged diagnostic row. The run still finishes as succeeded.

Price

$0.35 per 1,000 reels, plus a $0.0005 start fee per run (billed per gigabyte of run memory, so exactly that at the default 1 GB).

The per-reel rate doesn't move with volume or with your Apify plan.

ReelsTotal cost
100$0.0355
1,000$0.3505
10,000$3.5005
100,000$35.0005

What is actually charged

  • One reel-scraped event per reel row written to the dataset. Nothing else is metered per row.
  • Free: the sample row an empty run returns, and every diagnostic row — a blocked target, a dead URL, a Page with no reels. Those all carry "charged": false.
  • Reels dropped by your date filter never become rows, so they are never charged.
  • Duplicate reels inside a single run are dropped before they are charged.
  • A run that finds nothing costs the start fee and nothing more.
  • Rows never leave the dataset without a charge, and are never charged without a row. The billed event is a named one — nothing is attached to apify-default-dataset-item, so error rows can't quietly bill you.

Input

{
"startUrls": [
"https://www.facebook.com/9gag",
"https://www.facebook.com/natgeo"
],
"resultsLimit": 60,
"onlyPostsNewerThan": "30 days"
}
FieldWhat it does
startUrlsPublic Facebook Page URLs, one per line. A bare handle (9gag), a Reels-tab URL, a /pg/ URL, a /p/ URL and a profile.php?id= URL all work. Up to 50 Pages per run. A single /reel/… link is not a Page and comes back as a free diagnostic row.
resultsLimitHow many recent reels to take from each Page, newest first. Default 50, maximum 200. The first ten cost one request; past that the Actor walks the Page eight reels at a time, so a big number costs more time but roughly the same per reel. Keep it low while testing — you pay per reel.
onlyPostsNewerThanOptional. Drop reels older than this. Accepts 2026-08-01, a full ISO timestamp, an epoch, or a relative window such as 7 days. Free.
onlyPostsOlderThanOptional. Drop reels newer than this. Same formats. Also free.
sessionCookiesOptional. Your own Facebook cookie, as c_user=<value>; xs=<value>, one line per account. Use it when the shared session is busy and Pages come back blocked. In Chrome: F12 → Application → Cookies → https://www.facebook.com. Treat it like a password — anyone holding it can act as that account, and Facebook may sign the session out or restrict the account for automated reading.
proxyUrlsLeave empty. Fill it in only if you want the traffic to leave through proxy servers you already pay for, as http://user:pass@host:port.

Run it with empty input and you get one clearly labelled sample row, free.

Output

One row per reel. This is a real row from a real run:

{
"ok": true,
"charged": true,
"recordType": "reel",
"inputUrl": "https://www.facebook.com/9gag",
"pageName": "9GAG",
"pageId": "100064681269092",
"pageUrl": "https://www.facebook.com/9gag/",
"pageIsVerified": true,
"pageProfilePicture": "https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=100064681269092",
"reelId": "27847866498168467",
"reelUrl": "https://www.facebook.com/reel/27847866498168467",
"postId": "1532426152256746",
"videoUrl": "https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=27847866498168467",
"thumbnailUrl": "https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=27847866498168467&get_thumbnail=1",
"previewImageUrl": "https://scontent-yyz1-1.xx.fbcdn.net/v/t15.5256-10/759017053_1030907243061362_759126857526234640_n.jpg",
"caption": "how fancy you're #9gag #foodart",
"captionLength": 31,
"hashtags": ["9gag", "foodart"],
"time": "2026-08-15T07:00:01.000Z",
"timestamp": 1786777201,
"viewCount": 586000,
"viewCountText": "586K",
"reactionsCount": 1833,
"commentsCount": 15,
"sharesCount": 33,
"sharesCountText": "33",
"durationMs": 24682,
"durationSeconds": 24.682,
"width": 1080,
"height": 1920,
"aspectRatio": 0.5625,
"audioTitle": "Esperé Eckard-Lee · Paris Carousel",
"audioIsOriginal": true,
"isReshare": false,
"isSponsored": false,
"scrapedAt": "2026-08-16T05:08:11.916Z"
}

Field notes

  • inputUrl — the Page URL you asked for, so you can group rows by Page after merging several runs.
  • reelUrl — the canonical facebook.com/reel/… permalink. This is the link to share or open in a browser.
  • videoUrl — Facebook's own public media address for the reel. It's stable rather than a signed link that expires in a few hours, so it still works in a spreadsheet you open next week. Whether it hands you the file depends on who asks: fetched with a crawler user-agent it answers video/mp4, fetched with an ordinary browser or HTTP-client user-agent it answers about 300 bytes of HTML redirecting to the watch page. curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "<videoUrl>" -o reel.mp4 works; plain curl <videoUrl> does not. The Actor never downloads the file — you're charged for the row, not the video.
  • thumbnailUrl — a stable thumbnail from the same public media endpoint. previewImageUrl is the higher-resolution first frame, on a CDN address that does expire, so copy it if you need it to last.
  • caption — the reel text exactly as posted, emoji and line breaks intact. hashtags is the same caption with the tags pulled out, without the #.
  • time — the exact posting time, ISO 8601 UTC, taken from the reel itself rather than from a "2 days ago" label. timestamp is the same moment in epoch seconds.
  • viewCount — the play count. Facebook publishes this rounded, always "586K" and never 586,214, so viewCount is that rounded figure as a number and viewCountText keeps the string so nobody mistakes it for exact.
  • reactionsCount — total reactions of all types at read time, and this one is exact. So is commentsCount. Both were present on all 1,031 rows of a coverage sample taken across several Pages. They can still be null on a reel Facebook hasn't published a counter for yet, which is usually the very newest one on a Page.
  • sharesCount — shares at read time, rounded the same way views are. sharesCountText keeps the original. Null when Facebook publishes no share count for that reel.
  • durationMs — length in milliseconds. durationSeconds is the same value with its fractional part.
  • width, height, aspectRatio — the video frame. Reels are usually 1080x1920, but Facebook accepts landscape reels too, so don't assume vertical.
  • audioTitle — the soundtrack label Facebook shows: a licensed track, or "
  • isReshare — true when the Page re-shared somebody else's reel instead of posting its own.
  • isSponsored — true when the reel is a paid placement.

Every real row carries "charged": true. Sample rows carry "_sample": true, diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.

How it works

It reads the public Reels tab of the Page and lifts the reels out of the structured data already inside that response. No headless browser, no rendering, no scrolling.

The first ten reels arrive in that one request. Beyond that the Actor follows the same paging cursor the Reels tab itself uses, eight reels per call on the same connection, so going deeper costs a little more time and no extra page loads. The engagement counters live in a different part of the same response from the reels themselves, so the read runs on until the counters for every reel found have arrived and then stops — the rest of the payload is deferred video-player state this Actor has no use for.

Traffic leaves through a large pool of rotating addresses. Facebook throttles per address, so a refusal is answered by moving to a fresh one and asking again, up to eight times per Page, with the request identity varied each time. If the logged-out path is walled from every address, the Actor tries once more with an account session — yours from sessionCookies if you supplied one, otherwise the one that ships with the Actor.

Nothing is charged until a reel row is safely in your dataset.

Where this gets used

  • Short-form content research: pull the newest reels from thirty Pages in your category every morning and sort by viewCount to see what is actually working this week.
  • Brand and competitor monitoring, with engagement numbers as plain columns instead of screenshots.
  • Creator vetting — reach, reaction rate and posting cadence for a list of Pages, in one run, before you sign anything.
  • Hook and format analysis. caption, hashtags, durationSeconds and aspectRatio together tell you what the top performers have in common.
  • Building a reel archive. reelUrl, videoUrl and thumbnailUrl on every row mean the record survives a deleted reel.
  • Feeding a dashboard or a warehouse. Rows are flat and typed, so they load without a transformation step.

Reading the output

A run writes three kinds of row:

  • Real rows carry "charged": true and "recordType": "reel". One billed event each.
  • The sample row carries "_sample": true and "charged": false. There's exactly one, and only when the input had no Page URLs.
  • Diagnostic rows carry "_diagnostic": true, "charged": false and an errorCode you can switch on: NOT_FOUND when there's no public Page at that URL, BLOCKED when Facebook served a login interstitial from every address tried, NO_REELS when the Page rendered but publishes no reels, BAD_INPUT when a URL couldn't be read as a Page, TIME_BUDGET when the run ran out of time before reaching a Page, NETWORK when Facebook couldn't be reached. Each carries the inputUrl it belongs to and a plain-English explanation.

Filter on charged == true if you only want the data. The count of those rows always equals the number of events you were billed for, so counting rows tells you what the run cost.

Limitations

  • 200 reels per Page per run is the ceiling. A Page with fewer than you asked for returns what it has — that's not an error, and you're only charged for what arrives.
  • Deep runs take longer than shallow ones. The first ten reels come back in one request and every eight after that is another, so asking 50 Pages for 200 reels each is a long run. Give it a generous timeout or split it.
  • The date filters narrow the reels a Page has published. They can't reach further back than the Page itself goes, so asking for last year on a Page that started reels in March correctly returns nothing.
  • View counts and share counts are rounded, because that's the only form Facebook publishes them in. Reaction and comment counts are exact.
  • Occasionally Facebook hasn't published any engagement counter for a brand-new reel and reactionsCount, commentsCount and sharesCount come back null for it. The reel, its caption, its view count and its media links are all still there. It's rare. It didn't happen once across the 1,031-row sample below, and the counters fill in within a day.
  • Two optional fields are often empty because the reels themselves are: hashtags when the caption has none, audioTitle when the reel carries no soundtrack label. Across a 1,031-row sample they were filled on 32% and 49% of rows. Everything else on this list was filled on 100%.
  • Not every Page has a public Reels tab. Plenty of large Pages post short video to their timeline without it ever landing under Reels, and those return an uncharged NO_REELS row rather than invented data.
  • Public Pages only. Personal profiles with a private timeline, Groups and Events are out of scope and produce an uncharged NOT_FOUND or BLOCKED row.
  • Some Pages are age-restricted or country-restricted and show a logged-out visitor nothing. Those return an uncharged diagnostic row, and retrying doesn't change it.
  • Comments themselves are not returned, only the count. Same for the identities of people who reacted.
  • All the counts are a snapshot at read time and keep moving on a live reel.
  • videoUrl points at a public Facebook media address. It is not a licence — what you may do with somebody else's video is between you and them.
  • Facebook throttles per address. Under heavy parallel load a Page can come back BLOCKED; re-running a few minutes later normally clears it, and nothing is charged for the attempt.
  • Captions are returned as posted. They are not translated.

Questions

My Page has no @username, only a numeric id. Does it work?

Yes. Paste whatever Facebook shows you — facebook.com/profile.php?id=1000..., the facebook.com/people/Page-Name/1000.../ form, the /p/Page-Name-1000.../ form, or just the number. All four read the same Page, with the same fields and the same pagination as a Page with a custom URL.

Do I have to supply a Facebook account or cookies?

No. Every run works with sessionCookies empty. Pages are read logged out first, and when Facebook walls that the Actor uses the account session it ships with. Supplying your own is only worth it when the shared one is busy and you want a rate limit nobody else touches. Either way, private content stays out of reach.

How many reels can I get from one Page?

Up to 200 per run, set with resultsLimit. The default is 50. Lower it to 10 if you only want the newest few and want the cheapest possible run. Running on a schedule and deduplicating on reelId builds deep history over time, one cheap run at a time.

Why is the view count rounded but the reaction count exact?

That's how Facebook publishes them. The reels surface ships plays as a display string like "586K" and ships reactions and comments as real integers. viewCount is that string parsed into a number for you, and viewCountText keeps the original so the rounding is never hidden.

Is videoUrl a real download link?

It's Facebook's own public media address for the reel, and it's stable rather than signed. Whether it hands over the file depends on the user-agent — crawler identity gets video/mp4, browser identity gets a ~300-byte HTML redirect. See the field note above for the exact curl line. The Actor never fetches the video itself.

What happens if a Page has no reels?

One uncharged NO_REELS row for that Page, the run carries on to your other Pages, and you're billed nothing for it.

Does the date filter cost extra?

No. It runs before anything is billed, and reels it removes are never charged. Filtering to last week is strictly cheaper than not filtering.

Will the run fail if something goes wrong?

No. A blocked, empty or broken target produces an uncharged diagnostic row and the run finishes as succeeded. A failed run would still bill the start fee, and charging you for bad news about a bad URL isn't reasonable.

Can I run this on a schedule?

Yes, and that's the intended way to use it. No state carries over from one run to the next. Schedule the same Page list daily and deduplicate on reelId to see only what's new.

Do I need to supply a proxy?

No. The run brings its own egress and that cost is already inside the price. proxyUrls exists only for callers who specifically want traffic to leave through servers they own.