# Product Hunt Launches Scraper (`dami_studio/producthunt-scraper`) Actor

Product Hunt launches scraper API for the daily, weekly, monthly and yearly boards, topic pages or product URLs. Each row has the name, tagline, upvotes, comments, makers, website, rank and launch date. Only the daily board goes past a top 20. No login. $0.45 per 1,000 launches.

- **URL**: https://apify.com/dami_studio/producthunt-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** E-commerce, Lead generation
- **Features:** Limited permissions, Multi-tenant, Server interface
- **Stats:** 7 total users, 5 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.44 / 1,000 products

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

**Product Hunt scraper for launches by day, week, month or year**, or by topic and product address: every
launch comes back as a row with its name, tagline, upvote and comment counts, topics, rank, launch
date and the product's own website.

Worth knowing before you plan around it: only the daily board is deep. The weekly, monthly and yearly
boards are the top 20 each, so a year of weeklies is about a thousand rows, not the whole year of
launches.

| | |
|---|---|
| **Input** | A leaderboard period plus dates, topic slugs, or Product Hunt URLs |
| **Output** | One row per launch: name, tagline, upvotes, comments, topics, rank, makers and website |
| **Ceiling** | 120 pages and 2,000 rows per run |
| **Account needed** | None |
| **Price** | $0.45 per 1,000 launches on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 11,000 |

### 🔍 What Product Hunt Launches Scraper does

Three routes into the same data, and you can mix them in one run.

The **leaderboards** are the usual way in. Pick `daily` with a date range and you get one page per
day. Pick `weekly`, `monthly` or `yearly` and you get the top 20 of
each period your range touches.

**Topics** take the slug out of a Product Hunt topic address, like `artificial-intelligence` or
`developer-tools`, and return what Product Hunt currently ranks first in that topic.

**URLs** are the escape hatch. Any leaderboard, topic or product address you paste is read in
addition to whatever the date range generated.

### 📋 What data you get from each Product Hunt launch

| What you get | Field |
|---|---|
| The launch: name, tagline and description | `productName`, `tagline`, `description` |
| Votes and comments when the page was read | `upvotes`, `commentsCount` |
| Where it finished, and when it launched | `rank`, `launchedAt` |
| How Product Hunt files it, and who made it | `topics`, `makers` |
| The product's own site, and its Product Hunt page | `websiteUrl`, `productHuntUrl`, `slug`, `thumbnailUrl` |
| The launch id, for deduping | `postId` |
| The review summary Product Hunt shows | `reviewsRating`, `reviewsCount` |
| Where the row came from, and when | `inputUrl`, `scrapedAt` |
| What kind of row it is | `ok`, `charged`, `recordType` |

### ▶️ How to scrape Product Hunt launches

