# Product Hunt Scraper — Leaderboards & Launches (`diopside/product-hunt-launches`) Actor

Product Hunt launches from daily, weekly, monthly and yearly leaderboards plus topic and category pages.

- **URL**: https://apify.com/diopside/product-hunt-launches.md
- **Developed by:** [DIOPSIDE AI](https://apify.com/diopside) (community)
- **Categories:** Business, News, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 launches

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 — Leaderboards, Topics & Products

**Drop-in compatible with [`maximedupre/product-hunt-scraper`](https://apify.com/maximedupre/product-hunt-scraper) — cheaper and reliable.** Same input fields, same output keys: change the Actor id and your existing integration keeps working.

Product Hunt launches as structured JSON — daily, weekly, monthly and yearly leaderboards, plus **fully paginated** topic and category pages. Rank, upvotes, comments, topics, review score, followers, public maker credits, funding and Y Combinator flag. No login, no API key, no captcha solver.

***

### Why this one

Product Hunt sits behind Cloudflare, and that wall is **per exit IP and unstable**. While building this Actor, one probe run got a clean IP on its 3rd Apify datacenter session; the very next run was challenged on all four. A scraper that retries the same IP — or that discovers the block one 600 KB page request at a time — does not fail fast. It grinds until the platform kills it.

That is visible in the incumbent's own numbers. Over the 30 days to 2026‑09‑19 it ran 911 times: 743 succeeded, 37 failed, 16 were aborted, and **115 timed out** — 18% of runs produced nothing, and the biggest single bucket is the timeout.

This Actor is built around that one fact:

| | How it works here |
|---|---|
| **Cloudflare** | Real Chrome TLS fingerprint (`curl_cffi`), and the session is warmed on the homepage *first*. A challenged warm‑up costs one 6 KB response and that exit IP is thrown away immediately — never a page request, never a retry loop. |
| **Proxy ladder** | Datacenter proxy first (cheap). If four exit IPs in a row are challenged the Actor escalates to `RESIDENTIAL` **by itself** and finishes the run. You do not have to notice, re-run, or reconfigure anything. |
| **Parsing** | Reads Product Hunt's own Apollo SSR payload (`homefeedItems.edges[].node`), not the markup. Class names change weekly; the payload does not. |
| **Partial failure** | A dead source is logged, named in the status message and skipped. It never takes down the records already collected, and it never silently returns an empty dataset as "success". |
| **Honest counts** | `maxNbItemsToScrape: 15` saves 15 launches. Ad slots in the feed are detected by type (`__typename == "Ad"`), not by a pill image every row carries, so they are excluded from your bill without eating your quota. |

**And one thing the incumbent does not have:** topic and category pages here are **paginated**, and every row carries the source's `totalCount`. You can see that `developer-tools` has 14,243 products and decide how deep to go, instead of guessing.

***

### Input

Every field below is the incumbent's field, spelled the incumbent's way.

| Field | Type | Default | What it does |
|---|---|---|---|
| `target` | enum | `daily` | `daily` · `weekly` · `monthly` · `yearly` · `category` · `topic` · `pageUrls` |
| `startDate` / `endDate` | string | today (California) | Inclusive `YYYY-MM-DD` range for the daily leaderboard |
| `startWeek` / `endWeek` | string | — | Inclusive `YYYY-WW` range, e.g. `2026-37` |
| `startMonth` / `endMonth` | string | — | Inclusive `YYYY-MM` range |
| `startYear` / `endYear` | integer | — | Inclusive year range |
| `categorySlugs` | string\[] | — | e.g. `ai-code-editors` |
| `topicSlugs` | string\[] | — | e.g. `developer-tools` |
| `productHuntPageUrls` | string\[] | — | Leaderboard, topic, category **or product** page URLs |
| `maxNbItemsToScrape` | integer | 20 | Stop after this many **saved** launches. Empty = everything the source yields |
| `maxPagesPerSource` | integer | 5 | *(new)* Pages per topic/category slug; 15 products per page |
| `shouldIncludePromotedListings` | boolean | `false` | Keep Product Hunt's paid feed slots |
| `shouldScrapeOnlyFeaturedLaunches` | boolean | `false` | Keep only featured launches |
| `shouldScrapeProductDetails` | boolean | `false` | *(new)* Visit each product page for description, followers, rating, links, screenshots and maker credits. **No extra charge** |
| `proxyConfiguration` | object | `{"useApifyProxy": true}` | Required — see [Proxy](#proxy) |

```json
{
  "target": "daily",
  "startDate": "2026-09-18",
  "maxNbItemsToScrape": 15,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### Output

One item per launch (leaderboards) or product (topic/category/product pages). Field names match the incumbent; the additions come after.

```json
{
  "isPromoted": false,
  "thumbnailUrl": "https://ph-files.imgix.net/75f0625c-cbfa-4751-b269-42252ecb1f75.png?auto=format",
  "name": "Ami AI",
  "url": "https://www.producthunt.com/products/ami-ai",
  "tagline": "Lovable for getting customers",
  "categories": [],
  "followers": null,
  "commentsCount": 182,
  "reviewsCount": null,
  "launchesCount": null,
  "dayRank": 1,
  "weekRank": 5,
  "monthRank": 11,
  "yearRank": null,
  "launchDate": "2026-09-18",
  "description": null,
  "upvotesCount": 502,
  "links": [],
  "xAccountHandle": null,
  "imageUrls": [],
  "videoUrls": [],
  "tags": ["Sales", "Marketing", "Artificial Intelligence"],
  "team": [],
  "builtWith": [],
  "launches": [],
  "comments": [],
  "reviews": [],
  "website": null,

  "id": "1252325",
  "slug": "ami-ai",
  "productId": "1319473",
  "productSlug": "ami-ai",
  "productUrl": "https://www.producthunt.com/products/ami-ai",
  "postUrl": "https://www.producthunt.com/posts/ami-ai",
  "topics": [{ "id": "71", "slug": "sales", "name": "Sales" }],
  "launchScore": 490,
  "featuredAt": "2026-09-18T00:01:00-07:00",
  "isFeatured": true,
  "sourceUrl": "https://www.producthunt.com/leaderboard/daily/2026/9/18/all",
  "sourceType": "leaderboard",
  "position": 1
}
```

Turn on `shouldScrapeProductDetails` and the null columns fill in — `description`, `followers`, `reviewsCount`, `reviewsRating`, `website`, `links`, `xAccountHandle`, `imageUrls`, `team`, plus `githubUrl`, `linkedinUrl`, `iosUrl`, `androidUrl`, `employeeSize`, `fundingAmount`, `wasInYCombinator`. In the verification run every one of those was populated for 20/20 products.

Every record carries every column, on every source, so CSV and Excel exports line up.

`builtWith`, `launches`, `comments` and `reviews` are always empty arrays. They exist so a migrated integration does not hit a `KeyError`; use `launchesCount`, `commentsCount`, `reviewsCount` and `reviewsRating` instead.

### Sizes and limits

| Source | Per page | Pagination |
|---|---|---|
| Daily / weekly / monthly / yearly leaderboard | Top 20 of that period | **By period.** Product Hunt's "load more" runs through a GraphQL endpoint that rejects every unauthenticated request, so the way to cover a range is a date/week/month range, not deeper pages |
| Topic pages | 15 products | Real, `?page=N`, up to `maxPagesPerSource` |
| Category pages | 15 products | Real, `?page=N`, up to `maxPagesPerSource` |
| Product page URL | 1 product, full detail | — |

Measured on the Apify platform (2026‑09‑19): 15 launches from one daily leaderboard in **15 s**; 20 topic products *with* full product detail (21 page fetches) in **27 s**.

### Proxy

Apify Proxy is **required**. Raw Apify IPs get Cloudflare's "Just a moment…" interstitial — a verification run with `useApifyProxy: false` failed with exactly that, by design, rather than returning an empty dataset.

Leave `proxyConfiguration` at its default. Datacenter is tried first and the Actor escalates to `RESIDENTIAL` on its own when it has to. Set `apifyProxyGroups: ["RESIDENTIAL"]` yourself only if you want to skip the datacenter attempt entirely.

### Use cases

- **Launch tracking** — run the daily target on a schedule and keep a table of every launch, its rank and its upvote curve.
- **Competitive intelligence** — walk a category (`ai-code-editors`, 98 products) or a topic (`developer-tools`, 14,243) and get the whole field with review scores and follower counts.
- **Market sizing** — `totalCount` per topic/category, plus `postsCount` and `firstLaunchedAt` per product.
- **Trend research** — monthly and yearly leaderboards back through Product Hunt's archive.
- **Enriching a product list** — feed `/products/<slug>` URLs straight into `productHuntPageUrls`.

### Switching from `maximedupre/product-hunt-scraper`

1. Change the Actor id to `diopside/product-hunt-launches`.
2. That's it — `target`, the date/week/month/year fields, `categorySlugs`, `topicSlugs`, `productHuntPageUrls`, `maxNbItemsToScrape`, `shouldIncludePromotedListings` and `shouldScrapeOnlyFeaturedLaunches` all mean the same thing, and the output keys are unchanged.

Two differences worth knowing:

- `shouldScrapeComments`, `shouldScrapeReviews`, `shouldScrapeBuiltWith`, `shouldScrapeLaunches` and `shouldScrapeWebsite` are accepted and ignored. Use `shouldScrapeProductDetails`, which covers the product-page fields in one pass at no extra charge.
- **No email enrichment.** This Actor collects public product data and the maker credits Product Hunt prints on a launch. It does not visit personal profiles and does not collect contact details, so there is no per-email surcharge either.

### Data and compliance

Public Product Hunt pages only — the same data any visitor sees, read from the page's own SSR payload. No login, no personal contact data, no email or phone lookup.

# Actor input Schema

## `target` (type: `string`):

Choose one Product Hunt source. Fill in only that source's options; other source options are ignored.

## `startDate` (type: `string`):

First daily leaderboard date in YYYY-MM-DD. Leave blank for today's California-time leaderboard. Add an end date to walk a past date range.

## `endDate` (type: `string`):

Optional last date of an inclusive daily range, in YYYY-MM-DD. Leave blank to scrape only the start date.

## `startWeek` (type: `string`):

First leaderboard week in YYYY-WW, such as 2026-37. Add an end week for an inclusive range.

## `endWeek` (type: `string`):

Optional last week of an inclusive range, in YYYY-WW. Leave blank to scrape only the start week.

## `startMonth` (type: `string`):

First leaderboard month in YYYY-MM, such as 2026-09. Add an end month for an inclusive range.

## `endMonth` (type: `string`):

Optional last month of an inclusive range, in YYYY-MM. Leave blank to scrape only the start month.

## `startYear` (type: `integer`):

First leaderboard year, such as 2025. Add an end year for an inclusive range.

## `endYear` (type: `integer`):

Optional last year of an inclusive range. Leave blank to scrape only the start year.

## `categorySlugs` (type: `array`):

One Product Hunt category slug per row, such as ai-code-editors. Category pages paginate, so this source can return thousands of products.

## `topicSlugs` (type: `array`):

One Product Hunt topic slug per row, such as developer-tools. Topic pages paginate, so this source can return thousands of products.

## `productHuntPageUrls` (type: `array`):

Leaderboard, topic, category — and, unlike the incumbent, product — page URLs, one per row.

## `maxNbItemsToScrape` (type: `integer`):

Leave empty to save everything the chosen source yields. Set a positive number to stop after that many saved launches.

## `maxPagesPerSource` (type: `integer`):

Topic and category pages return 15 products per page. This caps how many pages are walked per slug (default 5 = 75 products).

## `shouldIncludePromotedListings` (type: `boolean`):

Include listings Product Hunt marks as promoted. Off by default.

## `shouldScrapeOnlyFeaturedLaunches` (type: `boolean`):

Keep only launches Product Hunt has featured. Off by default.

## `shouldScrapeProductDetails` (type: `boolean`):

Visit each product's Product Hunt page for description, followers, review count and rating, public social links, screenshots, maker credits, funding and Y Combinator flag. Adds one request per launch; no extra charge.

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

Product Hunt is behind Cloudflare and challenges raw Apify IPs, so Apify Proxy is required. Datacenter proxy is enough; the Actor escalates to RESIDENTIAL by itself if every datacenter exit IP is challenged.

## Actor input object example

```json
{
  "target": "daily",
  "startWeek": "2026-37",
  "startMonth": "2026-09",
  "startYear": 2025,
  "categorySlugs": [
    "ai-code-editors"
  ],
  "topicSlugs": [
    "developer-tools"
  ],
  "productHuntPageUrls": [
    "https://www.producthunt.com/leaderboard/daily/2026/9/18/all",
    "https://www.producthunt.com/topics/developer-tools",
    "https://www.producthunt.com/products/basedash"
  ],
  "maxNbItemsToScrape": 20,
  "maxPagesPerSource": 5,
  "shouldIncludePromotedListings": false,
  "shouldScrapeOnlyFeaturedLaunches": false,
  "shouldScrapeProductDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `launches` (type: `string`):

All launch records. Append ?format=csv for CSV.

## `datasetUrl` (type: `string`):

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 = {
    "target": "daily",
    "maxNbItemsToScrape": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("diopside/product-hunt-launches").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 = {
    "target": "daily",
    "maxNbItemsToScrape": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("diopside/product-hunt-launches").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 '{
  "target": "daily",
  "maxNbItemsToScrape": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call diopside/product-hunt-launches --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,diopside/product-hunt-launches"
        }
    }
}
```

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/a7gstk7R9yKWylqQN/builds/CaMR0aqH5hqIvTypC/openapi.json
