# Facebook Hashtag Scraper (`maximedupre/facebook-hashtag-scraper`) Actor

Collect available public Facebook posts that match one or more hashtags. Filter by post format and time range, then review post text, author details, engagement, media, and source links when Facebook exposes them.

- **URL**: https://apify.com/maximedupre/facebook-hashtag-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media, Marketing, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.65 / 1,000 hashtag posts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### #️⃣ Search Facebook posts by hashtag

Social media researchers, marketers, and developers can search one or more public Facebook hashtags and collect available matching posts in structured dataset rows. Review post text, public author details, engagement counts, media details, publication time, and source links when Facebook exposes them. Shared format and time filters help focus one run on the posts you need.

- Find available public Facebook posts for one or more hashtags with **[Facebook Hashtag Extractor](https://apify.com/maximedupre/facebook-hashtag-scraper/examples/facebook-hashtag-extractor)**.
- Review structured post text, authors, and source links with **[Facebook Hashtag Data](https://apify.com/maximedupre/facebook-hashtag-scraper/examples/facebook-hashtag-data)**.
- Keep only selected reels, videos, or photos with **[Facebook Hashtag Posts](https://apify.com/maximedupre/facebook-hashtag-scraper/examples/facebook-hashtag-posts)**.
- Focus a search on any time, the last month, or the last year with **[Facebook Hashtag Search](https://apify.com/maximedupre/facebook-hashtag-scraper/examples/facebook-hashtag-search)**.
- Review author, engagement, media, and publication details with **[Facebook Hashtag Scraper](https://apify.com/maximedupre/facebook-hashtag-scraper/examples/facebook-hashtag-scraper)**.

#### 📊 Facebook hashtag post data

**What you get**

Each saved row is one available public Facebook post that matched the submitted hashtag settings. It includes the post ID and URL, the available post format, text, author details, engagement counts, attached media, and publication time. Some optional values are not present when Facebook does not expose them.

- **Post identity:** `postId`, `postUrl`, and `postFormat` identify the source post and its available format.
- **Post content:** `postText` holds the title, caption, text, or description when available.
- **Author details:** `author` holds public author names, IDs, profile links, and avatar links when available.
- **Engagement:** `engagement` holds reported reaction, comment, share, and view values, plus the reported total.
- **Media details:** `media` lists available attached media types, IDs, links, and thumbnails.
- **Publication time:** `publishedAt` holds the source publication time when available.

#### ▶️ Run a Facebook hashtag search

**How it works**

1. Add one or more hashtag values.
2. Choose post formats or leave the format list empty to include all available formats.
3. Choose any time, the last month, or the last year.
4. Set an optional maximum number of posts and start the run.
5. Open the default dataset from the run output.

The same format and time settings apply to every hashtag in the run. The Actor saves the first eligible occurrence of a source post. If the same post appears again through another submitted hashtag, the later match is ignored. The saved row describes only that first match and does not combine later matches.

#### ⚙️ Input

**Input fields**

| Field | Type | What it does |
|---|---|---|
| `hashtags` | array of strings | Required. Add one or more hashtags to search. The same filters apply to every value. |
| `postFormats` | array of strings | Choose `reels`, `videos`, or `photos`. Leave the list empty to include all available formats. |
| `timeRange` | string | Choose `any`, `lastMonth`, or `lastYear`. The filter uses each post's available publication time. |
| `maxItems` | integer | Optional run limit with a minimum of `1`. Leave it empty to return all available posts until the source is exhausted. Otherwise, stop after this many posts. The schema has no upper bound. |

**Default input example**

This example is copied from the public input of a successful current-beta run that used the hosted default input:

```json
{
  "hashtags": [
    "travel"
  ],
  "postFormats": [
    "reels",
    "videos",
    "photos"
  ],
  "timeRange": "any",
  "maxItems": 100
}
```

#### 🧾 Output

**Run output link**

| Field | Type | What it does |
|---|---|---|
| `datasetItems` | string | Opens the default dataset overview with the saved public Facebook post rows. |

**Dataset row**

All saved rows use one shape. Optional fields are omitted when Facebook does not expose them.

| Field | Type | What it does |
|---|---|---|
| `postId` | string | Gives the source ID of the Facebook post. |
| `postUrl` | string (URL) | Gives a direct link to the Facebook post. |
| `postFormat` | string | Gives the available format, such as `reel`, `video`, or `photo`. |
| `postText` | string | Gives the title, caption, text, or description when available. |
| `author` | object | Holds public author details when available. |
| `author.id` | string | Gives the public author's source ID when available. |
| `author.name` | string | Gives the public author's name when available. |
| `author.url` | string (URL) | Gives a direct link to the public author profile when available. |
| `author.avatarUrl` | string (URL) | Gives a link to the author's public avatar image when available. |
| `engagement` | object | Holds engagement values reported for the post when available. |
| `engagement.reactions` | object | Holds counts for the reaction types reported by the source. |
| `engagement.reactions.like` | integer | Gives the number of Like reactions when reported. |
| `engagement.reactions.love` | integer | Gives the number of Love reactions when reported. |
| `engagement.reactions.haha` | integer | Gives the number of Haha reactions when reported. |
| `engagement.reactions.wow` | integer | Gives the number of Wow reactions when reported. |
| `engagement.reactions.sad` | integer | Gives the number of Sad reactions when reported. |
| `engagement.reactions.angry` | integer | Gives the number of Angry reactions when reported. |
| `engagement.comments` | integer | Gives the number of comments reported for the post. |
| `engagement.shares` | integer | Gives the number of shares reported for the post. |
| `engagement.totalEngagement` | integer | Gives the aggregate engagement value reported by the source. |
| `media` | array of objects | Lists attached media details when available. |
| `media[].type` | string | Gives the type of an attached media item, such as `photo`, `video`, or `reel`. |
| `media[].id` | string | Gives the source ID of an attached media item when available. |
| `media[].url` | string (URL) | Gives a direct source link to an attached media item when available. |
| `media[].thumbnailUrl` | string (URL) | Gives a link to a thumbnail for an attached media item when available. |
| `publishedAt` | string (date-time) | Gives the date and time when the source post was published, when available. |

**Example Facebook post**

This complete row is genuine output from the latest successful current-beta run. It is shown without invented or redacted source data.

```json
{
  "postId": "1526323986202837",
  "postUrl": "https://www.facebook.com/CNNArabic/posts/pfbid02Ckyxw6GQVof8G1ckuNTmBsmS6JyxQod5nTDmzUEWReKwkwdwJCeGn7oADb1pu6B4l",
  "postFormat": "photo",
  "postText": "البيت الأبيض يستبعد شبكة CNN من مهمتها المقررة ليوم الاثنين، والتي كانت تتضمن تمثيل المجموعة التلفزيونية المشتركة (pool) نيابة عن كامل هيئة الصحافة المعتمدة https://cnn.it/4ApHYfS",
  "author": {
    "id": "100064757498431",
    "name": "CNNArabic",
    "url": "https://www.facebook.com/CNNArabic",
    "avatarUrl": "https://scontent-arn2-1.xx.fbcdn.net/v/t39.30808-1/342200996_189496030550854_7062570227724457374_n.jpg?stp=cp0_dst-jpg_tt6&cstp=mx2048x2048&ctp=s50x50&_nc_cat=1&ccb=1-7&_nc_sid=2d3e12&_nc_ohc=cUtgm7iDeq8Q7kNvwFFntyl&_nc_oc=AdrUrfni-pFpdv1ltmdjFCK16zO5Hj2T7PRphnGrR7JQmvtZEmKfaAsSXMkTF-iEk-E&_nc_zt=24&_nc_ht=scontent-arn2-1.xx&_nc_gid=wcMbzAjiLNwsao0-LA_BTw&_nc_ss=70289&oh=00_AQIR4b55SiqmtBKLdmhpLw4qIacbDSPJoKsP9MnkjK1oGA&oe=6AB67236"
  },
  "engagement": {
    "comments": 1,
    "shares": 2,
    "reactions": {
      "like": 17,
      "haha": 6,
      "wow": 1
    },
    "totalEngagement": 27
  },
  "media": [
    {
      "type": "photo",
      "id": "1526323962869506",
      "url": "https://scontent-arn2-1.xx.fbcdn.net/v/t39.99422-6/796527992_1584024433502671_839914819866181719_n.png?stp=dst-jpg_tt6&cstp=mx1080x1350&ctp=s640x640&_nc_cat=100&ccb=1-7&_nc_sid=127cfc&_nc_ohc=URELPtjkRGIQ7kNvwEFzmBx&_nc_oc=AdrNlwY_2dX44np32DeoQuxO4iAqAkwMd4FxiDMjG9-Uivr6R8QSK9eGAE9IqTEbExc&_nc_zt=14&_nc_ht=scontent-arn2-1.xx&_nc_gid=wcMbzAjiLNwsao0-LA_BTw&_nc_ss=70289&oh=00_AQKThG9bSr-8xm-IGELh93nWVUMIZlAe5HDOK3XdiO6PSQ&oe=6AB67D64",
      "thumbnailUrl": "https://scontent-arn2-1.xx.fbcdn.net/v/t39.99422-6/796527992_1584024433502671_839914819866181719_n.png?stp=dst-jpg_tt6&cstp=mx1080x1350&ctp=s640x640&_nc_cat=100&ccb=1-7&_nc_sid=127cfc&_nc_ohc=URELPtjkRGIQ7kNvwEFzmBx&_nc_oc=AdrNlwY_2dX44np32DeoQuxO4iAqAkwMd4FxiDMjG9-Uivr6R8QSK9eGAE9IqTEbExc&_nc_zt=14&_nc_ht=scontent-arn2-1.xx&_nc_gid=wcMbzAjiLNwsao0-LA_BTw&_nc_ss=70289&oh=00_AQKThG9bSr-8xm-IGELh93nWVUMIZlAe5HDOK3XdiO6PSQ&oe=6AB67D64"
    }
  ],
  "publishedAt": "2026-09-21T04:34:31.000Z"
}
```

#### 💳 Pricing

**How charges work**

This Actor uses pay-per-event pricing. The primary event is `facebook-hashtag-post`, priced at `$0.00265` per event. Each event covers one post matching the requested Facebook hashtag filters.

#### 🔌 Integrations

Use the Apify Console or API to start runs and read the default dataset. The run output links to the saved public post rows.

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### What happens when the same post matches more than one hashtag?

The Actor saves the first eligible occurrence and ignores later matches for the same source post. The saved row describes only that first match and does not combine later hashtags or submitted values.

##### Can I search more than one hashtag in one run?

Yes. Add several hashtags to the list. All of them use the same post format, time range, and maximum-post setting.

##### What does an empty post format list do?

An empty `postFormats` list includes all available post formats. Add `reels`, `videos`, or `photos` when you want to narrow the saved rows.

##### What happens when I leave Maximum posts empty?

The Actor returns all available posts until the source is exhausted. The schema has no upper bound for `maxItems`, so a run can return fewer posts when the source has fewer eligible results.

##### Why is a field missing from a row?

Facebook does not expose the same fields for every public post. Optional author, engagement, media, text, and publication values are included only when they are available.

##### Can it collect private or deleted Facebook posts?

No. The Actor is for available public hashtag results. Private, restricted, deleted, and otherwise unavailable content is outside its scope.

##### Does it include comments or lists of people who reacted?

No. It includes engagement counts and available reaction counts. It does not collect comments, replies, commenter lists, liker lists, or sharer lists.

##### Does it download Facebook photos or videos?

No. It returns available media metadata, links, and thumbnails. It does not download or mirror source photo and video files.

##### Will it always return every Facebook post for a hashtag?

No. The Actor returns available matching posts and does not promise an exhaustive list of every post Facebook could associate with a hashtag.

### 📝 Changelog

**v0.0** (21-09-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~facebook-hashtag-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [Facebook User Posts Scraper](https://apify.com/maximedupre/facebook-user-posts-scraper): collect public posts from Facebook profiles, Pages, and known post URLs.
- [Instagram Hashtag Username Scraper](https://apify.com/maximedupre/instagram-hashtag-username-scraper): find public Instagram posts and usernames for hashtag research.
- [TikTok Hashtag Search Scraper](https://apify.com/maximedupre/tiktok-hashtag-search-scraper): find public TikTok hashtag metrics from keywords, hashtags, or tag URLs.
- [Facebook Hashtag Search Scraper](https://apify.com/easyapi/facebook-hashtag-search-scraper): collect Facebook hashtag posts with post and author details.
- [Facebook Hashtag Scraper](https://apify.com/scraping_solutions/facebook-hashtag-scraper): run another Facebook hashtag post search for trend and content research.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `hashtags` (type: `array`):

Enter one or more hashtags to search. The same filters apply to every hashtag.

## `postFormats` (type: `array`):

After available posts are collected, keep posts classified as reels, videos, or photos. Leave this list empty to include all available formats.

## `timeRange` (type: `string`):

Choose which post timestamps to keep after available posts are collected. This uses each post's available publication time.

## `maxItems` (type: `integer`):

Leave this empty to return all available posts until the source is exhausted. Otherwise, stop after this many posts.

## Actor input object example

```json
{
  "hashtags": [
    "travel",
    "photography"
  ],
  "postFormats": [
    "reels",
    "photos"
  ],
  "timeRange": "lastMonth",
  "maxItems": 100
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Open the collected public Facebook posts in the default dataset.

# 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 = {
    "hashtags": [
        "travel"
    ],
    "postFormats": [
        "reels",
        "videos",
        "photos"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/facebook-hashtag-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 = {
    "hashtags": ["travel"],
    "postFormats": [
        "reels",
        "videos",
        "photos",
    ],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/facebook-hashtag-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 '{
  "hashtags": [
    "travel"
  ],
  "postFormats": [
    "reels",
    "videos",
    "photos"
  ],
  "maxItems": 100
}' |
apify call maximedupre/facebook-hashtag-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/facebook-hashtag-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/wXDfVhYiLHOz3O9eA/builds/2IXNjQCUQWAPnr40j/openapi.json
