Indie Hackers Products Scraper
Pricing
from $1.79 / 1,000 results
Indie Hackers Products Scraper
Scrape public Indie Hackers product pages and get names, taglines, descriptions, websites, self-reported monthly revenue, post counts, founders, Twitter links and logos. Pick specific products by URL or slug, or read the first page of the products directory.
Pricing
from $1.79 / 1,000 results
Rating
0.0
(0)
Developer
Axiom Works
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Returns: one row per Indie Hackers product with name, tagline, websiteUrl, monthlyRevenueUsd, postCount, founders, sourceUrl.
Input: {"productSlugs": ["keep-the-score", "sql-pad"], "maxItems": 2}
Best for: bootstrapped-product lead lists, competitor and niche research, revenue tracking over time.
{"id": "keep-the-score","sourceUrl": "https://www.indiehackers.com/product/keep-the-score","name": "Keepthescore.com","tagline": "Create digital sports scoreboards and streaming overlays","websiteUrl": "https://Keepthescore.com","monthlyRevenueUsd": 25000,"postCount": 5}
What does Indie Hackers Products Scraper do?
Indie Hackers Products Scraper collects public product pages from the Indie Hackers directory and returns them as clean, structured records. Each record describes one product: its name, tagline, about text, website, self-reported monthly revenue, number of posts, the people listed on it, its Twitter link and its logo. You can point the Actor at specific product URLs or pull the top of the directory in a chosen sorting.
The Actor reads only pages that anyone can open in a browser, without an account. It starts at most one request per second with two products processed at a time, including retries. Missing pages (HTTP 404 or 410) are skipped immediately. Temporary failures and blocked responses get up to two retries with backoff on fresh sessions. Each fetch has a 35-second retry budget and a 12-second attempt timeout. If no result arrives within about 65 seconds, discovery stops and the run succeeds with a message suggesting targets or proxy settings. Apify Proxy is available for blocked requests on the platform.
It is built for founders researching competitors and niches, investors and analysts who want a list of bootstrapped products with revenue figures, newsletter and directory builders, lead researchers who need a product's website and founder profile, and anyone who feeds product data into a spreadsheet, a database or an AI workflow.
Typical uses include:
- building a list of products that report a given monthly revenue or more;
- re-running the same product URLs to compare revenue and post counts over time;
- collecting product websites and Twitter links for outreach research;
- grouping products by category to see which niches are crowded.
An optional enrichment step assigns each product a category from a fixed list. That step uses a third-party AI processor, which receives the product name, tagline and description. You can switch it off with the AI category option.
What data can you get?
Each product becomes one dataset item. Items are unique by id (the product slug), and sourceUrl points to the Indie Hackers product page the data came from.
| Field | Type | Description |
|---|---|---|
id | string | Product slug, unique per record |
sourceUrl | string | Product page the data came from |
name | string | Product name from the page header |
tagline | string | One-line tagline |
description | string | About text from the sidebar |
websiteUrl | string | Product website, repaired when the stored value is malformed |
monthlyRevenueText | string | Self-reported revenue exactly as displayed |
monthlyRevenueUsd | number | The same revenue parsed to US dollars per month, or null for suspicious values |
revenueSuspicious | boolean | True when the revenue text has an unknown unit or an implausibly large parsed value; MM is treated as millions |
postCount | number | Number of posts shown for the product |
founders | array | People listed on the product: name, profileUrl, role |
twitterUrl | string | Twitter or X link when the product lists one |
logoUrl | string | Logo image URL |
scrapedAt | string | ISO timestamp of when the product page was fetched |
category | string | Category assigned by the AI step, empty when enrichment is off or failed |
Revenue is entered by the product owners themselves, so it is not verified. Some products show no revenue at all, and a few show nonsense values. For those the Actor keeps the original text, sets revenueSuspicious to true, clears monthlyRevenueUsd, and still returns the product.
How to use Indie Hackers Products Scraper
- Open the Actor in Apify Console and go to the Input tab.
- Choose what to scrape. Paste product URLs into Product or listing URLs, or leave that field empty to read the directory.
- Set Max items to the number of products you want.
- Optionally set a minimum monthly revenue, and decide whether to keep the AI category.
- Click Start. When the run finishes, open the Output tab to view the table or download JSON, CSV or Excel.
There are two ways to choose products:
- Specific products. Put one or more
https://www.indiehackers.com/product/<slug>URLs in Product or listing URLs. You can also put thehttps://www.indiehackers.com/productsURL there, optionally with?sorting=set to one of the four sortings. - Directory listing. Leave the URLs empty. The Actor reads the first page of the products directory in your chosen sorting (about 18 products) and opens each product page for the full details. The directory does not expose further pages to a plain request, so a listing run returns at most one page of products.
If a run returns no rows, check the product URL or slug first. Remove keyword or lower minMonthlyRevenue to check whether filters excluded the products. A target that remains unavailable or blocked contributes no row; the final status suggests checking targets or enabling proxy. A run with no accessible products still finishes successfully with zero records. The directory exposes only its first page, so supply explicit product URLs to inspect other products.
Input
| Field | Type | Description |
|---|---|---|
startUrls | array | Product page URLs or the products listing URL. Overrides sorting when set. |
productSlugs | array | Product slugs (or product URLs) such as keep-the-score. Added to startUrls. |
maxMonthlyRevenue | integer | Inclusive monthly revenue ceiling; omitted by default. Combined with the minimum to select a revenue band. Missing and suspicious revenue are excluded when a bound is set. |
excludeSuspiciousRevenue | boolean | Skip products flagged by revenueSuspicious, default false. Missing revenue is kept unless a revenue bound is set. |
keyword | string | Keep only products whose name, tagline or description contains this text (case-insensitive). |
sorting | string | highest-revenue, lowest-revenue, recently-added or recently-updated. Used when no product URL or slug is supplied. |
minMonthlyRevenue | integer | Keep only products with at least this monthly revenue in US dollars. Products without revenue and suspicious values are dropped. |
maxItems | integer | Maximum products to return, default 50. |
enableAiEnrichment | boolean | Add the AI category, default true. |
proxyConfiguration | object | Proxy settings. Direct by default, with an automatic datacenter proxy retry when blocked. |
Example input for the newest products in the directory:
{"sorting": "recently-added","maxItems": 15,"enableAiEnrichment": true}
Example input for specific products by slug:
{"productSlugs": ["keep-the-score", "sql-pad"],"maxItems": 2}
Revenue filters run after the product detail request and before enrichment or saving. For example, {"minMonthlyRevenue":1000,"maxMonthlyRevenue":30000} keeps only products with parsed monthly revenue within that inclusive range. A ceiling without a minimum works too. These filters apply equally to explicit URLs, slugs, and directory candidates. They do not request another directory page when candidates are excluded. If the minimum exceeds the maximum, no products match; widen the range to collect results.
Set excludeSuspiciousRevenue to true to remove implausible claims while retaining products that have not reported revenue. This differs from setting a revenue bound, which also removes missing revenue. The flag uses the existing parser and its revenueSuspicious output; it does not verify the owner’s claim or establish that a plausible amount is accurate. Both options are additive and leave existing calls unchanged when omitted. Neither adds requests to a product fetch, and filtering happens before the optional AI classification.
Output
This is a real item from a run with the AI category switched off. It is a product that reports no revenue, which is common among new listings.
{"id": "pingtopay","sourceUrl": "https://www.indiehackers.com/product/pingtopay","name": "PingToPay","tagline": "Automated payment reminders for freelancers and agencies","description": "I'm a solo builder, and this came out of a problem I actually had: I freelance-adjacent work with clients abroad, and by the time I remembered an invoice was overdue, it was the middle of their night (or mine), and I'd s","websiteUrl": "https://pingtopay.app","monthlyRevenueText": null,"monthlyRevenueUsd": null,"revenueSuspicious": null,"postCount": 1,"founders": [{"name": "ResponsibleEye","profileUrl": "https://www.indiehackers.com/ResponsibleEye","role": "Founder"}],"twitterUrl": null,"logoUrl": "https://storage.googleapis.com/indie-hackers.appspot.com/product-avatars/pingtopay/200x200_pingtopay.webp","category": null}
Fields the page does not provide are returned as null rather than invented. The Twitter link in particular is present for only a minority of products. In test runs, the name, tagline, description, website, post count, founders and logo were filled for every product, while revenue was missing for a small number of them.
You can download the dataset in JSON, CSV, Excel, XML or HTML, or read it through the Apify API.
How much does it cost?
The Actor is charged per result: you pay for each product record saved to the dataset. Products that are skipped (not found, filtered out by the revenue filter, or duplicates) are not charged. When the AI category is switched on and succeeds for a product, that product also counts as an enriched result. If the AI step fails or is unavailable, the product is saved without a category and without the enrichment charge.
Current prices are on the Pricing tab of the Actor page, which is always up to date. The Max items setting is a hard cap, so a run never saves, and never charges for, more products than you asked for. Start with a small number to see the output before you scale up.
Use with AI agents (MCP)
You can call the Actor from any MCP-compatible assistant through the Apify MCP server. Add this to your client configuration:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=axiomworks/indie-hackers-products-scraper"}}}
Example prompts you can give an assistant that has the Actor connected:
- "Get the 15 most recently added products on Indie Hackers and list their taglines and websites."
- "Scrape these Indie Hackers product slugs and show the products that report at least 5,000 dollars of monthly revenue."
- "Scrape these three Indie Hackers product pages and tell me who the founders are."
- "Find Indie Hackers products with a Twitter link and group them by category."
The input schema lists the required and optional fields, so an agent can fill in the call without extra guidance.
Integrations and API
You can run the Actor from code, schedule it, or connect it to other tools with the Apify integrations such as webhooks, Make, Zapier and Google Sheets.
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("axiomworks/indie-hackers-products-scraper").call(run_input={"sorting": "recently-added", "maxItems": 15})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["name"], item["monthlyRevenueText"])
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('axiomworks/indie-hackers-products-scraper').call({productSlugs: ['keep-the-score', 'sql-pad'],minMonthlyRevenue: 1000,maxItems: 2,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.info(items.length);
cURL
curl -X POST "https://api.apify.com/v2/acts/axiomworks~indie-hackers-products-scraper/run-sync-get-dataset-items" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"sorting": "recently-added", "maxItems": 15}'
FAQ
Why does a listing run return only about 18 products? The directory page serves its first page of products and ignores paging parameters when fetched without a browser session. To collect other products, supply their product URLs or slugs.
Why is the revenue missing or odd for some products?
Revenue is typed in by each product owner and is not checked. Some products leave it empty and some enter implausibly large values. The Actor keeps the original text in monthlyRevenueText, recognizes K, M, MM and B, and sets revenueSuspicious for unknown units or implausibly large parsed values while leaving monthlyRevenueUsd null.
What does the minimum monthly revenue filter do? It is applied after each product page is read. Products with no revenue, with a suspicious value, or with a value below your limit are skipped. Because the Actor must open each page to check, a strict filter can return fewer products than Max items.
Why is the website sometimes slightly different from the original text? Some owners store malformed links such as a single slash after the scheme or a bare domain. The Actor repairs these into valid web addresses and drops values that cannot be repaired.
What happens with a wrong URL or a product that no longer exists? The Actor logs a warning for that URL, skips it and carries on. If nothing at all can be collected, the run finishes with zero items and a warning, with a status message suggesting what to change.
Do I need a proxy? Usually not. Requests go direct by default and the Actor retries through an Apify datacenter proxy if it is blocked. You can select your own proxy group in the input.
Is the category always present? No. It is added only when the AI step is on and succeeds. If it is unavailable, the product is still saved with an empty category.
Can I get the full post history of a product? No. This Actor returns the product profile and the post count, not the individual posts.
Is it legal to scrape Indie Hackers?
The Actor collects only information that is publicly visible without logging in, at a modest request rate. It does not access private data, bypass logins or solve CAPTCHAs. Even so, whether a particular use of the data is allowed depends on your jurisdiction and purpose. The records include the names and public profile links of people listed on products, which can count as personal data under privacy laws such as GDPR. Use that data for legitimate purposes, respect opt-out requests, and review the terms of the website and the laws that apply to you. This Actor is an independent tool and is not affiliated with or endorsed by Indie Hackers. This section is general information, not legal advice.
Feedback
If a field is missing, a product page layout changes or you need another data point, open an issue from the Actor page in Apify Console. Include the input you used and the product URL involved, which makes problems much quicker to reproduce and fix.
