# Facebook Video Search Scraper: Reels, No Login (`automation_craft/facebook-video-search-scraper`) Actor

Search public Facebook videos and reels by keyword, #hashtag or video search link, no login, with date, reels only and place filters. Rows: views, reactions, comments, shares, video files, captions and transcripts; Video details add-on for exact plays. JSON, CSV, API. From $1.42 per 1,000 videos.

- **URL**: https://apify.com/automation_craft/facebook-video-search-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** Social media, Videos, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.42 / 1,000 videos

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Facebook Video Search Scraper: Reels, No Login

**Facebook video search scraper** for public videos and reels, with no login, no cookies and no Facebook account: give keywords, phrases, #hashtags or a pasted Facebook video search link and get the videos Facebook's own video search finds for each of them, in its Top order or with its Most recent filter, inside a date window and at a tagged place if you like. Every row carries the video's link, reel or video, its caption (and a compact result its title), author, date, views, duration, thumbnail, the query that found it, its rank and whether its text really holds your words; full results add the exact time, reactions by type, comment and share counts, size, video files, music and Facebook's captions. Pay per video, from $1.42 per 1,000.

Built for content and trend research, creative and competitor monitoring, influencer and creator discovery, brand mentions in video, newsrooms and fact checkers, academic studies and AI data sets, and for scheduled runs in n8n, Make or Zapier. Rows carry what Facebook shows a visitor who is not logged in; use them under the rules that apply to you.

#### At a glance

- Facebook's own video search (the same results the Videos tab of facebook.com/watch shows), read logged out from Apify's datacenter proxy: no account to lose, no cookies to keep fresh.
- Two kinds of result, both delivered: a **full result** (the whole video post: exact time, exact views, reactions by type, comments, shares, size, HD and SD files, music, captions) and a **compact result** (Facebook's video card: title, owner, day, views as Facebook shows them, duration, thumbnail). `detailLevel` says which.
- **Video details** (add-on): each delivered video's own page, for its exact play and view counts, reactions, comments, exact time, text, files and captions link, so a compact result gets the exact figures its card leaves out (shares aside: a video's own page shows none).
- **Deep search**: when Facebook's plain search ends (often near 90 to 100 videos a query), month by month windows go further back.
- Filters judged on every row, never guessed: date window, reels or videos, minimum views, reactions, comments and shares, the strict query match, words to keep or leave out. A row Facebook shows only as a day or a cut view figure is judged on every value it can mean; a row that cannot be judged is left out free (and counted) unless Video details reads its exact figure.
- Free transcripts (Facebook's own captions), free author details (a page's followers, category and rating), resume tokens, compact rows for AI agents and sheets.

### Quick start

1. Open the Actor and type your keywords in **Search queries** (one per line), for example `pizza recipe`.
2. Set **Videos per query** (the form starts at 10).
3. Optional: a date window (**Posted on or after**, for example `30 days`), **Order** set to Facebook's Most recent filter, a tagged place, **Video types** (reels only), minimum views or counts, **Video details**, **Transcripts**, **Author details**.
4. Click **Start**. Download the rows as JSON, CSV or Excel, or read them through the API.

### What you get

One row per video, plus one free coverage row per search and one free summary row per run.

