# Product Hunt Scraper - $0.45 per 1,000 Launches (`dami_studio/producthunt-scraper`) Actor

Once a launch's day on Product Hunt is over it carries on into the weekly, monthly and yearly boards. All four are readable here, plus topic pages and product URLs: name, tagline, upvotes, comments, makers, website, rank and launch date. No token. $0.45 per 1,000.

- **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
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Product Hunt Scraper

Pick a leaderboard period and a date range, or paste Product Hunt leaderboard, topic or product addresses. You get one row per launch: product name, tagline, the full description, upvotes, comments, topics, maker names, the product's own website, thumbnail, rank and launch date.

No account, no developer token, no cookies, no browser.

- Daily, weekly, monthly and yearly leaderboards, over whatever date range you ask for.
- Topic pages and single product addresses work too, in the same run and the same row shape.
- Every row carries the description, the makers and the website, not just the ranking.
- A launch that ranks on several leaderboards in one run is returned once and charged once.
- Empty input returns one labelled sample row, free.

### Price

**$0.45 per 1,000 products.** Plus **$0.0005 per run** as the platform start fee, billed per gigabyte of run memory, so exactly that on the default 1 GB.

No volume tiers, no minimum spend, no subscription.

| Products | Total |
|---|---|
| 100 | $0.0455 |
| 1,000 | $0.4505 |
| 10,000 | $4.5005 |
| 100,000 | $45.0005 |

#### What gets charged

- One `product-scraped` event per product row written to the dataset. Nothing else is metered per row.
- Free: the sample row an empty run returns, and every diagnostic row. They all carry `"charged": false`.
- A launch already returned from another leaderboard in the same run is dropped before it's charged, so overlapping date ranges don't bill you twice.
- Paid placements on the leaderboard are dropped before they're charged. You asked for launches, not adverts.
- A page that returns nothing, gets throttled or doesn't exist writes a free diagnostic row instead of a billed one.
- A run that finds nothing costs the start fee and nothing else.
- Rows never leave the dataset without a charge and are never charged without a row. The billed event is a named one, so nothing is quietly attached to `apify-default-dataset-item`.

### Input

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

| Field | What it does |
|---|---|
| `leaderboardPeriod` | `daily`, `weekly`, `monthly` or `yearly`. Daily reads one page per day in your range and returns roughly 17 to 20 launches from each. The others return the top 20 of every period your range touches. |
| `dateFrom` | First day to read, as `YYYY-MM-DD`. Defaults to seven days before `dateTo`. A run reads at most 120 leaderboard pages. |
| `dateTo` | Last day to read, as `YYYY-MM-DD`. Defaults to yesterday, because today's leaderboard is still moving. |
| `topics` | Topic slugs as they appear in a topic address: `artificial-intelligence`, `developer-tools`, `productivity`. Each returns the products Product Hunt currently ranks first in that topic. |
| `startUrls` | Leaderboard, topic or product addresses pasted directly. Read in addition to the leaderboard range. |
| `maxItems` | Total rows across every page in the run. Default 20, hard ceiling 2,000. Keep it low while testing, since you pay per row. |
| `includeDetails` | On by default. List pages carry name, tagline, upvotes, comments, topics, thumbnail, rank and launch date. The description, makers and website live on the product page, so each row costs one extra page read. Turn it off for a faster, lighter run when the ranking and the engagement numbers are all you need. |
| `proxyUrls` | Leave empty. Only for callers who want traffic to leave through proxy servers they already pay for, as `http://user:pass@host:port`. |

Run it with empty input and you get one labelled sample row, free.

### Output

One row per launch. This is a real row from a real run:

