Facebook Video Search Scraper - Description & Hashtags avatar

Facebook Video Search Scraper - Description & Hashtags

Pricing

Pay per usage

Go to Apify Store
Facebook Video Search Scraper - Description & Hashtags

Facebook Video Search Scraper - Description & Hashtags

Facebook Video Search Scraper extracts videos from Facebook search results, capturing titles, descriptions, URLs, views, reactions, comments, shares, and timestamps. Ideal for content research, trend analysis, competitor monitoring, and automating structured Facebook video data collection.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

SimpleAPI

SimpleAPI

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

0

Monthly active users

3 days ago

Last modified

Share

Search Facebook Watch by keyword and get back one row per public video, carrying the full caption text and Facebook's own structured hashtag entities — tag name, /hashtag/ URL and stable numeric ID — plus the creator, thumbnail, duration and a direct video link. Every row is typed JSON keyed on query, videoUrl, fullDescription, hashtags, hashtagSource and video_owner_profile. Content strategists, hashtag researchers and social listening teams use it to see the exact wording and tags creators attach to a topic before publishing their own. No Facebook login is required — everything is read logged out.

🎬 What is Facebook Video Search Scraper - Description & Hashtags?

It is an Apify Actor that runs a keyword through Facebook's own Watch search and returns every matching public video as one structured dataset row, including the complete caption and Facebook's linkified hashtag entities — not a screen-scraped snippet. No Facebook account, login or cookie is required; the Actor searches and reads video pages logged out.

  • Discovery is by keyword, not URL or category — one search phrase per line, each searched separately against facebook.com/watch/search
  • Core identifying fields on every rowvideoUrl, facebookId, video_owner_profile (creator name, profile URL, verification status)
  • The secondary data that drives the buying decisionfullDescription (the complete caption) and a structured hashtag block: hashtags, hashtagUrls, hashtagIds, hashtagCount, hashtagSource
  • Temporal and media fieldsrelative_time_string, video_duration_text, thumbnail_image
  • A real keep-if filtermustContainHashtags drops any video that uses none of your listed tags
  • Standard Apify dataset export — JSON, CSV, Excel or XML, or read straight through the Apify API

What data can I extract with Facebook Video Search Scraper?

Every row combines a caption/hashtag block with the underlying video's identity, creator and timing fields.

FieldExample valueUse case
query"street food"Which of your keywords produced this row
videoUrl"https://www.facebook.com/reel/1180213145174950/"Direct link to watch or embed the video
fullDescription"#cricket #fans #cricketlovers \n#indiacricket"The complete caption as written
hashtags["cricket","fans","cricketlovers","indiacricket"]Tag names, deduplicated, in caption order
hashtagUrls["https://www.facebook.com/hashtag/cricket?__eep__=6", ...]Browsable /hashtag/ page for each tag
hashtagIds["222029194603396", ...]Facebook's stable numeric hashtag ID, for joins
hashtagCount4len(hashtags)
hashtagSource"entity"Which mechanism produced hashtags for this row
hashtagsFromText["cricket","fans","cricketlovers","indiacricket"]A plain-text #tag scan of the same caption
matchedRequiredHashtags[]Which of your mustContainHashtags this row matched
descriptionSource"in_payload"Where fullDescription came from
descriptionStatus"in_payload"Outcome of the caption-recovery attempt
descriptionLength44Character count of fullDescription
renderShape"story"Which of Facebook's two result view models this row came from
mentionedPages[]Tagged profile/Page/Group entities in the caption
video_owner_profile{"name":"Cricket Lover","url":"...","is_verified":false, ...}Creator identity and verification flag
relative_time_string"21 days ago"Human-readable publish recency
video_duration_text"14:57"Video length as displayed
thumbnail_image{"uri":"https://scontent...jpg"}Preview image
title"Sikorsky's S-97 Raider..."Video title, where Facebook supplies one
save_description"..."The caption exactly as Facebook's search response carries it
label"..."Facebook's accessibility label for the tile
facebookId"1180213145174950"Facebook's video ID
video{"id":"1180213145174950"}Video object as returned by Facebook
video_broadcast_statusnullBroadcast status as reported by Facebook
facebookUrl"https://www.facebook.com/watch/search?q=cricket"The search page this row was found on
inputUrl"https://www.facebook.com/watch/search?q=cricket"Same value as facebookUrl
rowType"video"video for a result, error for an accounting row
errorReason"rate_limited"Present only on rowType: "error" rows — see below