| Field | What it is | Full result | Compact result | Compact result read by Video details |
|---|---|---|---|---|
| `videoId`, `url`, `videoType` | Facebook's video id, the video's link (`/reel/<id>/`, a page's `/videos/<id>/`, or `/watch/?v=<id>`), `reel` or `video` | yes | yes | yes |
| `query`, `searchRank`, `searchPage`, `sortBy`, `searchWindow`, `searchLocation` | the search that found it, its place in Facebook's results | yes | yes | yes |
| `matchesQuery`, `matchedWords` | whether the title, text or link preview title holds every word of the query, and which words it holds | yes | yes | yes |
| `detailLevel` | `full`, `card` (a compact result), `details` or `full+details` (Video details read its page) | yes | yes | yes |
| `title`, `text`, `hashtags`, `mentions` | the title (Facebook's video cards show one; full results carry the caption in `text` and no title), the caption or post text exactly as served, its hashtags and mentions | text, hashtags, mentions (no title) | title and caption | title, the whole caption, hashtags |
| `createdAt`, `createdAtUnix` | the exact time, UTC | yes | null | yes |
| `publishedLabel`, `publishedFrom`, `publishedTo` | a compact result's day as Facebook shows it ("Oct 1", "14 hours ago") and every moment it can mean | exact time | yes | exact time |
| `authorName`, `authorType`, `authorId`, `authorUrl`, `authorPageId`, `authorIsVerified` | the page or person who posted it (see Personal data) | yes (the verified mark with **Author details**) | name, verified mark | name; a page's id and link |
| `viewCount`, `viewCountLabel`, `viewCountMin`, `viewCountMax`, `viewCountIsExact` | views: exact where Facebook gives them; a compact result's views as shown ("285K views") with the range they mean (Facebook cuts, never rounds) | exact | shown and range | exact |
| `playCount` | plays, from the video's own page | null | null | yes |
| `reactionCount`, `reactions`, `commentCount`, `shareCount`, `engagementCount` | reactions (total and by type), comments, shares, their total | yes | null | reactions and comments (the video's page shows no shares) |
| `durationSeconds`, `width`, `height`, `orientation`, `aspectRatio` | length and size | yes | duration | duration |
| `thumbnailUrl`, `videoFileUrl`, `videoFileUrlSd` | the thumbnail, the HD file link (SD where there is no HD), the SD file link (Facebook's links stop working about 4 days after the read (their own expiry time, measured 1.3 to 4.5 days)) | yes | thumbnail | yes |
| `captionsUrl`, `captionsLanguage`, `captionsLocale`, `captionsCreationMethod`, `captionsTracks` | Facebook's own captions file (the track its player plays), that track's language and how Facebook says it was made ("Auto-generated", in the track's language), and every caption track Facebook lists, where the video has captions | yes | null | captions link |
| `transcript`, `transcriptCues`, `transcriptStatus` | the captions' text and its timed cues (start and end in seconds), with **Transcripts** on | yes | needs Video details | yes |
| `musicTitle`, `musicArtist` | the song Facebook shows on a reel | where shown | null | null |
| `isLive`, `broadcastStatus` | live flags | yes | yes | yes |
| `taggedPlace`, `taggedProfiles`, `isGroupPost`, `groupName`, `audience`, `isAiLabelled`, `link` | the post's place, tags, group, audience, Facebook's AI label, a link preview | yes | null | null |
| `authorFollowers`, `authorCategory`, `authorRecommendPercent`, `authorReviewCount`, `authorDetailsStatus` | with **Author details**: a page's followers (as Facebook rounds them), category and rating; `authorDetailsStatus` is `ok`, `ok_without_rating` (a page whose link names it by number only, `facebook.com/people/...` or `profile.php`: followers and category, no rating), `not_a_page`, `failed` or `not_read` | pages | owners that are pages | pages |
| `detailsStatus` | with Video details: `ok`, `not_found` (the video is gone), `no_figures`, `failed`, `skipped_charge_limit`, `not_read`, `other_video` (the page showed another video) | | | yes |
| `postId`, `feedbackId`, `storyId`, `scrapedAt`, `searchKey`, `subjectKey` | Facebook's post and feedback ids, the time of the read, the search's keys | yes | `scrapedAt`, keys | `postId`, `scrapedAt`, keys |

Measured fill, real actor runs of 2026-10-23 UTC (1,426 videos of the matrix real4, build 0.1.5: 344 full results, 973 compact results, 109 read with Video details; 98 percent reels. Full results: exact time, views, reactions, comments, shares, duration, thumbnail and HD file 100 percent, size 99, captions 26, music 19. Compact results: title, text, day, views as shown, duration and thumbnail 100 percent. With Video details: exact time, views, plays, reactions, comments and files 100 percent, shares 73 (the full results among them; a video's own page shows none), captions 34).

#### Coverage, status and summary rows (free)

- **coverage** (one per search): the pages read, videos read (`fullResults`, `cards`), delivered and charged, repeats, videos another search delivered, videos past the cap, every filter's count (`filtered`: window, type, views, counts, query, keywords, `undecided`), the month windows walked, `stopReason` and whether the search is `complete`.
- **status**: a value not used (`values_skipped`, positions only), a place that names no single place (`location_not_found`, with Facebook's suggestions), an add-on that could not be read in the run (`addon_unavailable`), a place lookup or a search query Facebook did not answer (`lookup_failed`), a place name of a resume token that now names another place (`place_changed`), invalid input (`invalid`), searches not started (`skipped`).
- **summary** (the last row): the run's counters, its requests, the work allowance, its charges and, when a search stopped before its end, a `resumeToken`.

#### Example video row (a full result with Video details)

```json
{
  "type": "video",
  "videoId": "1514562030165679",
  "postId": "1698827854983925",
  "url": "https://www.facebook.com/reel/1514562030165679/",
  "videoType": "reel",
  "query": "how to cook rice",
  "sortBy": "top",
  "searchLocation": null,
  "searchRank": 3,
  "searchPage": 1,
  "searchWindow": null,
  "subjectKey": "s:141c94835607c7df",
  "searchKey": "c:141c94835607c7df",
  "matchesQuery": false,
  "matchedWords": [
    "rice"
  ],
  "detailLevel": "full+details",
  "title": "Let’s make fried rice.",
  "text": "Let’s make fried rice.",
  "hashtags": [],
  "mentions": [],
  "createdAt": "2026-05-29T10:41:27.000Z",
  "createdAtUnix": 1780051287,
  "publishedLabel": null,
  "publishedFrom": "2026-05-29T10:41:27.000Z",
  "publishedTo": "2026-05-29T10:41:27.000Z",
  "authorName": "Joyful Cook",
  "authorId": "100045701816925",
  "authorUrl": "https://www.facebook.com/joyfulcookrecipes",
  "authorType": "page",
  "authorPageId": "111391827244712",
  "authorIsBusinessPage": true,
  "authorIsVerified": null,
  "authorProfilePictureUrl": "https://scontent-lga3-3.xx.fbcdn.net/...",
  "groupId": null,
  "groupName": null,
  "groupUrl": null,
  "isGroupPost": false,
  "taggedPlace": null,
  "taggedProfiles": [],
  "audience": "Public",
  "isAiLabelled": false,
  "viewCount": 907555,
  "viewCountLabel": null,
  "viewCountMin": 907555,
  "viewCountMax": 907555,
  "viewCountIsExact": true,
  "playCount": 1612359,
  "reactionCount": 34892,
  "reactionCountIsExact": true,
  "reactions": {
    "like": 33785,
    "love": 1034,
    "care": 58,
    "haha": 3,
    "wow": 8,
    "sad": 3,
    "angry": 1
  },
  "commentCount": 677,
  "shareCount": 2021,
  "engagementCount": 37590,
  "durationSeconds": 221.2,
  "width": 1080,
  "height": 1920,
  "orientation": "portrait",
  "aspectRatio": 0.563,
  "isLive": false,
  "broadcastStatus": null,
  "thumbnailUrl": "https://scontent-lga3-2.xx.fbcdn.net/...",
  "videoFileUrl": "https://video-lga3-3.xx.fbcdn.net/...",
  "videoFileUrlSd": "https://video-lga3-3.xx.fbcdn.net/...",
  "captionsUrl": "https://scontent-lga3-3.xx.fbcdn.net/...",
  "captionsLanguage": "English",
  "captionsLocale": "en_US",
  "captionsCreationMethod": "Auto-generated",
  "captionsTracks": [
    {
      "locale": "en_US",
      "language": "English",
      "creationMethod": "Auto-generated",
      "url": "https://scontent-lga3-3.xx.fbcdn.net/..."
    }
  ],
  "transcript": "See how delicious this fried rice is looking and it is super easy to make as well. You can serve at least 20 guests to this recipe so keep watching, let's begin ...",
  "transcriptCues": [
    {
      "start": 0,
      "end": 3.405,
      "text": "See how delicious this fried rice is looking and it is super"
    },
    {
      "start": 3.405,
      "end": 7.085,
      "text": "easy to make as well. You can serve at least 20 guests to"
    }
  ],
  "transcriptStatus": "ok",
  "musicTitle": null,
  "musicArtist": null,
  "link": null,
  "detailsStatus": "ok",
  "authorFollowers": null,
  "authorCategory": null,
  "authorRecommendPercent": null,
  "authorReviewCount": null,
  "authorDetailsStatus": null,
  "feedbackId": "ZmVlZGJhY2s6MTY5ODgyNzg1NDk4MzkyNQ==",
  "storyId": "UzpfSTEwMDA0NTcwMTgxNjkyNTpWSzoxNTE0NTYyMDMwMTY1Njc5",
  "scrapedAt": "2026-10-23T20:57:31.282Z"
}
```

#### How fast and how deep

Measured on the real actor (build 0.1.5, 256 MB, datacenter proxy, one lane), 2026-10-23 UTC: the prefill (10 videos) in 8 seconds; 1,000 videos of one query in 640 seconds (about 95 a minute; 453 seconds in an earlier run); 150 videos with the month windows in 63 seconds; 100 videos with Video details in 371 seconds (100 of 100 read); 20 queries of 3 videos in 81 seconds. Facebook's plain search ends near 90 to 100 videos a query; deep search goes on month by month (1,000 videos for "nike" in one run). Several queries go faster with `maxConcurrency` (3 lanes: 30 videos in 15 seconds).

### How much does it cost to scrape Facebook videos?

Pay per event: you pay for the videos delivered (and Video details when you turn it on), never for a repeat, a video a filter leaves out, a failed call, a place name that names no place or an input that cannot be used.

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Video (`video`), per 1,000 videos | $1.99 | $1.82 | $1.65 | $1.42 |
| Video details (`video_details`), per 1,000 videos, add-on | $1.32 | $1.20 | $1.09 | $0.94 |
| Actor start (`apify-actor-start`), once per run | $0.0075 | $0.0075 | $0.0075 | $0.0075 |

Platinum and Diamond plans pay the Gold price. There is no discount on the Actor start event. The Store pricing card shows these same prices per 1,000 events: "$1.99 / 1,000" on the Video row means one video costs about a fifth of a cent on the Free plan ($0.00199), and "$1.42 / 1,000" means one video costs about a seventh of a cent on the Gold plan ($0.00142).

- **Video** is charged once per video per run: a video that two of your queries find is delivered and charged once. Videos left out by the date window, the video type, a minimum, the query match or your words are not charged and get no row.
- **Video details** is charged only with **Video details** on, and only when the video's own page gave its figures; a video that is gone, or whose page shows no figures, is delivered without it and not charged for it.
- **Transcripts** and **Author details** cost nothing extra.

Worked examples, start fee included:

| Run | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| The prefill: 10 videos of one query | $0.0274 | $0.0257 | $0.0240 | $0.0217 |
| 1,000 videos | $1.9975 | $1.8275 | $1.6575 | $1.4275 |
| 1,000 videos with Video details | $3.3175 | $3.0275 | $2.7475 | $2.3675 |
| A daily scheduled run of 20 queries x 20 videos (400 videos a run) | $0.8035 a day | $0.7355 a day | $0.6675 a day | $0.5755 a day |
| The same daily run for 30 days | $24.105 | $22.065 | $20.025 | $17.265 |

Every run reads its searches fresh: a video a scheduled run delivered yesterday is delivered and charged again today when the search finds it again. Narrow a daily run with **Posted on or after** (for example `2 days`) to keep repeats down, and dedupe on `videoId` in your own sheet or workflow.

#### The work allowance

Work that earns nothing (searches whose videos every filter leaves out, refused calls, long stretches of repeats) is bounded by an allowance in real cost that grows with every event the run bills. When it is spent the run stops: the search it was reading ends with `work_allowance` in its coverage row, the searches not started get one free `skipped` row, and every row already delivered is kept. **Video details** reads from a small allowance of its own that its own events refill, so watch pages that fail never stop the search they serve; the part of each delivered video's own allowance its search did not need is added to it, so one slow page does not switch it off; a video it has no room for at that moment is delivered without it (`detailsStatus` `not_read`, one free `addon_unavailable` row a run), the next videos are read again as deliveries refill it, and videos it could not judge stay open for a resume token.

### Input

| Field | What it does | Default |
|---|---|---|
| `searchQueries` | Up to 100 queries, one per line: a keyword or phrase, a #hashtag, or a Facebook video search link (`facebook.com/watch/search/?q=pasta` or `facebook.com/search/videos/?q=pasta`; its most recent, date and location filters are read too). A query in double quotes must stand as that exact phrase for the query match. A value written as a link that is not a Facebook video search link (a post search, a single video, another site, `mailto:`, `tel:`) is skipped free and named in a `values_skipped` row, never searched as words. Also read: `query`, `queries`, `searchTerms`, `searchTerm`, and `startUrls` (links as `{ "url": ... }` objects or text). | none (the form starts with `pizza recipe`) |
| `sortBy` | `top` (Facebook's relevance ranking) or `recent` (Facebook's own Most recent filter: it favours recent videos but keeps Facebook's order, not a strict newest first; add a start date for a hard limit). Also read: `recentVideos`, `recent_videos`, `recentPosts` (true is `recent`). | `top`, or the order a pasted link names |
| `maxVideosPerQuery` | The most videos delivered per query (and per location), 1 to 5,000. Also read: `resultsCount`, `maxResults`, `resultsLimit`. | 20 (the form starts at 10) |
| `maxVideos` | A cap of video rows for the whole run, across queries. Also read: `maxItems`. | no cap |
| `startDate`, `endDate` | The date window, UTC, on or after 2004-01-01: `YYYY-MM-DD`, `today`, `yesterday`, or a time back such as `7 days`, `3 weeks`, `2 months`, `1 year`. Sent as Facebook's date filter and checked on every video (below). Also read: `postedAfter`, `dateFrom`, `start_date`, `postedBefore`, `dateTo`, `end_date`. | no window (the end is today) |
| `locations` | Up to 20 places, one per line: a Facebook location id (`108424279189115` is New York, New York) or a place's full name as Facebook writes it (`London, United Kingdom`). Sent as Facebook's own location filter; each query is searched once per location, at most 300 searches a run. Also read: `location`, `locationUid`, `locationId`, `location_uid`. | none |
| `deepSearch` | When a query's results end before its video number, go on month by month backwards (back to the start date, or 24 months), each month a new search; a deep walk ends after 3 months in a row that bring no new video. | on |
| `videoTypes` | `reel`, `video` or both. Also read: `videoType`, and `onlyReels` (`only_reels`) true means reels only. | both |
| `minViews` | Only videos with at least this many views. | none |
| `minReactions`, `minComments`, `minShares` | Only videos with at least this many. Compact results carry none of these counts: they are left out unless **Video details** reads them (shares never: a video's own page shows none). | none |
| `mustContainQuery` | Keep only videos whose title, text or link title holds every word of the query as a whole word (case and accents aside). | off |
| `includeKeywords`, `excludeKeywords` | Up to 50 words or phrases to keep (any of them) and to leave out (any of them), as whole words, case aside. Also read: `keywordFilter`. | none |
| `maxPagesPerQuery` | The most result pages read per search (about 7 videos a page), 1 to 1,000. | no page limit |
| `includeVideoDetails` | Read each delivered video's own page for its exact figures (the Video details event). Also read: `enrichDetailPage`. | off |
| `includeTranscript` | Add the text of Facebook's own captions (free). | off |
| `includeAuthorDetails` | Add a page author's followers, category, verified mark and rating (free). Also read: `includeAuthorFollowers`. | off |
| `outputFormat` | `full` or `compact` (one level rows). Also read: `compact` (true or false). | `full` |
| `includePersonalData` | The personal data switch (below). | off |
| `maxConcurrency` | How many searches are read at the same time, 1 to 5, each on its own exit. Prices do not change. | 1 |
| `requestDelayMs` | The pause between two calls of one search, 300 to 10,000 ms. | 400 |
| `maxRunSeconds` | Stop starting new work after this many seconds (60 to 86,400) and end with the coverage rows and the summary. | the run's own timeout |
| `proxyConfiguration` | Apify Proxy: the datacenter pool (default), the `RESIDENTIAL` group with a two letter country, your own proxies (`http(s)://user:password@host:port` links; never shown in logs or rows), or no proxy (the run's own address). Also read: `proxy`. | Apify datacenter pool |
| `resumeToken` | The `resumeToken` of an earlier run's summary row, to go on with its searches where they stopped (below). | none |

#### How dates, views and counts are judged

Facebook shows a compact result's date as a day ("Oct 1", "Dec 5, 2025") or an age ("14 hours ago", "Yesterday"), and its views cut to what it shows ("285K views" means 285,000 to 285,999). The Actor judges such a row on every value it can mean: a day counts in every time zone (UTC+14 to UTC-12), so a compact result dated on the first or last day of your window is "in doubt"; "285K views" passes a minimum of 280,000, fails 290,000 and is in doubt at 285,500. A row in doubt, or one without a count a minimum needs, is left out free and counted (`filtered.undecided` in the coverage row, `videosUndecided` in the summary). With **Video details** on, its page is read and the row is judged again on its exact figures; every row is judged once more as it will be delivered, after its page.

#### Resume tokens

When a search of a run stops before Facebook's end (its video number, its page limit, the charge limit, the run deadline, a refusal, or videos left in doubt because Video details could not read them), the run's summary row carries a `resumeToken`. Run the same searches again, given the same way (the same words, order, date window, and the same place ids or place names), with that token in `resumeToken`: each search starts where it stopped, a search that run read to its end is not read again, and each search skips, free, the videos IT delivered in that run. A token with a search that is not in the input refuses the run with one free row; a relative window (`7 days`) names other dates on another day, so resume with the dates of the first run. Nothing is stored on Apify between runs; with personal data off a token holds no person's id.

```json
{ "searchQueries": ["pizza recipe"], "maxVideosPerQuery": 100, "resumeToken": "fbr1.eyJ2..." }
```

Apify checks each setting of the table above against its type before the run starts: a text where a number, a switch or a list is expected (`"30"`, `"true"`) is refused by the API with nothing charged. The keys of other tools named under "Also read" also take those values as text (`"resultsLimit": "30"`, `"recent_videos": "true"`, `"location_uid": "108424279189115"`). A value sent as `null` or `""` counts as left out. Two keys of one meaning sent together, a setting name the Actor does not know, or a value it cannot use as given refuse the input with one free `invalid` row (only the start fee is charged).

Examples:

```json
{ "searchQueries": ["pizza recipe", "#homemadepizza"], "maxVideosPerQuery": 50 }
```

```json
{
  "searchQueries": ["electric scooter review"],
  "startDate": "30 days",
  "videoTypes": ["reel"],
  "minViews": 10000,
  "includeVideoDetails": true,
  "mustContainQuery": true
}
```

```json
{
  "searchQueries": ["pizza"],
  "locations": ["New York, New York"],
  "maxVideosPerQuery": 100,
  "includeTranscript": true,
  "includeAuthorDetails": true
}
```

### Personal data

Off by default. Rows then carry the names of video authors as Facebook shows them (they are part of the content) and each video's own link, and leave empty the fields that name or reach a private person: a person author's id, profile link and picture (`authorId`, `authorUrl`, `authorProfilePictureUrl`), a person author's `storyId`, and the ids and links of people tagged or mentioned. A person's video link that holds the person's profile name (`facebook.com/<name>/videos/<id>`) is given as `facebook.com/reel/<id>/` or `facebook.com/watch/?v=<id>`, which open the same video without a login. A compact result never says whether its owner is a page or a person, so its owner's id and link are empty too, unless **Author details** finds the owner is a page (a page's id and link are business data and are always delivered). Texts are never masked. With **Include personal data** (`includePersonalData: true`) those fields are filled; you are responsible for a lawful use of personal data (GDPR included).

### What this Actor does NOT do

- **Logged in data and cookies**: it reads what a visitor who is not logged in sees; no account, no cookies, nothing private.
- **Other search types**: it searches videos and reels only, never posts, pages, people, groups or events.
- **A video by its link, or the videos of one page**: use the Facebook Post Scraper (posts, videos and reels by link) or the Facebook Posts Scraper (a page's posts, its videos and reels among them).
- **Live videos search**: Facebook's live filter answers no results to a visitor who is not logged in.
- **Comments of a video**: use the Facebook Comments Scraper with the video's link.
- **Speech to text**: transcripts are Facebook's own captions; a video without captions has no transcript.
- **The video files themselves**: rows carry the file links (Facebook's links stop working about 4 days after the read (their own expiry time, measured 1.3 to 4.5 days)); the files are not stored.
- **Whether comments are turned off, collaborators, paid partnership labels**: Facebook's answers to a visitor who is not logged in do not carry them (they mark every video as closed to that visitor's comments, so comments turned off cannot be told apart).
- **A memory of earlier runs**: each run reads its searches fresh; use a date window or a resume token for scheduled runs.

### API examples

Run and get the rows (replace `<APIFY_TOKEN>`):

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~facebook-video-search-scraper/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries": ["pizza recipe"], "maxVideosPerQuery": 20}'
```

Node.js:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('automation_craft/facebook-video-search-scraper').call({ searchQueries: ['pizza recipe'], maxVideosPerQuery: 20, includeVideoDetails: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((x) => x.type === 'video'));
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("automation_craft/facebook-video-search-scraper").call(run_input={"searchQueries": ["pizza recipe"], "maxVideosPerQuery": 20})
videos = [x for x in client.dataset(run["defaultDatasetId"]).iterate_items() if x["type"] == "video"]
```

Send the rows where you need them with Apify's own integrations: a webhook on the run's end, or the Make, Zapier and n8n Apify modules.

### FAQ

#### Can I search Facebook videos by keyword without logging in?

Yes. The Actor reads Facebook's own video search the way a visitor who is not logged in sees it, through Apify's datacenter proxy: no account, no cookies. It returns public videos and reels only.

#### Can I download the Facebook videos a search finds?

Each full result (and each video read with Video details) carries `videoFileUrl` (HD where Facebook offers it) and `videoFileUrlSd`, the files Facebook's own player plays. Download them soon: Facebook's links stop working about 4 days after the read (their own expiry time, measured 1.3 to 4.5 days).

#### Does it get the view count of Facebook reels and videos?

Yes. Full results carry the exact `viewCount`; compact results carry Facebook's views as shown ("285K views") with the range they mean. With Video details on, every video gets its exact views and plays (`playCount`) from its own page.

#### Can I filter Facebook videos by date?

Yes: set **Posted on or after** and **Posted on or before** (or a time back such as `30 days`). The window goes to Facebook as its own date filter and is checked again on every row, because Facebook's filter lets other dates through; a compact result that shows only a day is judged on that whole day.

#### Can I get the transcript of a Facebook video?

Yes, where the video has Facebook's own captions: turn on **Transcripts** (free) and each row gets `transcript`, its timed `transcriptCues` and `transcriptStatus`. A compact result carries its captions link only once **Video details** read its page; there is no speech to text, so a video without captions says `no_captions`.

#### Why does this Actor run with limited permissions?

It needs nothing beyond its own run storage, so it runs with Apify's limited permissions (least privilege): it can read and write only the dataset and key-value store of its own run, and nothing else in your account.

### More data tools by Automation Craft

- [Facebook Posts Scraper - Page Posts, No Login](https://apify.com/automation_craft/facebook-posts-scraper)
- [Facebook Post Scraper: Reactions and Shares by URL](https://apify.com/automation_craft/facebook-post-scraper)
- [Facebook Comments Scraper: Replies, No Login](https://apify.com/automation_craft/facebook-comments-scraper)
- [Facebook Groups Scraper: Posts of Public Groups](https://apify.com/automation_craft/facebook-groups-scraper)
- [Facebook Page ID Finder: Names to Page IDs](https://apify.com/automation_craft/facebook-page-id-finder)
- [Instagram Posts Scraper: Profiles, Reels, No Login](https://apify.com/automation_craft/instagram-posts-scraper)
- [Threads Search Scraper: Keywords, Hashtags, Dates](https://apify.com/automation_craft/threads-search-scraper)
- [Meta Ad Transcript Scraper - Video Ads to Text](https://apify.com/automation_craft/meta-ad-transcript-scraper)
- [Meta Ads Library Scraper - Ad Library, All Filters](https://apify.com/automation_craft/meta-ads-library-scraper)

### Changelog

See the Changelog tab (`CHANGELOG.md`).

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/facebook-video-search-scraper/changelog.md

# Actor input Schema

## `searchQueries` (type: `array`):

What to search Facebook's videos for, one query per line (up to 100): a keyword or phrase (pizza recipe), a #hashtag, or a Facebook video search link (facebook.com/watch/search/?q=pasta or facebook.com/search/videos/?q=pasta; its most recent, date and location filters are read too). Any other link (a post search, a single video, another site, mailto: or tel:) is skipped free and named in a row, never searched as words. Each query is searched on its own and every row names it. Facebook's search is fuzzy: each row says whether its title or text holds every word (matchesQuery), and "Only videos that contain the query" keeps only those. Also read from query, queries, searchTerms, searchTerm and startUrls (links as { url } objects or text).

## `sortBy` (type: `string`):

top: Facebook's relevance ranking (videos of any age). recent: Facebook's own Most recent filter, which favours recent videos but keeps Facebook's order, not a strict newest first (set a start date for a hard limit). Left empty: top, or the order a pasted search link names. Also read from recentVideos (true is recent) and recentPosts.

## `maxVideosPerQuery` (type: `integer`):

The most new videos delivered per query (and per location). Left empty (an API call without it): 20; the Console form starts at 10. A query whose results end earlier is walked month by month when "Deep search" is on. Also read from resultsCount, maxResults and resultsLimit.

## `maxVideos` (type: `integer`):

The most videos delivered in the whole run, across queries. Left empty: no cap beyond the per query number and your charge limit. Also read from maxItems.

## `startDate` (type: `string`):

The first day of a date window (UTC): YYYY-MM-DD, today, yesterday, or a time back from the run's start such as 7 days, 3 weeks, 2 months, 1 year. Sent to Facebook as its own date filter and checked again on every video: a video with an exact time is judged on it; a compact result shows only a day ("Oct 1") or an age ("14 hours ago"), which is judged as every moment it can mean in any time zone, so one on the window's first or last day is left out unless "Video details" reads its exact time. Videos outside the window are left out and not charged. On or after 2004-01-01. Left empty: no start. Also read from postedAfter, dateFrom and start_date.

## `endDate` (type: `string`):

The last day of the date window (UTC), in the same forms as the start. Left empty: today. Also read from postedBefore, dateTo and end_date.

## `locations` (type: `array`):

Only videos Facebook's own location filter returns for a place, one per line: a Facebook location id (108424279189115 is New York, New York) or a place's full name as Facebook writes it (New York, New York; London, United Kingdom), looked up in Facebook's own place list. A name that names no single place gets a free row with Facebook's suggestions and its searches are not run. Each query is searched once per location. Up to 20. Also read from location, locationUid, locationId and location_uid.

## `deepSearch` (type: `boolean`):

When a query's results end before its video number, go on month by month backwards (this month, the month before, back to the start date or 24 months), each month a new search of its own: Facebook's date filter ranks other videos first, so a month finds videos the plain search did not. Repeats are free.

## `videoTypes` (type: `array`):

Only these kinds (any of them): reel (a facebook.com/reel/ link) or video (every other video). Left empty: both. Others are left out and not charged. Also read from videoType, and onlyReels true means reels only.

## `minViews` (type: `integer`):

Only videos with at least this many views. A compact result shows Facebook's cut figure ("285K views" is 285,000 to 285,999), judged as its whole range: one whose range crosses your number is left out unless "Video details" reads the exact count. Videos below it, or with no count shown, are left out and not charged.

## `minReactions` (type: `integer`):

Only videos with at least this many reactions. Compact results carry no reaction, comment or share counts: with a minimum set they are left out unless "Video details" reads the counts (shares never: the watch page shows none). Videos with fewer, or with no count, are left out and not charged.

## `minComments` (type: `integer`):

Only videos with at least this many comments. A compact result carries no comment count: with a minimum set it is left out unless "Video details" reads the count. Videos with fewer, or with no count, are left out and not charged.

## `minShares` (type: `integer`):

Only videos with at least this many shares. Only full results carry a share count (a video's own page shows none, so "Video details" adds none): compact results are left out when a minimum is set. Videos with fewer, or with no count, are left out and not charged.

## `mustContainQuery` (type: `boolean`):

Keep only videos whose title, text or link title holds every word of the query as a whole word, case and accents (é, ü, ñ) aside; a query in double quotes must stand as that exact phrase. Off: Facebook's own matches are delivered and each row says whether it holds the query (matchesQuery, matchedWords).

## `includeKeywords` (type: `array`):

Only videos whose title or text holds at least one of these words or phrases (whole words, case aside). Up to 50. Also read from keywordFilter.

## `excludeKeywords` (type: `array`):

Videos whose title or text holds any of these words or phrases are left out and not charged (the same matching rule). Up to 50.

## `maxPagesPerQuery` (type: `integer`):

The most result pages read per search (about 7 videos a page). Left empty: no page limit (the videos per search cap and Facebook's own end decide).

## `includeVideoDetails` (type: `boolean`):

Read each delivered video's own page for its exact figures (the Video details event, charged only when the page gave them): exact play and view counts, reactions by type, the comment count, the exact time and text, the video files and the captions link. Most useful for compact results (about half of a plain search, nearly all of a filtered one), which show only a day, a cut view figure and no counts. Off by default. Also read from enrichDetailPage.

## `includeTranscript` (type: `boolean`):

Add the text of Facebook's own captions of each delivered video that has them (transcript, transcriptStatus), at no extra charge. A compact result carries its captions link only once "Video details" read its page. No speech to text: a video without Facebook captions says no_captions. Off by default.

## `includeAuthorDetails` (type: `boolean`):

Add each page author's follower count (as Facebook rounds it), category, verified mark and rating ("96% recommend (312 reviews)") from the page's own embed and reviews tab, once per author per run, at no extra charge. Read for a full result's page author and for every compact result's owner: the embed answers only for a page, so an owner it names is a page and its id and link are delivered; people get authorDetailsStatus not_a_page; a page whose link names it by number only (facebook.com/people/... or profile.php) gets its followers and category without the rating (ok_without_rating). Off by default. Also read from includeAuthorFollowers.

## `outputFormat` (type: `string`):

full: every field; compact: the main fields of a video one level deep (link, title, text, author, date, views, counts, duration, thumbnail, file, transcript). Left empty: full. Also read from compact (true or false).

## `includePersonalData` (type: `boolean`):

Off (the default): the dedicated fields that name or reach a private person are empty: the author's id, profile link and picture unless the row shows a page (a compact result never names its owner's kind, so its owner id and link are empty), the ids and links of people tagged or mentioned, and a person's video link is given as facebook.com/reel/<id> or watch/?v=<id> (both open without a login). Names, texts and every video's own address are delivered as Facebook shows them, either way. On: those fields are filled; you are responsible for a lawful use of personal data (GDPR included).

## `maxConcurrency` (type: `integer`):

How many searches are read at the same time, each on its own exit. Left empty: 1 (one after another).

## `requestDelayMs` (type: `integer`):

The pause between two calls of one search, in milliseconds. Left empty: 400.

## `maxRunSeconds` (type: `integer`):

Stop starting new work after this many seconds and end with the coverage rows and the summary (what was delivered stays delivered and charged). Left empty: the run's own timeout.

## `proxyConfiguration` (type: `object`):

Apify Proxy, the datacenter pool by default; choose the RESIDENTIAL group with a country for exits of that country, your own proxies (http(s) links with their port; each new exit takes the next one), or no proxy for the run's own address. Also read from proxy.

## `resumeToken` (type: `string`):

Go on with the searches an earlier run stopped before their end (its video number, the charge limit, the run deadline): paste the resumeToken of that run's summary row here and run the same searches again, given the same way (the same words, order, date window, and the same place ids or place names). Each search starts where it stopped, searches that run read to the end are not read again, and each search skips, free, the videos it delivered in that run. Left empty: every search starts at its first page.

## Actor input object example

```json
{
  "searchQueries": [
    "pizza recipe"
  ],
  "maxVideosPerQuery": 10,
  "deepSearch": true,
  "mustContainQuery": false,
  "outputFormat": "full",
  "includePersonalData": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "pizza recipe"
    ],
    "maxVideosPerQuery": 10,
    "outputFormat": "full",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/facebook-video-search-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["pizza recipe"],
    "maxVideosPerQuery": 10,
    "outputFormat": "full",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/facebook-video-search-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "pizza recipe"
  ],
  "maxVideosPerQuery": 10,
  "outputFormat": "full",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation_craft/facebook-video-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation_craft/facebook-video-search-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/MtXCpPISejmQfp07a/builds/6Kuz2soyNZf7uxmqM/openapi.json
