# Product Hunt Scraper (`romajure/product-hunt-scraper`) Actor

Scrape Product Hunt without login: daily, weekly, monthly leaderboards, topics, search and products with votes, comments, makers, website URLs. Pay per product.

- **URL**: https://apify.com/romajure/product-hunt-scraper.md
- **Developed by:** [Romas Jurevicius](https://apify.com/romajure) (community)
- **Categories:** News, AI
- **Stats:** 3 total users, 2 monthly users, 91.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 product scrapeds

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

### Product Hunt Scraper

Product Hunt Scraper turns Product Hunt into a clean, machine-readable feed of launches. It returns one JSON record per product launch - "Onepin, #1 Product of the Day, 401 votes" - with the name, tagline, full description, vote and comment counts, the position on the leaderboard you asked for, the launch date, the topics, the makers and the hunter (name, username, headline, profile URL), the thumbnail, the gallery images and videos, the pricing type, the daily/weekly/monthly badges, the product's review score, the Product Hunt URL and the **product's own website URL with Product Hunt's `ref=producthunt` and utm parameters stripped**. Optionally it attaches the launch discussion: every comment thread with its replies, author, votes and date.

No account, API key or login is needed. The Actor reads the same public GraphQL endpoint the Product Hunt web app uses (`www.producthunt.com/frontend/graphql`), with the request shape that endpoint expects (persisted-query hash plus the XHR header). If you have an official API v2 developer token you can supply it and leaderboards, topics and products are read from `api.producthunt.com/v2/api/graphql` instead.

Typical uses: tracking which products launch every day for a newsletter or a Slack digest, monitoring competitors in a topic such as `artificial-intelligence` or `developer-tools`, building a lead list of makers who just launched (with their real website, not a redirect), researching how launches in a category perform (votes, comments, pricing), or pulling the discussion of a specific launch for sentiment analysis.

Four modes are supported:

- **`leaderboard`** - the daily, weekly or monthly ranking for a given date (default: today in US Pacific, Product Hunt's clock). Records carry `rank`.
- **`topic`** - the products listed under one or more topic slugs (`artificial-intelligence`, `saas`, `marketing`), ordered like the topic page (highest rated) or by most recent launch. Each record is the product's latest launch.
- **`search`** - Product Hunt's product search for a free-text query. Each record is the matching product's latest launch.
- **`products`** - specific launches or products by URL: `/products/<slug>` gives the product's latest launch, `/posts/<slug>` or `/products/<slug>/launches/<launch>` one specific launch.

### How to scrape Product Hunt

1. Open the Actor in Apify Console and click **Try for free**.
2. Pick a **Mode**. For `leaderboard` choose the **Period** and optionally a **Date** (`2026-10-10`); for `topic` enter topic slugs; for `search` a **Query**; for `products` the Product Hunt URLs.
3. Set **Max items** (default 20). Turn on **Include comments** if you want the launch discussion (default 30 comments per product, adjustable with **Max comments per product**). Turn off **Include makers and hunter** for leaner records.
4. Leave **Proxy configuration** on Apify Proxy (recommended) and click **Start**.
5. Results appear in the **Output** tab within seconds and can be downloaded as JSON, CSV or Excel, or read through the API.

#### How the fetching works

Leaderboards are read with Product Hunt's own feed query (`homefeedItems` ordered by `DAILY_RANK`, `WEEKLY_RANK` or `MONTHLY_RANK`, 20 items per page, cursor pagination) - the exact data the leaderboard page renders, including the site's own rank. Promoted "Ad" slots that Product Hunt mixes into the feed are skipped and never charged. Topic pages use the topic's product listing (`topic.products`, 20 per page), search uses `productSearch` (page-number pagination), and products mode looks launches up by slug. Every record is built from a single Post node that already includes the product's website, makers, hunter, topics, badges and media, so there is normally **one request per 20 products**. Only when a launch has no website on record does the Actor follow the `/r/p/<id>` short link (one tiny request, explicitly allowed by Product Hunt's robots.txt) to recover it.

Comments come from the launch's thread list (30 threads per request, each with up to 10 replies) in Product Hunt's default "most relevant" order, flattened as thread, replies, next thread. `isReply` and `parentId` keep the structure.

Requests go through a shared client with a 400 ms politeness gap, at most two in flight, browser-like TLS and headers, and retries on network errors, 429 and 5xx. The client keeps one proxy session (one IP) for as long as it passes Cloudflare and rotates it only after a 403, retrying up to four times through fresh sessions; a persisting Cloudflare challenge is reported as a `blocked` status record with the HTTP status and body snippet, never as an empty success. Every pushed launch id is remembered in the run state so a migrated or resurrected run never charges the same product twice.

### Product Hunt Scraper pricing

This Actor uses Apify's **pay-per-event** model. There is no subscription and no per-result platform fee on top:

- **Actor start**: a flat fee of $0.00005 per run.
- **Product scraped**: **$0.0015 per product / launch** pushed to your dataset ($1.50 per 1,000 products).
- **Comment scraped**: **$0.0005 per comment** attached to a pushed product (only with **Include comments** on).

A daily leaderboard (about 25-35 featured launches) costs around $0.05; a 100-product topic listing $0.15; a single product with 30 comments $0.0165. Status records (blocked, not found, empty, error) are free. You can cap spending with **Maximum cost per run**; when the cap is reached the Actor stops cleanly and keeps everything scraped so far. If the remaining budget covers only part of a product's comments, the product is pushed with the comments that were charged.

### Input example

```json
{
    "mode": "leaderboard",
    "period": "daily",
    "date": "2026-10-10",
    "maxItems": 30,
    "includeComments": false,
    "maxCommentsPerProduct": 30,
    "includeMakers": true,
    "proxyConfiguration": { "useApifyProxy": true }
}
```

#### Input fields

| Field                   | Type                                            | Default            | Description                                                                                                             |
| ----------------------- | ----------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `mode`                  | `leaderboard` / `topic` / `search` / `products` | `leaderboard`      | What to scrape.                                                                                                         |
| `period`                | `daily` / `weekly` / `monthly`                  | `daily`            | Leaderboard mode: the ranking period.                                                                                   |
| `date`                  | `YYYY-MM-DD`                                    | today (US Pacific) | Leaderboard mode: the day, the ISO week containing it, or the month containing it.                                      |
| `topics`                | array of strings                                | -                  | Topic mode: topic slugs from `producthunt.com/topics/<slug>` (full URLs accepted).                                      |
| `topicOrder`            | `highest_rated` / `most_recent_launch`          | `highest_rated`    | Topic mode: the topic page's default order, or newest launches first.                                                   |
| `query`                 | string                                          | -                  | Search mode: free-text product search.                                                                                  |
| `productUrls`           | array of strings                                | -                  | Products mode: `/products/<slug>`, `/posts/<slug>` or `/products/<slug>/launches/<launch>` URLs, or bare product slugs. |
| `maxItems`              | integer                                         | `20`               | Stop after this many products (across all topics / URLs).                                                               |
| `includeComments`       | boolean                                         | `false`            | Attach the launch discussion (`comments`).                                                                              |
| `maxCommentsPerProduct` | integer                                         | `30`               | Cap on comments per product, 1-500.                                                                                     |
| `includeMakers`         | boolean                                         | `true`             | Attach `makers` and `hunter`.                                                                                           |
| `apiToken`              | secret string                                   | -                  | Optional official API v2 developer token; see below.                                                                    |
| `proxyConfiguration`    | object                                          | Apify Proxy        | Standard proxy settings.                                                                                                |

### Output example

```json
{
    "id": "1257662",
    "slug": "onepin",
    "name": "Onepin",
    "tagline": "AI voiceover with every name, price and date said right",
    "description": "AI voices sound human now. But they still guess names from the spelling, and nobody has time to listen to every line. Onepin runs on the voices you already use (ElevenLabs, OpenAI, Google, 30+ more), spells out prices and dates, checks names against a 4M-word pronunciation dictionary, scores every line, and fixes the wrong word without re-rendering the take.",
    "url": "https://www.producthunt.com/posts/onepin",
    "productSlug": "onepin",
    "productUrl": "https://www.producthunt.com/products/onepin",
    "websiteUrl": "https://onepin.ai/",
    "votesCount": 401,
    "commentsCount": 61,
    "rank": 1,
    "launchDate": "2026-10-10T07:01:00.000Z",
    "topics": ["developer-tools", "artificial-intelligence", "audio"],
    "makers": [
        {
            "name": "Soohyun Bae",
            "username": "soohyun",
            "headline": "CEO of Onepin",
            "url": "https://www.producthunt.com/@soohyun",
            "avatarUrl": "https://ph-avatars.imgix.net/4108508/original.jpeg"
        }
    ],
    "hunter": {
        "name": "Rohan Chaubey",
        "username": "rohanrecommends",
        "headline": "Top Hunter | Author | Startup Advisor",
        "url": "https://www.producthunt.com/@rohanrecommends",
        "avatarUrl": "https://ph-avatars.imgix.net/4325010/a8bdb2a7-d1ec-444a-9823-2833c30c540c.jpeg"
    },
    "thumbnailUrl": "https://ph-files.imgix.net/25268265-e582-4351-8a6e-1f94e6959d71.png?auto=format",
    "galleryUrls": ["https://ph-files.imgix.net/59e2d20a-8e04-423f-ac81-90fa2a2d6af6.png?auto=format"],
    "videoUrls": ["https://www.youtube.com/watch?v=ijQ_XeMYz00"],
    "pricingType": "freemium",
    "badges": [
        {
            "type": "top_post",
            "position": 1,
            "period": "daily",
            "date": "2026-10-10",
            "label": "#1 Product of the Day (2026-10-10)"
        }
    ],
    "reviewsRating": 0,
    "reviewsCount": 0,
    "comments": [
        {
            "id": "5936741",
            "author": {
                "name": "Emma Pugsley",
                "username": "you_x_you_i",
                "headline": "Building a website optimizer",
                "url": "https://www.producthunt.com/@you_x_you_i",
                "avatarUrl": "https://ph-avatars.imgix.net/9810694/avatar.png"
            },
            "body": "Congratulations on the launch. ReSO AI sounds very comprehensive ...",
            "votes": 11,
            "date": "2026-10-10T07:57:08.000Z",
            "isReply": false,
            "parentId": null,
            "url": "https://www.producthunt.com/products/reso?comment=5936741"
        }
    ],
    "source": "frontend",
    "scrapedAt": "2026-10-11T07:12:41.000Z"
}
```

`rank` is the position on the requested leaderboard (null in other modes). `pricingType` is `free`, `freemium` (Product Hunt's "free options") or `paid`. `badges` lists Product of the Day/Week/Month/Year positions and Golden Kitty awards. `reviewsRating` and `reviewsCount` are the product-level review score (0-5) where the listing exposes it. `comments` is only present when **Include comments** is on. `source` is `frontend` (website, no login) or `api-v2` (token).

### Integrations

Connect the Actor to Google Sheets, Slack, Airtable, Make, Zapier, n8n or your own code through Apify's [integrations](https://docs.apify.com/platform/integrations). Schedule it daily to archive every leaderboard, or call it from an LLM agent through the Apify MCP server or the API client (`apify-client` for JavaScript and Python).

### Sources and limitations

- **Website GraphQL (default, no token).** Product Hunt's web app calls `www.producthunt.com/frontend/graphql` without authentication; the endpoint executes persisted queries and accepts a new document when it arrives with its SHA-256 hash and the `X-Requested-With: XMLHttpRequest` header. The Actor's documents only select fields the web app itself selects, so they match the live schema. If Product Hunt changes the schema or the persisted-query policy, the run reports it precisely (`blocked` or `error` status with the server's message) instead of returning partial data. This path is working as of October 2026 but is not an official API; treat it as best effort.
- **Cloudflare.** The site sits behind a Cloudflare managed challenge. A browser-like TLS/header fingerprint passes it (that is how this Actor runs); plain `curl` does not. Through Apify Proxy roughly one datacenter session in three is challenged on its first request, which is why the client sticks to a session that passed and rotates only on a 403 (up to five attempts per request). If a run still ends with a `blocked` record, retry, switch to a residential proxy group, or use `apiToken`.
- **robots.txt.** `/search*` pages are disallowed, so the Actor never fetches them: search goes through the GraphQL `productSearch` field the site's own search uses. `/r/p/*` short links are explicitly allowed and are the only non-GraphQL requests made.
- **Official API v2 (`apiToken`).** Implemented from the published schema (`posts` with `postedAfter`/`postedBefore`/`topic`/`order`, `post(slug)`, nested `comments`). The token path could not be exercised end to end while building this version (no token was available), so treat it as a documented, untested alternative. API v2 has no text search (search always uses the website), no product-level review score, no pricing type and no badges, and nests at most 20 comments per post; rank is the position in the vote-ordered result, not the site's badge.
- **Rank and votes move.** Daily boards fill in during the day (US Pacific); scraping a day before 23:59 PT gives an intermediate ranking. `votesCount` is the live count at scrape time.
- **Search and topic records are products,** each represented by its latest launch; a product with several launches appears once. A topic page lists products tagged with that topic at product level, so the launch's own `topics` (first 10 tags of that launch) do not always include the topic you asked for - in a 40-item `artificial-intelligence` run, 21 launches carried the tag themselves.

### Product Hunt Scraper FAQ

#### Which date does the daily leaderboard use?

Product Hunt's day runs on US Pacific time; `date` is interpreted in that zone, and the default is today in that zone. `weekly` uses the ISO week (Monday to Sunday) containing the date, matching `/leaderboard/weekly/<year>/<week>`.

#### Why is `websiteUrl` sometimes null?

The launch has no website on record and its short link did not redirect (usually a product that is no longer online). Everything else on the record is still filled.

#### Can I get the Product of the Month badges for older months?

Yes - `period: "monthly"` with any past `date`. Monthly boards list a few hundred launches; raise `maxItems` accordingly.

#### How much does a full day cost?

A daily board is typically 25-35 launches, so about $0.04-0.05 without comments. With 30 comments per product, add about $0.015 per product.

#### What happens if Product Hunt blocks the request?

The Actor pushes a free `blocked` status record quoting the HTTP status and body, stops, and fails the run if nothing was collected - it never reports an empty dataset as success.

### Related actors

Same author, same pay-per-event model and the same no-login approach. They combine well in one pipeline (for example calendar events plus prediction odds plus channel chatter around a release):

- [Telegram Channel Scraper](https://apify.com/romajure/telegram-channel-scraper) - posts, views, media and links from public Telegram channels, no login.
- [Substack Scraper](https://apify.com/romajure/substack-scraper) - posts, authors, likes, restacks and comments from public Substack publications, custom domains included.
- [Economic Calendar Scraper](https://apify.com/romajure/economic-calendar) - Forex Factory and Investing.com macro events with UTC times, impact, actual, forecast and previous values.
- [Prediction Market Odds Scraper](https://apify.com/romajure/prediction-market-odds) - Polymarket and Kalshi markets with 0-1 prices, implied probabilities, bid/ask, volume and orderbooks.

### Legal and compliance

The Actor reads publicly available pages and the public endpoint behind them without logging in, keeps request rates low (two requests at a time, 400 ms apart) and respects Product Hunt's robots.txt. Scraping public data is generally legal, but you are responsible for complying with Product Hunt's Terms of Service, the API terms if you use a token, and applicable laws such as GDPR when you store personal data (maker, hunter and commenter names are personal data). Use the data for your own research, monitoring and analysis; do not republish it as a Product Hunt clone.

### Support

Found a bug, need a field that is missing, or want a different output shape? Open an issue in the Actor's **Issues** tab in Apify Console.

# Actor input Schema

## `mode` (type: `string`):

`leaderboard`: the daily / weekly / monthly ranking (uses **Period** and **Date**). `topic`: products listed under topic slugs (uses **Topics**). `search`: product search (uses **Query**). `products`: specific launches or products by URL (uses **Product URLs**).

## `period` (type: `string`):

Leaderboard mode only. `daily` ranks the launches of one day, `weekly` the ISO week containing **Date**, `monthly` the month containing **Date**.

## `date` (type: `string`):

Leaderboard mode only. ISO date (`2026-10-10`) selecting the day, week or month. Defaults to today in Product Hunt's timezone (US Pacific).

## `topics` (type: `array`):

Topic mode only. Topic slugs as they appear in `producthunt.com/topics/<slug>`, e.g. `artificial-intelligence`, `developer-tools`, `productivity`, `saas`, `marketing`.

## `topicOrder` (type: `string`):

Topic mode only. `highest_rated` mirrors the topic page (best-reviewed products first); `most_recent_launch` lists the newest launches in the topic first.

## `query` (type: `string`):

Search mode only. Free-text product search, e.g. `notion`, `ai note taking`, `invoice`.

## `productUrls` (type: `array`):

Products mode only. Product Hunt URLs or slugs: `https://www.producthunt.com/products/<slug>` (latest launch of the product), `https://www.producthunt.com/posts/<launch-slug>` or `.../products/<slug>/launches/<launch-slug>` (one specific launch). A bare `slug` is treated as a product slug.

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

Stop after this many products have been pushed (across all topics / URLs in the run). Each product is one `product-scraped` event.

## `includeComments` (type: `boolean`):

Fetch the launch discussion for every product (threads and their replies, most relevant first). One extra request per 30 comments; each comment is a `comment-scraped` event.

## `maxCommentsPerProduct` (type: `integer`):

Upper bound on comments collected per product when **Include comments** is on.

## `includeMakers` (type: `boolean`):

Attach the maker team and the hunter (name, username, headline, profile URL) to every product. Turn off to keep records lean.

## `apiToken` (type: `string`):

Optional developer token from api.producthunt.com/v2/docs. When set, leaderboard, topic and products modes read from the official API v2 (`api.producthunt.com/v2/api/graphql`) instead of the public website; search always uses the website because API v2 has no text search. Leave empty to run without any token.

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

Proxy settings. Apify Proxy is recommended; Product Hunt sits behind Cloudflare and a datacenter session with browser-like TLS passes it, a bare curl does not.

## Actor input object example

```json
{
  "mode": "leaderboard",
  "period": "daily",
  "topics": [
    "artificial-intelligence"
  ],
  "topicOrder": "highest_rated",
  "productUrls": [
    "https://www.producthunt.com/products/notion"
  ],
  "maxItems": 20,
  "includeComments": false,
  "maxCommentsPerProduct": 30,
  "includeMakers": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `products` (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 = {
    "mode": "leaderboard",
    "period": "daily",
    "topics": [
        "artificial-intelligence"
    ],
    "topicOrder": "highest_rated",
    "productUrls": [
        "https://www.producthunt.com/products/notion"
    ],
    "maxItems": 20,
    "maxCommentsPerProduct": 30,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("romajure/product-hunt-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 = {
    "mode": "leaderboard",
    "period": "daily",
    "topics": ["artificial-intelligence"],
    "topicOrder": "highest_rated",
    "productUrls": ["https://www.producthunt.com/products/notion"],
    "maxItems": 20,
    "maxCommentsPerProduct": 30,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("romajure/product-hunt-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 '{
  "mode": "leaderboard",
  "period": "daily",
  "topics": [
    "artificial-intelligence"
  ],
  "topicOrder": "highest_rated",
  "productUrls": [
    "https://www.producthunt.com/products/notion"
  ],
  "maxItems": 20,
  "maxCommentsPerProduct": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call romajure/product-hunt-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,romajure/product-hunt-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/4MJBnZc3b57rOCSoT/builds/eLt5lBoi1uJZLmGaA/openapi.json