🏷️ Caption and hashtag fields

fullDescription, hashtagSource, hashtagIds and matchedRequiredHashtags are the fields that decide whether a video is useful for tag research: hashtagSource tells you whether the tags came from Facebook's own linkified entity list (entity, with stable IDs) or a text scan (regex, no IDs), descriptionStatus tells you whether the caption is the complete text or a tile snippet, and matchedRequiredHashtags proves which of your filter tags actually matched. A hashtag researcher counting tag co-occurrence across a niche joins on hashtagIds rather than tag strings, since Facebook's own ID is stable across spelling variants.

🎯 Identity and targeting fields

query tells you which keyword produced the row, renderShape tells you which Facebook view model it came from, and video_owner_profile carries the creator's name, profile URL and verification flag for filtering by publisher. relative_time_string and video_duration_text let you segment by recency and length without a second request.

Why not build this yourself?

Facebook does not publish a public API that lets a third-party app search Watch videos by keyword and read back captions and hashtag entities — the Graph API's public surface does not expose this search. A DIY scraper means reverse-engineering an internal GraphQL endpoint instead, and the maintenance load is the real cost.

Facebook's Watch search runs on an internal GraphQL operation identified by a numeric doc_id that has to be pulled out of the page's own JS bundles — the bundle discovery has to scan escaped-slash URLs embedded in JSON, not just src="..." attributes, or the operation id goes stale on the next bundle reshuffle. The search response itself arrives in two different, differently-shaped result edges under the same GraphQL typename (video_metadata_model tiles and story edges), and only one of them ships Facebook's own hashtag entity list — the other has to be recovered from the video's own page, which is refused to a normal browser user-agent and only served to a search-engine-crawler user-agent class. On top of that, Facebook answers a datacenter proxy exit to the search endpoint with an HTTP 200 and a rate-limit error carrying zero results rather than an honest block, so a scraper that doesn't recognize that response as a wall reports an empty run as a successful one. Facebook Video Search Scraper - Description & Hashtags handles the doc_id resolution, both result shapes, the caption-recovery hop, and the wall/rate-limit detection so you get structured rows instead of an integration project.

Build your own if you need a use case this Actor doesn't cover, or already run comparable GraphQL-scraping infrastructure. Use this Actor for a working keyword-to-caption-and-hashtag pipeline today.

How to use data extracted from Facebook Video Search Scraper

📝 Content and SEO strategists

Search your target topic, then read fullDescription and hashtags across the result set to see the actual wording and tag vocabulary creators use before writing your own caption. hashtagSource: "entity" rows carry Facebook's own tag IDs, so you can distinguish an authoritative tag from a text-scan guess when deciding which ones to reuse.

📊 Hashtag researchers and analysts

Run a keyword list on a schedule and count tag frequency and co-occurrence with hashtags and hashtagIds, joining on the numeric ID rather than the tag string so spelling or capitalization variants don't split a count. mustContainHashtags narrows a run to videos already using specific tags, and matchedRequiredHashtags records which ones matched each row.

🔎 Social listening and brand monitoring

Re-run the same keyword list on a schedule via the Apify scheduler and diff fullDescription and hashtags over time to watch how the language around a product, event or brand shifts. video_owner_profile tells you which creators and Pages are publishing on the topic and how often.

🤖 AI agents and automated pipelines