1. Open [Product Hunt Launches Scraper](https://apify.com/dami_studio/producthunt-scraper) and click
   **Try for free**.
2. Choose a **Leaderboard period**, then set **From date** and **To date**.
3. Or skip that and paste addresses into **Product Hunt URLs**, or topic slugs into **Topics**.
4. Set **Maximum rows**. Keep it low on the first run.
5. Click **Start**, then download the dataset as JSON, CSV or Excel.

Run it with nothing filled in and you get one labelled sample row, which is not charged.

### 💰 How much does it cost to scrape Product Hunt?

**$0.45 per 1,000 launches** on the Free plan, $0.445 on Starter, $0.44 on Scale and $0.435 on Business. On the free
plan, the $5 Apify gives you each month covers about 11,000 launches.

One charge per launch row. A launch that turns up on more than one leaderboard in the same run, say a
daily board and that week's board, is charged once. Topic and product pages count separately: a
product that ranks in two of your topics comes back, and is charged, once for each. Paid placements
on a board are left out. Sample and diagnostic rows are never charged.

### 📥 What you give it

Every field is optional.

```json
{
  "leaderboardPeriod": "daily",
  "dateFrom": "2026-08-09",
  "dateTo": "2026-08-15",
  "maxItems": 100
}
```

| Field | Default | What it is |
|---|---|---|
| `leaderboardPeriod` | none | `daily`, `weekly`, `monthly` or `yearly`. Leave it out if you are supplying your own URLs or topics. |
| `dateFrom` | six days before `dateTo` | `YYYY-MM-DD`. `2026/8/9` is also accepted. With the default `dateTo`, that makes the seven days ending yesterday. |
| `dateTo` | yesterday | Yesterday in UTC, not today. |
| `topics` | none | Up to 40 topic slugs, as they appear in the address. |
| `startUrls` | none | Up to 120 leaderboard, topic or product addresses. |
| `maxItems` | `20` | Total rows across every page, 1 to 2,000. |
| `includeDetails` | `true` | Fetches each product's own page for the description, the maker names and the website. One extra read per row. Turn it off for ranking and engagement numbers only. |
| `proxyUrls` | none | Your own servers, one per line as `http://user:pass@host:port`, if you want the run to go out through them. Leave it empty otherwise. |

**A date in any other shape, or a `dateFrom` after `dateTo`, stops the run before it reads a page.**
You get one free `BAD_INPUT` row that names the date to fix, and no launches are charged.

### 📤 What you get back

A real row:

```json
{
  "ok": true,
  "charged": true,
  "recordType": "product",
  "productName": "Omniwork",
  "tagline": "The Creative Agent OS, create better with desktop AI agents",
  "description": "Omniwork is an always-on Creative Agent OS that turns ideas into finished work. ...",
  "upvotes": 416,
  "commentsCount": 41,
  "topics": ["Productivity", "Artificial Intelligence", "Social media marketing"],
  "makers": ["Zoey Chen", "Finn Ding", "Shihao_Huang", "Tiana", "Abby Mao"],
  "websiteUrl": "https://www.omniwork.ai",
  "thumbnailUrl": "https://ph-files.imgix.net/ca9f8039-1afd-45fb-8410-e43e4f63d929.png",
  "launchedAt": "2026-08-09T07:01:00.000Z",
  "rank": 1,
  "productHuntUrl": "https://www.producthunt.com/products/omniwork-2",
  "slug": "omniwork-2",
  "postId": "1196035",
  "reviewsRating": 0,
  "reviewsCount": 0,
  "inputUrl": "https://www.producthunt.com/leaderboard/daily/2026/8/9",
  "scrapedAt": "2026-09-21T01:27:08.091Z"
}
```

The `description` there is cut short for this page. A real row carries the whole paragraph.

| Field | How to read it |
|---|---|
| `postId` | The launch id. The right key to dedupe and diff on, because a product can launch more than once. |
| `upvotes`, `commentsCount` | A snapshot taken when the page was read, not a final total. |
| `topics` | Up to three, as Product Hunt files them. |
| `makers` | Names only, and only when the page's launch matches the row. Older launches of a product that has shipped several, and rows that came from a topic page, have none. |
| `websiteUrl` | The product's own site, not the Product Hunt page. |
| `rank` | Position within that period's board. |
| `inputUrl` | The page the row came from, so you can trace it. |

### 🧾 Reading the output

| Row | How to spot it | Billed |
|---|---|---|
| A launch | `charged: true` and `recordType: "product"` | yes |
| A launch whose own page could not be read | `charged: false` and a `detailNote` | no |
| The sample row | `_sample: true` and `charged: false`, and only when the input named no target | no |
| A diagnostic | `_diagnostic: true`, `ok: false` and `recordType: "diagnostic"` | no |

The sample row also carries `ok: true` and `recordType: "product"`, so neither of those separates it.
Keep the rows where `charged` is `true`, or drop the rows that carry `_sample` or `_diagnostic`.

`charged` is written when the row is built, a moment before the charge goes out, so treat it as
"this is a real row" rather than as a receipt. A charge that fails adds a `CHARGE_ERROR` diagnostic
at the end of the run.

The Console's default table hides the diagnostic columns, so those rows look blank there. Download
the JSON, or add `errorCode` to the view, to read them.

| Code | What it means |
|---|---|
| `BAD_INPUT` | A date could not be read, or `dateFrom` came after `dateTo`. Nothing was read, and `details` says which date to fix. |
| `NO_RESULTS` | The page held no launches. A future date or an empty board does this. |
| `DUPLICATES` | Everything on that page had already been returned earlier in the same run. |
| `NOT_FOUND` | The address does not exist. Usually a mistyped product slug or an unknown topic. |
|`RATE_LIMITED` | That page could not be read on this run. Try again later. |
| `NOT_SERVED` | This launch was not served this run. Re-run it later. Runs before 13 October 2026 wrote `BLOCKED` here. |
| `NETWORK` | The page could not be reached. Re-run it. |
| `TIME_BUDGET` | The run ran out of time before reading that page, or before writing some of the products it found. Rows already collected are still delivered, and nothing was charged for the rest. The run still ends as succeeded, with an amber status message, even when the time limit stopped it before any product came back. |
| `CHARGE_ERROR` | One or more charges could not be recorded, so some rows may have gone out unbilled. |
| `UNEXPECTED_ERROR` | Something broke. Rows already written are kept. |
| `PROXY_INPUT_ADJUSTED` | A connection setting sent through the API is not offered here and was replaced. |

### 💡 What people use it for

- A weekly digest of what launched in a category, keyed on `postId` so nothing repeats.
- Collecting product websites from `websiteUrl`, which is the product's own domain rather than a profile.
- Tracking where a launch finished on its board, by reading `rank` across a date range.
- Seeing who is behind launches in a niche.

From last week's launches to the contact details each product publishes:

1. Choose **Daily** under **Leaderboard period** and clear **From date** and **To date**, so the run
   reads the seven days ending yesterday.
2. Set **Maximum rows** to 150, enough for a week of daily boards, and leave **Include description,
   makers and website** on so every row carries `websiteUrl`.
3. Paste the `websiteUrl` values into the **Websites** box of
   [Contact Details Scraper](https://apify.com/dami_studio/contact-details-scraper).

### 🚧 What it does not do

- **No keyword search.** You pick boards, topics or URLs. There is no query field.
- **Weekly, monthly and yearly boards are the top 20 only.** Only the daily board is deep.
- **Counts are a snapshot**, read at the moment the page was. They are not final totals.
- **Makers are names, not profiles.** No usernames, no links, no follower counts, and none at all on
  rows that came from a topic page.
- **No comments, no reviews text, no upvoter lists.** `reviewsRating` and `reviewsCount` are the
  summary numbers Product Hunt publishes, nothing more.
- **A product whose own page could not be read is not billed.** If the page failed, the row still
  arrives with the board's fields, `detailNote` and `charged: false`, and `description`, `makers` and
  `websiteUrl` empty; re-run those slugs if you need them. If the run's time ran out before the page
  was read, the product is left out and a `TIME_BUDGET` row counts it.
- **120 pages and 2,000 rows per run.** Anything past that is dropped, explicit URLs first in the
  queue. Split a bigger job across runs.
- **Today's board is deliberately out of reach** through the date range.
  Paste the URL if you want it anyway.
- It is not an official Product Hunt tool. Dami's Studio is independent and is not affiliated with or endorsed by Product Hunt, or by any other company named on this page.

### 🧭 Which launch and startup scraper do you need?

| If you want | Use |
|---|---|
| Product Hunt launches, with upvotes, makers and websites | This one |
| Y Combinator startups by batch, industry or status | [Y Combinator Companies Scraper](https://apify.com/dami_studio/ycombinator-companies-scraper) |
| Hacker News stories, Ask and Show HN posts, and comments | [Hacker News Scraper](https://apify.com/dami_studio/hacker-news-scraper) |
| Startup jobs with salary and equity | [Wellfound Jobs Scraper](https://apify.com/dami_studio/wellfound-jobs-scraper) |
| Emails, phones and socials published on a list of websites | [Contact Details Scraper](https://apify.com/dami_studio/contact-details-scraper) |

### ❓ Questions people ask

#### Do I need a Product Hunt account or an API token?

No. Nothing to paste in, nothing to renew.

#### Can I search for a keyword?

Not here. Read a topic or a date range and filter the rows yourself.

#### Why are `makers` empty on some rows?

Because that page's launch id did not match the row, which happens on older launches of a product
that has shipped several, and on every row that came from a topic page. An empty list beats a
guessed one.

#### Can I get today's launches?

Not through the date range. Paste today's leaderboard URL into `startUrls` if you want it anyway.

#### Can I call it from code or connect it to an AI assistant?

The [API tab](https://apify.com/dami_studio/producthunt-scraper/api/python) has code for Python, JavaScript and the
CLI. MCP clients like Claude and ChatGPT use
`https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/producthunt-scraper`; coding assistants can load [our
skill file](https://api.apify.com/v2/key-value-stores/BTBHU3DdiuoF4JOsK/records/apify-social-communities-SKILL.md).
All three bill your Apify account at the same price.

#### Is scraping Product Hunt legal?

Leaderboards, topic pages and product pages are public. Rows can carry people's names, which
data-protection law covers, so have a reason for collecting them. Apify's write-up on
[the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) is a fair start, and
we are not lawyers.

### 🆘 If something breaks

Open the **Issues** tab on the actor page. Send the run ID and the input you used; the diagnostic
row's `errorCode` and `inputUrl` name the page that went wrong.

# Actor input Schema

## `leaderboardPeriod` (type: `string`):

Which leaderboard to read. Daily gives one page per day in your date range (about 17-20 launches each). Weekly, monthly and yearly give the top 20 of each period the range touches. Leave empty if you are supplying your own URLs below.

## `dateFrom` (type: `string`):

First day to read, as YYYY-MM-DD, on or before the To date. Defaults to six days before the To date, which makes seven days. Up to 120 leaderboard pages per run.

## `dateTo` (type: `string`):

Last day to read, as YYYY-MM-DD. Defaults to yesterday.

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

Topic slugs, as they appear in a Product Hunt topic address - for example artificial-intelligence, developer-tools, productivity. Each topic returns the products Product Hunt currently ranks first in it.

## `startUrls` (type: `array`):

Paste leaderboard, topic or product addresses directly, for example https://www.producthunt.com/leaderboard/daily/2026/8/14, https://www.producthunt.com/topics/artificial-intelligence or https://www.producthunt.com/products/notion. Anything you put here is read in addition to the leaderboard range above.

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

Total number of products to return across every page in the run. Keep it low while you are testing - you pay per row.

## `includeDetails` (type: `boolean`):

On by default. The list pages carry the name, tagline, votes, comments, topics, thumbnail, rank and launch date; the description, the maker names and the product's own website live on the product page, so each row costs one extra page read. Turn this off for a faster, lighter run when you only need the ranking and the engagement numbers.

## `proxyUrls` (type: `array`):

Leave this empty for a normal run. Fill it in only if you want the traffic to leave through proxy servers you already pay for, one URL per line, in the form http://user:pass@host:port.

## Actor input object example

```json
{
  "leaderboardPeriod": "daily",
  "dateFrom": "2026-08-09",
  "dateTo": "2026-08-15",
  "maxItems": 20,
  "includeDetails": true
}
```

# Actor output Schema

## `results` (type: `string`):

Every row in the default dataset: productName, tagline, description, upvotes, commentsCount, topics, makers, websiteUrl, thumbnailUrl, launchedAt, rank, productHuntUrl, slug, postId, reviewsRating, reviewsCount, inputUrl. An empty or unmatched run returns a single uncharged row explaining what happened instead.

# 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 = {
    "leaderboardPeriod": "daily",
    "dateFrom": "2026-08-09",
    "dateTo": "2026-08-15",
    "maxItems": 20,
    "includeDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/producthunt-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 = {
    "leaderboardPeriod": "daily",
    "dateFrom": "2026-08-09",
    "dateTo": "2026-08-15",
    "maxItems": 20,
    "includeDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/producthunt-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 '{
  "leaderboardPeriod": "daily",
  "dateFrom": "2026-08-09",
  "dateTo": "2026-08-15",
  "maxItems": 20,
  "includeDetails": true
}' |
apify call dami_studio/producthunt-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/producthunt-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/NZHuO5kEo74sjiT9T/builds/jNuntAI9CYZrmCymg/openapi.json
