# Product Hunt Scraper: Daily, Weekly & Monthly Launches (`hexagone-data/producthunt-scraper`) Actor

Scrape Product Hunt leaderboards by day, week or month: rank, votes, comments, topics, tagline, product links; optional launch details with makers, website, followers and rating. Pay per result.

- **URL**: https://apify.com/hexagone-data/producthunt-scraper.md
- **Developed by:** [Hexagone Data](https://apify.com/hexagone-data) (community)
- **Categories:** Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 90.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.05 / 1,000 launch records

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 Leaderboards Scraper — Daily, Weekly & Monthly Launch Rankings

Scrape **Product Hunt leaderboards**: the daily, weekly and monthly rankings of launches, with each launch's rank, votes (as displayed), comments, topics and link. Turn on launch details for makers, hunter, description, pricing and product stats.

Use dated exports to track a launch's ranking over time, compare weeks or months, or analyze which topics and makers show up at the top. One record is delivered **per launch and per leaderboard**: the same launch appearing in the daily and the weekly leaderboard gives two records, each with its own rank. Votes and comments move in real time on Product Hunt; every record carries a `scrapedAt` timestamp: the time the leaderboard page that served this record was read (each page of a long leaderboard has its own time). With details on, `detailsScrapedAt` is the time that launch's detail query answered.

### Try it with 20 launch records

1. Paste a leaderboard URL into **Leaderboard URLs**, e.g. `https://www.producthunt.com/leaderboard/weekly/2026/43`.
2. Leave **Maximum number of launch records** at `20`.
3. Start the Actor and open its dataset.
4. Read **Run summary** before exporting: a run can deliver results and still contain partially collected leaderboards (see Coverage below).

```json
{
  "startUrls": [{"url": "https://www.producthunt.com/leaderboard/weekly/2026/43"}],
  "includeDetails": false,
  "maxItems": 20
}
```

The form prefill is 20 records; the schema default is 500. Set `maxItems` explicitly in API calls; `0` removes the limit. You are charged per delivered record, plus a $0.005 start fee per run.

### Choose leaderboard URLs

| Input | Data | Limit |
|---|---|---|
| Daily `/leaderboard/daily/YYYY/M/D` | The full day's leaderboard: first page + pagination until the site says it is done | A date still in progress returns only what exists so far |
| Weekly `/leaderboard/weekly/YYYY/W` | The full week's leaderboard, paginated the same way | Rank gaps left by the site are reported (`rankGaps`), never silently filled |
| Monthly `/leaderboard/monthly/YYYY/M` | The month's leaderboard, paginated the same way | Same, plus duplicate ranks reported (`duplicateRanks`) |
| `/all` suffix or any other page | — | Rejected with a reason; it never blocks the other URLs |

`includeDetails` costs one extra request per delivered launch. `reviewsCount` is always `null`: the number of reviews displayed on a product page is not available without loading each 1.3 MB product page, and the launch query returns a different number (`reviewersCount`) that would be wrong under this name (measured: CleanShot displays 55 reviews, the query returns 48). The exact rating (`rating`) and follower count (`followers`) are delivered when details are on.

### Output

| Fields | Meaning |
|---|---|
| `launchId`, `launchSlug`, `productId`, `productSlug` | Launch and product identifiers. A product can have several launches; slugs can differ (launch `notra-5` belongs to product `notra-3`). |
| `name`, `tagline`, `url` | Launch name and tagline as displayed (trimmed), and the launch page URL. |
| `leaderboard`, `leaderboardDate`, `rank` | Which leaderboard the record comes from (first day of the period in `leaderboardDate`) and the launch's rank in it — the site's rank, never recomputed. |
| `dailyRank`, `weeklyRank`, `monthlyRank` | Each period's rank as carried by the data, when present. |
| `votes`, `commentsCount` | As displayed on the leaderboard: `votes` is the current score (`latestScore`), never the launch-day score. |
| `topics` | All topics from the site data, including contest topics the leaderboard hides from display. |
| `featuredAt`, `thumbnailUrl`, `scrapedAt` | Launch time exactly as the site gives it (Pacific time with offset), thumbnail, and the UTC time the leaderboard page that served this record was read. |
| `detailsScrapedAt` | With `includeDetails`, the UTC time the launch detail query for this record answered (present only when `detailsSource` is `postPage`). |
| `detailsSource` | `postPage` when the detail fields were fetched, `leaderboard` when they are null (details off or failed). |
| `description`, `pricingType`, `makers`, `hunter` | Launch details (with `includeDetails`). `makers` are the launch's makers, not the product page's author list; `hunter` is null when the site gives no hunter. |
| `websiteUrl`, `productName`, `productTagline`, `followers`, `rating`, `productLaunchCount` | Product data (with `includeDetails`). `websiteUrl` is the **product's** website, which can differ from the link of this particular launch (Inferock: launch link `inferock.ai`, product website on GitHub). `followers` is the exact count (the page rounds, e.g. 3564 → "3.6K"); `rating` is null when the product has no reviews; `reviewsCount` is always null (see above). |

#### Real output example

Collected on **28 October 2026** — demonstrates the format, not today's scores.

```json
{
  "launchId": "1265035",
  "launchSlug": "inferock",
  "name": "Inferock",
  "tagline": "Serverless inference, with credits back for failed calls.",
  "url": "https://www.producthunt.com/products/inferock?launch=inferock",
  "productId": "1291234",
  "productSlug": "inferock",
  "leaderboard": "daily",
  "leaderboardDate": "2026-10-14",
  "rank": 2,
  "dailyRank": 2,
  "weeklyRank": 3,
  "monthlyRank": 51,
  "votes": 262,
  "commentsCount": 26,
  "topics": ["Developer Tools", "Artificial Intelligence", "Google Cloud Run"],
  "featuredAt": "2026-10-14T00:01:00-07:00",
  "thumbnailUrl": "https://ph-files.imgix.net/7a48325f-d5b7-4547-9aaf-aae3b709d967.png",
  "scrapedAt": "2026-10-28T07:51:19.774110+00:00",
  "detailsSource": "postPage",
  "description": "Get free signup credits to use all available models on Inferock.\n\nBring your own keys: run your OpenAI, Claude or Gemini accounts, see where calls fail and what they cost, and get credits back on eligible failed calls.\n\nServerless: pay-per-token LLM inference. Get signup credits to start using.",
  "pricingType": "free_options",
  "makers": [
    {"name": "Hamza Afzal Butt", "username": "hamza_afzal_butt",
     "headline": "B2B SaaS Growth Marketing Consultant",
     "profileUrl": "https://www.producthunt.com/@hamza_afzal_butt"},
    {"name": "Sumedh Bengale", "username": "sumedh_bengale",
     "headline": "Dev Rel Assoicate at Inferock",
     "profileUrl": "https://www.producthunt.com/@sumedh_bengale"},
    {"name": "Bharath Koneti", "username": "bharath_koneti",
     "headline": "Co-founder Inferock AI",
     "profileUrl": "https://www.producthunt.com/@bharath_koneti"}
  ],
  "hunter": {"name": "fmerian", "username": "fmerian",
             "profileUrl": "https://www.producthunt.com/@fmerian"},
  "websiteUrl": "https://github.com/inferock/inferock-bench",
  "productName": "Inferock",
  "productTagline": "An independent receipt for every LLM API call",
  "followers": 874,
  "reviewsCount": null,
  "rating": 4.0,
  "productLaunchCount": 2
}
```

This is the record as collected, except that the makers list is shortened here (`makers` had 4 entries for this launch). The "Google Cloud Run" topic is real data the leaderboard page hides from display — this Actor keeps it.

### Access and Cloudflare challenges

Product Hunt filters server IP addresses with Cloudflare challenges ("Just a moment…"). The Actor runs through the Apify proxy by default (datacenter): when a request is challenged, it does not treat the response as data or as an empty page — it opens a new address and retries the same request, and after three consecutive challenges on datacenter addresses it switches to residential IPs for the rest of the run. Transient network failures through the proxy (SSL resets, dropped connections, 502/503/504 gateways without a challenge page) get the same treatment: new address, same request. Rate limiting (HTTP 429) and a 200 answer that is not readable JSON are retried the same way. Every request gets at most 8 attempts in total; a still-challenged URL is reported as blocked (`blocked_by_site`) and a still-failing one as `network_error`, each with the count of attempts and a dedicated warning — the run says so instead of pretending success. If you select your own proxy group or your own proxies, your choice is kept as-is for the whole run.

This address rotation can slow a run down (every request keeps a 2-second spacing). Once `maxItems` is reached, no further leaderboard page is fetched at all. The extra proxy cost is included in the per-record price. The run output reports `requestsByAccess` (requests made through `datacenter` / `residential` / `none`, or `custom` for your own proxies or another proxy group you chose) and `challenges` (how many Cloudflare challenges were answered by a new address).

### Coverage and run summary

Product Hunt does not announce a total, so completeness is measured from what the site actually serves. A leaderboard is marked `done` when its pagination ends normally (`hasNextPage=false`, no failed page, no stale query id, no looping cursor); anything else is `partial_collection` with the reason.

Product Hunt itself skips ranks, e.g. there is no #10 on 14 Oct 2026, and September 2026 has more than 20 gaps. Missing ranks are not a partial collection: they are listed per URL in the run output (`rankGaps`) so you can account for them. The same applies to duplicate ranks — the site sometimes serves two launches at the same rank (twice at #80 in week 43); both are delivered and the rank is listed in `duplicateRanks`. Ads inserted in the feed (`adsSkipped`) are counted and never delivered. A future date or an empty period is `no_products` with a reason; if every URL comes back empty the run fails with a clear message instead of a silent success.

If **Run summary** stays blank, open the run's **Storage → Key-value store** tab and click the eye icon on the **SUMMARY** row. Check per-URL statuses before treating a dataset as complete.

### Known limits

- **`reviewsCount` is always null** (explained above); `rating` and `followers` are exact.
- **Product Hunt itself skips and repeats ranks** (see Coverage); the delivered records follow the site's data, gaps and duplicates are reported per URL.
- **Product Hunt changes internal query ids** when it updates the site. If that happens, requests fail with a dedicated warning ("Product Hunt changed an internal query id; this Actor needs an update"), leaderboards already fetched are still delivered, and the affected URLs are reported — never a silent empty success. If the launch detail query is the one affected, details are turned off for the rest of the run at the first failure (one wasted request, not one per launch): launches keep coming with `detailsSource: "leaderboard"`, and the run summary says so.
- Requests are spaced 2 seconds apart; a closed day takes 1 to 3 requests, a full week about 10, a month several dozen — plus one request per launch when details are on. Cloudflare challenges add retries and address rotations (see Access).

### Pricing

**$1.50 per 1,000 delivered launch records** plus a **$0.005 start fee per run**: **$0.035 for 20**, $1.505 for 1,000. The start fee is charged once per GB of run memory (the default is 1 GB, so once per run). Apify subscribers pay less automatically, on both events: 10% off on the Bronze plan, 20% on Silver, 30% on Gold and above. Standard Apify platform usage, including the default proxy and any residential escalation, is included in this price. A run delivering no records only pays the start fee; each delivered record (one launch in one leaderboard) is one chargeable event.

If you set a **maximum cost per run**, the Actor stops cleanly when it is reached: the run succeeds, the records already delivered stay in the dataset, the affected leaderboard URLs are marked `stopped_at_limit` with how many of the launches read were delivered, and the status message says the maximum charge per run was reached.

### Personal data

With `includeDetails`, records include the public profile data Product Hunt shows for a launch's makers and hunter: names, usernames, headlines and profile links. This data is public on Product Hunt, but it is still personal data. You are responsible for how you use it under the GDPR and the other laws that apply to you: have a legitimate purpose, keep only what you need, and do not use it for unsolicited outreach or marketing. Leave `includeDetails` off if you do not need it.

### Automation and support

Use the Apify API to run the Actor on a schedule (e.g. every day for the previous day's daily leaderboard) and keep dated exports to follow rankings over time.

For a reproducible problem, open an issue with the leaderboard URL, run ID and expected result. Do not include API tokens. Site changes can affect collection; check the run summary before using the results.

### Français

Collectez les classements Product Hunt (jour, semaine, mois) : rang, votes affichés, commentaires, thèmes et, en option, les détails de chaque lancement (makers, chasseur, description, statistiques produit). Une ligne par lancement et par classement. Les classements sont paginés jusqu'au bout, dans la limite de `maxItems` : 20 dans le formulaire, **500 par défaut** dans l'API (un mois dépasse 600 lancements), `0` = sans limite ; les rangs sautés par le site sont listés (`rankGaps`), les rangs doublés livrés deux fois (`duplicateRanks`). Le proxy Apify est activé par défaut : le site filtre les serveurs par défis Cloudflare, l'actor change d'adresse et passe aux IP résidentielles au besoin (coût inclus). `reviewsCount` est toujours null (le nombre affiché n'est pas disponible sans charger chaque fiche produit). `scrapedAt` est l'heure de lecture de la page de classement qui a fourni la ligne, `detailsScrapedAt` celle de la fiche du lancement. Les détails contiennent des données personnelles publiques (noms, pseudos, titres et profils des makers et du chasseur) : vous êtes responsable de leur usage (RGPD, lois locales) ; ne les utilisez pas pour du démarchage non sollicité.

Product Hunt is a trademark of its owner. This Actor is not affiliated with, endorsed by or sponsored by Product Hunt.

# Actor input Schema

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

Product Hunt leaderboard URLs to scrape: /leaderboard/daily/YYYY/M/D, /leaderboard/weekly/YYYY/W or /leaderboard/monthly/YYYY/M. The /all tab and any other page are rejected with a reason. The same launch appearing in several leaderboards is delivered once per leaderboard.

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

One extra request per delivered launch (makers, hunter, description, pricing, product stats). Slower and heavier; without it you get the full leaderboard fields only.

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

Stops after this many launch records across all leaderboard URLs. 0 = no limit. You are charged per delivered record, plus a $0.005 start fee per run.

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

Product Hunt filters server IP addresses with Cloudflare challenges. The default Apify datacenter proxy works (the Actor rotates addresses and switches to residential IPs after repeated challenges). Choose your own proxy group only if you have a reason; the extra proxy cost is included in the per-record price.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.producthunt.com/leaderboard/weekly/2026/43"
    }
  ],
  "includeDetails": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All launch records, one per launch and per scraped leaderboard, with rank, votes, comments, topics and optional details.

## `leaderboardView` (type: `string`):

Leaderboard view: rank, launch, tagline, votes, comments, topics, link, thumbnail.

## `summary` (type: `string`):

Readable per-URL summary: status, launches delivered, ads skipped, rank gaps and the reason for any partial collection.

## `summaryJson` (type: `string`):

The same summary as JSON (OUTPUT record), for programmatic use.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.producthunt.com/leaderboard/weekly/2026/43"
        }
    ],
    "includeDetails": false,
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("hexagone-data/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 = {
    "startUrls": [{ "url": "https://www.producthunt.com/leaderboard/weekly/2026/43" }],
    "includeDetails": False,
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("hexagone-data/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 '{
  "startUrls": [
    {
      "url": "https://www.producthunt.com/leaderboard/weekly/2026/43"
    }
  ],
  "includeDetails": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call hexagone-data/producthunt-scraper --silent --output-dataset

```

## MCP server setup

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