fullDescription and hashtags are typed, normalized JSON with no HTML to strip, so a row can be indexed into a vector store or handed to an agent tool directly. An agent framework calling the Apify API can search a topic and read back structured caption and hashtag data in the same request-response cycle it uses for any other tool call.

⬇️ Input

Required: startUrls.

ParameterRequiredTypeDescriptionExample value
startUrlsYesarrayOne search phrase per line — for example street food, cricket highlights, ev charging. Each line is searched separately on Facebook Watch and every returned row is tagged with the keyword it came from. These are keywords, not URLs.["cricket", "street food"]
maxVideosNointeger (min 1, max 1000, default 10)How many videos to collect for each keyword. Facebook returns roughly 7-8 results per page, so larger numbers mean more pages and longer runs. Results are de-duplicated by video ID across pages and keywords.25
extractHashtagsNoboolean (default true)Read Facebook's own linkified hashtag entities out of the caption — each one gives a tag name, a browsable /hashtag/ URL and a stable tag ID. When Facebook returns no entity list for a caption, the tags are read from the text instead and hashtagSource says so.true
includeFullDescriptionNoboolean (default true)About 60% of results carry Facebook's own hashtag entity list in the search response. The rest are tile-shaped and carry caption text only. Turn this on to fetch those videos' own pages, which returns Facebook's hashtag entities — name, /hashtag/ URL and numeric ID — for 33 of 38 measured tile rows, and confirms the caption text (identical on 38/38, so it corrects nothing but proves nothing was cut). Costs one request per tile-shaped video. descriptionStatus records what happened per row.true
mustContainHashtagsNoarray (default [])One tag per line, with or without the leading #. A video is kept when it carries at least one of them, and matchedRequiredHashtags lists which ones matched. Leave empty to keep everything.["streetfood"]
includeMentionedPagesNoboolean (default false)Off by default on purpose. Profile, Page and Group tags inside captions are rare — measured at 2 of 59 videos (3%) — and Facebook returns name: null on them, so only the short name, ID and URL are usable. Expect an empty array on almost every row.false
proxyConfigurationNoobjectYour selection is honoured: custom proxy URLs are tried first, then the Apify groups you pick, then Apify Residential as the final tier. Residential is the default because Facebook's search endpoint answers datacentre exits with a rate-limit error and zero results.{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}

Input example