```json
{
  "ok": true,
  "charged": true,
  "recordType": "product",
  "productName": "Nuphos",
  "tagline": "The AI-Native DevOps Workspace.",
  "description": "Nuphos gives engineering teams a shared environment where AI agents can learn your infrastructure, investigate issues, and operate production systems.",
  "upvotes": 380,
  "commentsCount": 79,
  "topics": ["API", "SaaS", "Developer Tools"],
  "makers": ["Yuanlin Lin", "Ling Wu", "Ian Zhang", "Bruce Du"],
  "websiteUrl": "https://nuphos.ai",
  "thumbnailUrl": "https://ph-files.imgix.net/5a2070e3-5b37-4b34-b67a-d6fcbe39215f.png",
  "launchedAt": "2026-08-13T07:01:00.000Z",
  "rank": 3,
  "productHuntUrl": "https://www.producthunt.com/products/nuphos",
  "slug": "nuphos",
  "postId": "1214622",
  "reviewsRating": null,
  "reviewsCount": 0,
  "inputUrl": "https://www.producthunt.com/leaderboard/daily/2026/8/13",
  "scrapedAt": "2026-08-16T09:16:39.764Z"
}
```

#### Field notes

- `productName` is the name of the launch, which isn't always the name of the product. A company that launches a second tool keeps one product page and gives each launch its own name.
- `description` is the full description from the product page, not the one-line tagline.
- `upvotes` is the vote total at read time. It keeps moving on a launch that's still live, so a row read at noon and a row read at midnight will differ.
- `commentsCount` has the same caveat.
- `topics` holds up to three topic names from the leaderboard entry, or the product's categories when the row came from a topic page.
- `makers` are the people credited on the launch. See the limits for when this comes back empty.
- `websiteUrl` is the product's own address, taken from the product page rather than from a redirect link.
- `thumbnailUrl` is the launch thumbnail at full size. Add imgix parameters yourself if you want it resized.
- `launchedAt` is when the launch was featured, in UTC.
- `rank` is the position on the leaderboard you asked for. Daily rank for a daily page, weekly rank for a weekly page. For a row from a topic page or a product address, it's the daily rank that launch reached on its own launch day.
- `postId` is the launch id. Stable, and the right key when you re-run: a product that launches twice produces two rows with two ids.
- `reviewsRating` is the average review score out of five, or null when nobody has reviewed it.
- `inputUrl` is the page the row was read from, so you can group rows back to the day or topic that produced them.

Real rows carry `"charged": true`. Sample rows carry `"_sample": true`, diagnostic rows carry `"_diagnostic": true` and an `errorCode`. Neither is billed.

### How it works

Every Product Hunt page is rendered on their server and ships the data it was built from inside the page, as structured JSON. The run reads that JSON directly. No page rendering, no headless browser, no login, no developer token.

Requests leave through a rotating pool of addresses, and the run changes address well before Product Hunt's per-address budget runs out, so a long run keeps going instead of stalling.

Leaderboard pages give the ranking and the engagement numbers in one read. When `includeDetails` is on, the product pages are then read in parallel to fill in the description, the makers and the website. Launch ids already returned from another leaderboard in the run are skipped. Topic and product pages are treated as separate questions, so a product Product Hunt ranks in two of the topics you asked for gives you a row under each.

### What people use it for

- Tracking the daily top 20 on a schedule and diffing on `postId` to see only what's new since yesterday.
- Building a lead list of newly launched products in a category. Run a month of daily leaderboards, keep the rows whose topics match, and you have the name, the website and usually the makers.
- Competitive monitoring. Watch a topic and see which products are climbing, with the vote and comment counts attached.
- Launch-performance research. A year of daily pages gives you a clean table of rank against votes against comments.
- Newsletter curation, where you want the tagline and description in the same row as the link rather than pasted by hand.

### Reading the output

- **Real rows** carry `"charged": true` and `"recordType": "product"`. One billed event each.
- **The sample row** carries `"_sample": true` and `"charged": false`. There's exactly one, and only when the input named no leaderboard, topic or address.
- **Diagnostic rows** carry `"_diagnostic": true`, `"charged": false` and an `errorCode`: `NO_RESULTS` when a page listed nothing, `DUPLICATES` when everything on the page had already been returned, `NOT_FOUND` when there's no page at that address, `BLOCKED` when the page wasn't served on any address tried, `RATE_LIMITED` when Product Hunt throttled the run, `TIME_BUDGET` when time ran out, `NETWORK` for anything else. Each carries a plain-English `error` and the `url` it belongs to.

