Product Hunt Scraper - Daily and Weekly Launches
Pricing
from $0.44 / 1,000 products
Product Hunt Scraper - Daily and Weekly Launches
Scrape Product Hunt launches from 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 token, no login. $0.45 per 1,000 launches.
Pricing
from $0.44 / 1,000 products
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
2
Monthly active users
5 hours ago
Last modified
Categories
Share
Pull Product Hunt 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 publish a 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, flat on every plan. The free plan's $5 a month covers about 11,000 |
🔍 What Product Hunt 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, roughly 17 to 20 launches each. 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
- Open Product Hunt Scraper and click Try for free.
- Choose a Leaderboard period, then set From date and To date.
- Or skip that and paste addresses into Product Hunt URLs, or topic slugs into Topics.
- Set Maximum rows. Keep it low on the first run.
- 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. The same rate on every Apify plan, with no volume tiers. 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.
{"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, because today's board is still moving. |
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 that is not in one of those two shapes is silently replaced by the default window, which
is the seven days ending yesterday. Nothing tells you it happened, so check launchedAt on the
first few rows if your dates came out of another system.
📤 What you get back
A real row, from run crtA2I1AfUk9wDbze:
{"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. Read the same launch a week later and the numbers move. |
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 |
| 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 |
|---|---|
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, BLOCKED | That page could not be read on this run. Try again later. |
NETWORK | The page could not be reached. Re-run it. |
TIME_BUDGET | The run ran out of time before reading that page. Rows already collected are still delivered. |
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
postIdso 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
rankacross a date range. - Seeing who is behind launches in a niche.
From last week's launches to a list of product websites:
- Choose Daily under Leaderboard period and clear From date and To date, so the run reads the seven days ending yesterday.
- 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. - Open each
websiteUrlto see the product on its own site.
🚧 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.
reviewsRatingandreviewsCountare the summary numbers Product Hunt publishes, nothing more. - When a product page cannot be read in time, the row is still delivered and still billed, with
description,makersandwebsiteUrlempty. Nothing in the row separates "not fetched" from "not published", so if those fields matter to you, check for empties and re-run those slugs. - 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, because it is still moving. 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 |
| Hacker News stories, Ask and Show HN posts, and comments | Hacker News Scraper |
| Startup jobs with salary and equity | Wellfound Jobs 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?
Through the date range, no, because the board is still moving and the ranks would be wrong within the
hour. 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?
Yes. The API tab has ready-made code
for Python, JavaScript and the command line. For Claude, ChatGPT or another MCP client, connect
https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/producthunt-scraper. Either way the
run happens on 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 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.