{
"startUrls": ["street food", "ev charging"],
"maxVideos": 25,
"extractHashtags": true,
"includeFullDescription": true,
"mustContainHashtags": ["streetfood"],
"includeMentionedPages": false,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Common pitfall: despite the field name, startUrls only accepts search keywords, not Facebook URLs. Pasting an actual Facebook URL does not open that page — it gets searched as literal text against Watch search and will usually return nothing useful. Type the topic itself, one per line.

⬆️ Output

Typed, normalized JSON, one row per video (or one accounting row per keyword that produced nothing — see below). Export as JSON, CSV, Excel or XML, or read the dataset through the Apify API.

{
"query": "cricket",
"videoUrl": "https://www.facebook.com/reel/1180213145174950/",
"fullDescription": "#cricket #fans #cricketlovers \n#indiacricket",
"hashtags": ["cricket", "fans", "cricketlovers", "indiacricket"],
"hashtagCount": 4,
"hashtagSource": "entity",
"hashtagUrls": [
"https://www.facebook.com/hashtag/cricket?__eep__=6",
"https://www.facebook.com/hashtag/fans?__eep__=6",
"https://www.facebook.com/hashtag/cricketlovers?__eep__=6",
"https://www.facebook.com/hashtag/indiacricket?__eep__=6"
],
"hashtagIds": ["222029194603396", "149550058542367", "511137268924703", "419268324830427"],
"hashtagsFromText": ["cricket", "fans", "cricketlovers", "indiacricket"],
"matchedRequiredHashtags": [],
"descriptionSource": "in_payload",
"descriptionStatus": "in_payload",
"descriptionLength": 44,
"renderShape": "story",
"mentionedPages": [],
"video_owner_profile": {
"__typename": "User",
"id": "100071552850071",
"__isNode": null,
"__isActor": "User",
"name": "Cricket Lover",
"url": "https://www.facebook.com/people/Cricket-Lover/100071552850071/",
"is_verified": false
},
"relative_time_string": "21 days ago",
"video_duration_text": "14:57",
"thumbnail_image": { "uri": "https://scontent-phx1-1.xx.fbcdn.net/v/t15.5256-10/..." },
"title": "#cricket #fans #cricketlovers \n#indiacricket",
"save_description": "#cricket #fans #cricketlovers \n#indiacricket",
"label": null,
"facebookId": "1180213145174950",
"video": { "id": "1180213145174950" },
"video_broadcast_status": null,
"facebookUrl": "https://www.facebook.com/watch/search?q=cricket",
"inputUrl": "https://www.facebook.com/watch/search?q=cricket",
"rowType": "video"
}

errorReason does not appear on this row at all — it is not null, the key is simply absent. It exists only on rowType: "error" accounting rows, which carry every other field as null or empty and explain why a keyword produced nothing (search_page_blocked, no_cursor, rate_limited, blocked, no_response, all_results_filtered_out_by_mustContainHashtags, facebook_returned_no_result_edges, no_parsable_videos). Accounting rows are pushed without the charged_event_name used for real video rows, so a blocked or empty keyword is never billed — filter them out downstream with rowType == "video".

How do you filter and target specific videos?

Four real controls decide what lands in your dataset. Keyword precision comes first — Facebook Watch search matches on the phrase you supply, so a specific phrase ("street food vendor mumbai") returns a tighter, more on-topic set than a broad single word. mustContainHashtags is a keep-if-matches-any-of filter: a video survives if it carries at least one of your listed tags, and matchedRequiredHashtags on the surviving rows shows you which tag actually matched — useful for auditing whether the filter is doing what you expect. Completeness controls trade cost for data depth: extractHashtags off skips hashtag work entirely (hashtagSource: "disabled"), and includeFullDescription off skips the one extra request per tile-shaped video, leaving those rows with descriptionStatus: "snippet_only" and no hashtag IDs. Volume is maxVideos per keyword — Facebook serves roughly 7-8 results per page, so a higher target means more pages and a longer run, and results are de-duplicated by video ID across both pages and keywords so the same video posted under two searched topics only appears once.

{ "startUrls": ["mumbai street food"], "maxVideos": 50 }
{ "startUrls": ["ev charging"], "mustContainHashtags": ["evcharging", "electricvehicle"] }
{ "startUrls": ["cricket"], "extractHashtags": true, "includeFullDescription": false }

▶️ Want to try other Facebook scrapers?

Scraper NameWhat it extracts
Facebook Page Content Strategy ScraperPost-level topic keywords and content patterns from Facebook Pages
Facebook Group Engagement AnalyzerEngagement scoring and leaderboards for posts inside a Facebook Group
Instagram Reels Hashtag ScraperReels discovered by hashtag, keyword or URL, with play counts and audio metadata
YouTube Channel Keyword Research ScraperChannels and videos discovered by seed keyword, with SEO keyword extraction

How to extract Facebook video data programmatically

Facebook Video Search Scraper - Description & Hashtags runs as a standard Apify Actor — one API call in, structured JSON dataset back out.

Python example

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("<YOUR_USERNAME>/facebook-video-search-scraper-description-hashtags").call(run_input={
"startUrls": ["street food", "ev charging"],
"maxVideos": 25,
"mustContainHashtags": ["streetfood"],
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row.get("rowType") == "video":
print(row["query"], row["videoUrl"], row["hashtags"])

Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request.

Export to spreadsheets or CRM

Export the dataset as CSV and map query, videoUrl, fullDescription and hashtags straight into spreadsheet columns, or feed the same JSON into a CRM/content-calendar import step through the Apify API.

Yes. This Actor reads public Facebook Watch videos and the captions and hashtags their creators chose to attach — content posted publicly and visible to any logged-out visitor. These are content and business records, not personal profile data, so the obligations that apply are Facebook's terms of service and database/unfair-competition rules around systematic reuse of a compiled dataset, not GDPR-style personal-data rules.

One exception: with includeMentionedPages turned on, a caption may tag a profile, Page or Group by name — a rare event, but where it happens the row carries a name, ID and URL that can identify an individual. This is incidental to the caption data this Actor exists to collect, not its purpose, and it is off by default for that reason.

Consult legal counsel for commercial applications involving bulk storage of personal data.

❓ Frequently asked questions

What if a keyword search returns zero matching videos?

The run does not silently return an empty dataset. It writes a single rowType: "error" accounting row for that keyword, with errorReason set to why (facebook_returned_no_result_edges, no_parsable_videos, all_results_filtered_out_by_mustContainHashtags, or a block/rate-limit reason), and moves on to the next keyword. Accounting rows are never billed.

Can I get the full caption and hashtags together, or just one?

Both come on the same row. fullDescription is the complete caption text and hashtags/hashtagUrls/hashtagIds are the structured tag list read out of it — you don't choose one or the other. extractHashtags and includeFullDescription each control how much extra work goes into filling those fields, not whether they exist on the row.

How accurate is the caption and hashtag data?

The Actor returns the caption and hashtag entities exactly as Facebook's own search response or video page carries them at request time. Accuracy depends on whether the creator has since edited or deleted the caption. Re-run the keyword periodically if you need current data rather than a one-time snapshot.

How many videos can I get per run?

maxVideos accepts 1 to 1000 per keyword. Facebook returns roughly 7-8 results per page, so a large maxVideos means more pages and a longer run. Results are de-duplicated by video ID across pages and across every keyword in the same run, so the same video found under two searched topics is only saved once.

What is hashtagSource and why does it matter?

It records which of two independent mechanisms produced the hashtags list on that row: entity means Facebook's own linkified hashtag entities were present in the search response or recovered from the video page (with stable numeric IDs in hashtagIds); regex means no entity list was available and the tags were read out of the caption text instead (hashtagIds will be null for those); none means no tags were found either way; disabled means extractHashtags was turned off. hashtagsFromText always carries the text-scan read regardless of source, so you can compare the two instead of trusting a silent merge.

Does Facebook Video Search Scraper work with Claude, ChatGPT and AI agent frameworks?

Yes. It is callable as a standard HTTP endpoint through the Apify API, so any agent framework that can make a request — LangChain, CrewAI, n8n, a custom tool definition — can invoke it and receive typed JSON directly.

How does Facebook Video Search Scraper - Description & Hashtags compare to other Facebook video scrapers?

Checked on the Apify Store on 2026-07-26: apify/facebook-video-search-scraper documents a broader field set focused on video metadata (duration, views, owner info, broadcast status) and accepts either a keyword or a Facebook search URL, with PAY_PER_EVENT pricing. powerai/facebook-video-search-scraper documents location and date-range filters alongside keyword search but a narrower output (no structured hashtag entities). Neither competitor's README documents a hashtag-entity mechanism, a caption-recovery hop, or a mustContainHashtags filter — this Actor's caption and hashtag depth, including which of two extraction paths produced each row, is not documented on either listing as of the date checked.

Can I use it without a Facebook account or API key?

Yes. No Facebook account, login, cookie or API key is needed — the Actor searches and reads video pages logged out. The only credential required is your Apify account to run the Actor and read the dataset.

Conclusion

Facebook Video Search Scraper - Description & Hashtags turns a list of topics into a structured dataset of public Facebook videos, each carrying the complete caption and Facebook's own hashtag entities rather than a snippet to re-parse. It is built for content strategists, hashtag researchers and social listening teams who need to know what creators actually say and tag on a topic, with a stable schema and a documented filter (mustContainHashtags) for narrowing results precisely. Start a run from the Apify Console or the Apify API with your keyword list to get the first rows in your dataset.