Filter on `charged == true` and you have exactly the rows you paid for.

### Dates, timezones and today

Product Hunt runs its leaderboard day on US Pacific time. A launch is featured at 00:01 Pacific and the day closes 24 hours later. The dates you pass in are read as calendar days and turned straight into leaderboard addresses, so `2026-08-14` means Product Hunt's 14 August page wherever you happen to be.

`launchedAt` is converted to UTC, which is why a launch featured at 00:01 Pacific shows as `07:01Z`. Same instant, written in the timezone the rest of the dataset uses.

The default `dateTo` is yesterday rather than today, because today's page is still being voted on. Ask for it explicitly if a half-finished ranking is what you want.

### Limits

- A leaderboard page returns the top 20 of its period. For a daily page that's effectively the whole day, since Product Hunt features roughly 17 to 20 products a day. For weekly, monthly and yearly it's the top 20 and no further, because Product Hunt hands the rest of that list to its own in-browser code rather than putting it in the page. Ask for a range of daily pages when you need depth.
- Maker names are published on the product page for the launch that page currently features. That covers recent launches and every product that has launched only once, measured at 90 of 100 rows over a week of daily leaderboards. For an older launch by a product that has launched again since, Product Hunt doesn't publish that launch's maker list to a logged-out reader, and the field comes back as an empty list rather than the wrong people's names.
- Upvotes and comment counts are a snapshot at read time and will differ from what you see if you open the page a minute later.
- There's no free-text keyword search. Product Hunt assembles search results in the browser rather than on the server and asks crawlers to stay out of that path, so a logged-out reader has nothing to read there. Narrow by date range or topic instead, then filter the rows yourself on tagline or description.
- Topic pages return the products Product Hunt currently ranks highest in that topic, which is a different list from the launches of a given day. Those rows describe the product, with the vote and comment totals of its most recent launch attached, and they carry no maker list.
- Comments, reviews, vote lists and hunter profiles are out of scope. One row per launch is what this returns.
- A run reads at most 120 leaderboard pages and returns at most 2,000 rows.
- Occasionally Product Hunt answers with a challenge page on every address the run tries. That produces a free `BLOCKED` diagnostic row and the run carries on.

### Questions

**Do I need a Product Hunt account or a developer token?**

No. The run reads only what Product Hunt publishes to a logged-out reader. It never signs in and never asks you for a key.

**What if a leaderboard page is empty or doesn't exist?**

One uncharged diagnostic row for that page explaining what happened, and the run carries on to your other pages.

**Why is the default end date yesterday?**

Today's leaderboard is still being voted on, so reading it gives you a ranking that will have changed by the evening. Pass today's date explicitly if you want the in-progress board.

**Can I get more than 20 rows from one weekly or monthly leaderboard?**

Not from that page. Product Hunt puts only the first twenty into the page itself. Ask for the daily pages that make up the period instead. Between them they cover every launch.

**Will the run fail if something goes wrong?**

No. A blocked, throttled, empty or missing page produces an uncharged diagnostic row and the run still finishes as succeeded. A failed run would still bill the start fee, which would mean paying to be told something went wrong.

**Can I run it on a schedule?**

Yes. Nothing is held between runs. Use `postId` to work out which launches are new since last time.

**Does turning off `includeDetails` make it cheaper?**

No, you're billed per row either way. It makes the run faster and lighter, because each row then costs one page read shared with nineteen others instead of one of its own.

# 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. Defaults to seven days before the To date. Up to 120 leaderboard pages per run.

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

Last day to read, as YYYY-MM-DD. Defaults to yesterday, because today's leaderboard is still moving.

## `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. By default the run rotates a large pool of addresses that cost you nothing per gigabyte. Fill it in only if you specifically want the traffic to leave through proxy servers you already pay for, 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, blocked 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/PHeH0S9SnwMJm1LNr/openapi.json
