# Gumroad Product Scraper (`axiomworks/gumroad-products-scraper`) Actor

Find public Gumroad products using keywords, top-level categories, and optional tag filters. The dataset includes product names, seller details, ratings, URLs, thumbnails, and description previews. Duplicate products found across searches are removed using their public permalink identifiers.

- **URL**: https://apify.com/axiomworks/gumroad-products-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.67 / 1,000 results

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

## Gumroad Products Scraper

**Returns:** one row per Gumroad product with `name`, `creatorName`, `priceCents`, `currency`, `ratingCount`, `type`, and `sourceUrl`.
**Input:** `{"searchQueries":["notion template"],"sort":"most_reviewed","maxItems":20}`
**Best for:** digital product research, creator discovery, and rating-based product shortlists.

```json
{"id":"tkfmcx","name":"Notion Student Dashboard","creatorName":"Easlo Academy","priceCents":0,"currency":"usd","ratingCount":4880,"sourceUrl":"https://easloacademy.gumroad.com/l/tkfmcx"}
```

### What does Gumroad Products Scraper do?

Gumroad Products Scraper gathers public product discovery results from Gumroad. Give it one or more keywords, one or more top-level category slugs, tag filters, or a combination. The Actor sends a search request for each combination of supplied keyword, category, tag, and file extension. It moves through the result pages until it reaches `maxItems`, finds no more matching products, or reaches the total reported by Gumroad. Repeated products appear once in the dataset, identified by their stable public permalink identifier.

Each record has the public product URL and discovery fields. Descriptions are Gumroad search previews and may end with an ellipsis. Prices use each product's currency in integer cents, without conversion. Missing optional values are `null`.

Use `payWhatYouWantOnly` to select products whose flexible pricing flag is true, or `sellerVerifiedOnly` to select sellers with a true verification flag. Both are optional and default to false. They combine with the existing type, rating-count and zero-price filters before deduplication and the shared item limit. A product that is pay what you want does not necessarily have a zero minimum price. `freeOnly` keeps its existing meaning: the listed price must be zero.

`originalPriceCents` copies the optional original price from the search response in the product currency. Compare it with `priceCents` when both are present; the Actor does not infer a discount percentage or invent an original price when Gumroad omits one. No detail-page requests are needed for this field. Selective filters may need several pages to find enough qualifying products. Pages with no qualifying matches do not end pagination; repeated source pages and empty responses still stop it.

Listings and ratings may change. The dataset captures Gumroad search results at run time.
File-extension filtering helps you find downloadable formats such as PDF books, ZIP asset packs, and Blender files. Supply `fileTypes` with one or more extensions; Gumroad applies each extension filter on the search endpoint. Multiple extensions mean any of the supplied formats, with repeated products saved once. The Actor normalizes uppercase extensions and a leading dot. This filter does not add a per-product file inventory to the output: the discovery response does not provide one.

Tags also work as standalone targets. For example, `{"tags":["notion"],"maxItems":20}` browses that tag without requiring a keyword or category. Combine tags with keywords to narrow discovery, or supply several tags to collect their combined results under one shared limit.

### What data can you get?

| Field | Meaning |
| --- | --- |
| `id` | Stable public permalink identifier used for deduplication. |
| `sourceUrl` | Canonical public product page URL from the search item. |
| `name` | Product name in the search result. |
| `creatorName` | Public seller display name. |
| `creatorUrl` | Public seller profile URL when supplied. |
| `priceCents` | Listed price in the product's currency, in cents. |
| `currency` | Product currency code. |
| `originalPriceCents` | Original price in product currency when the search response supplies it; otherwise null. |
| `payWhatYouWant` | Whether the listing has flexible pricing. |
| `ratingAverage` | Average public rating when supplied. |
| `ratingCount` | Number of public ratings when supplied. |
| `thumbnailUrl` | Public product thumbnail URL when supplied. |
| `type` | Gumroad's native product type, such as digital or bundle. |
| `description` | Search result description preview. |
| `recurrence` | Subscription recurrence when supplied. |
| `quantityRemaining` | Remaining quantity when Gumroad supplies it. |
| `sellerId` | Public seller identifier from the search result. |
| `sellerVerified` | Whether Gumroad marks the seller as verified. |
| `sellerAvatarUrl` | Public seller avatar URL when supplied. |

Search results do not supply reliable per-product tags, sales totals, or categories. Zero and null are distinct: zero is a reported value, while null indicates unavailable data.

### How to use

Open the Actor on Apify and enter a keyword in **Search queries**, or enter a top-level Gumroad taxonomy slug in **Categories**. Set the sort and item limit, then run. The default example searches for `notion template`, orders by most reviewed, and returns up to 20 unique products. To browse a category, clear the keyword list and enter a slug such as `design`. You may supply several keywords and several categories; the Actor searches their combinations and removes duplicate products across them.

For a narrow search, start with one keyword and a small `maxItems`. If the first results do not match your aim, refine the phrase or add a relevant category or tag. Tags are search filters and are not copied into product records as if Gumroad had supplied per-product tag metadata. Categories should use top-level slugs. Unknown or nested taxonomy slugs may be ignored by Gumroad and can produce broad results; inspect the returned products before assuming the category restricted them.

The Actor requests at most one search page per second. It follows Gumroad's page offsets of 1, 10, 19, and so on when each response contains nine products. It stops early on an empty result page. If all searches have no results, the run finishes with an empty dataset and a status message suggesting broader keywords, a top-level category slug, or fewer filters. If the server blocks or throttles a request, the Actor waits and retries; users who enable Apify Proxy get a fresh proxy session on each retry. A persistent request failure is caught for that search, logged, and included in the final status when no results are available. The run succeeds with zero rows if every valid target remains blocked; other targets continue.

A run can return fewer than `maxItems` if fewer matching products exist, filters remove them, or entries lack required fields. A value of 7 yields exactly 7 items when enough qualifying products exist. Each pushed item has one result event. Missing optional fields are `null`.

### Input

| Input | Purpose | Default |
| --- | --- | --- |
| `searchQueries` | Keyword phrases; supply keywords, categories or tags. | Example prefill: `notion template` |
| `categories` | Top-level category slugs; optional when keywords or tags are supplied. | Empty list |
| `tags` | Tag filters; may be supplied alone or combined with keywords and categories. | Empty list |
| `sort` | One of `featured`, `most_reviewed`, `highest_rated`, `newest`, `hot_and_new`, `price_asc`, `price_desc`. | `featured` |
| `minPrice` | Optional lower search price filter in Gumroad search units. | Omitted |
| `maxPrice` | Optional upper search price filter in Gumroad search units. | Omitted |
| `minRating` | Optional minimum rating filter, from 1 to 4. | Omitted |
| `maxItems` | Maximum unique records to emit, from 1 to 10000. | 50 |
| `nativeTypes` | Keep matching Gumroad native product types. | Empty list |
| `fileTypes` | Download extensions, such as pdf, zip or blend; any supplied extension may match. | Empty list |
| `minRatingCount` | Keep products with at least this many public ratings. | Omitted |
| `payWhatYouWantOnly` | Keep only listings marked pay what you want; combine with freeOnly to require zero listed price. | `false` |
| `sellerVerifiedOnly` | Keep only sellers marked verified by Gumroad. | `false` |
| `freeOnly` | Keep products with a listed price of zero in their own currency. | `false` |
| `proxyConfiguration` | Apify Proxy configuration. | Disabled |

Here is a keyword search input:

```json
{
  "searchQueries": ["notion template"],
  "sort": "most_reviewed",
  "maxItems": 20,
  "proxyConfiguration": {"useApifyProxy": false}
}
```

For a category search, use `{"categories":["design"],"sort":"highest_rated","maxItems":30}`. You can pass keyword and category lists together to compare a phrase within categories. Empty keyword, category and tag lists are invalid, and the Actor exits with a clear error. Do not use product page URLs as search terms; this Actor searches Gumroad discovery listings.

For a rated course shortlist, add `"nativeTypes":["course"]` and `"minRatingCount":20`. Set `"freeOnly":true` to keep zero-price listings. These three filters are checked against each search result before it is saved; products without the requested type or rating count are excluded. The Actor continues paging until it fills the item limit or exhausts the result set. A zero listed price can also be a pay-what-you-want listing, so inspect `payWhatYouWant` when that distinction matters.

`maxItems` is shared across all combinations. Overlapping products appear once. Searches follow input order, so put priority targets first. Product URLs omit layout and recommendation parameters.

A file-filtered discovery input is `{"searchQueries":["blender"],"fileTypes":["pdf","blend"],"maxItems":20}`. Each extension is searched separately through the same Gumroad discovery endpoint; the Actor deduplicates products across those searches. A PDF result may also include other download formats. An unknown extension can return no products. Start with a small limit to check the result set before collecting a larger catalog.

### Output

The following is one real item from a local run using the keyword example above. Current search results can differ as Gumroad changes its index.

```json
{
  "id": "tkfmcx",
  "sourceUrl": "https://easloacademy.gumroad.com/l/tkfmcx",
  "name": "Notion Student Dashboard",
  "creatorName": "Easlo Academy",
  "creatorUrl": "https://easloacademy.gumroad.com/",
  "priceCents": 0,
  "currency": "usd",
  "payWhatYouWant": true,
  "ratingAverage": 5,
  "ratingCount": 4880,
  "thumbnailUrl": "https://public-files.gumroad.com/jvqdiiolbolhlduclvktr5wj6h7o",
  "type": "digital",
  "description": "Transform Your Student Life with an Organized Notion Dashboard Introducing a pre-built template c...",
  "recurrence": null,
  "quantityRemaining": null,
  "sellerId": "3345958371424",
  "sellerVerified": false,
  "sellerAvatarUrl": "https://public-files.gumroad.com/4k7ue4pbjerm3o4y3tnuo9m1oave"
}
```

This record maps a public Gumroad search item. URLs have tracking parameters removed. The description is a search preview, and missing optional data is null.

### How much does it cost?

The Actor is charged per result record. One `result` event is associated with each dataset item that is actually pushed. A query that returns zero items produces no result events. A record already emitted from another search combination is skipped and is not charged again. The run may make several search requests to find the records, depending on the requested item limit and how much overlap exists between queries. See the Actor's **Pricing** tab for current pricing and charging details.

Set `maxItems` to the number of records you need; processing stops when that limit is reached.

### Use with AI agents (MCP)

An AI agent can discover and run this Actor through Apify's MCP server. Point your MCP client at the server with this tool path:

```text
https://mcp.apify.com/?tools=axiomworks/gumroad-products-scraper
```

Configure your MCP client's Apify connection and give the agent a target and item limit. Example prompts: “Find ten Gumroad notion templates and show name, creatorName, sourceUrl and currency.” Or: “Browse design, sort by highest_rated, and compare ratingAverage with ratingCount.”

Ask agents to carry sourceUrl for review, keep currencies beside prices, and report null values as unavailable. Descriptions are previews. Rating counts provide context for averages; the Actor does not judge product quality.

### Integrations and API

Apify datasets can be connected to other tools after the run. Download JSON or CSV in the Console, use a dataset API endpoint in a workflow, or call the Actor from an application. The following examples show a keyword run and then read its dataset. Supply your own Apify token through your runtime's usual secret mechanism; do not place credentials in a shared script or published document.

Python with the Apify client:

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("axiomworks/gumroad-products-scraper").call(run_input={
    "searchQueries": ["notion template"],
    "maxItems": 20,
})
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
for item in items:
    print(item["name"], item["sourceUrl"])
```

JavaScript with the Apify client:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/gumroad-products-scraper').call({
    categories: ['design'],
    sort: 'highest_rated',
    maxItems: 30,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) process.stdout.write(`${item.name}\n`);
```

A cURL request can start a run and return dataset items in one response:

```bash
curl -X POST \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries":["notion template"],"maxItems":20}' \
  'https://api.apify.com/v2/acts/axiomworks~gumroad-products-scraper/run-sync-get-dataset-items'
```

For large runs, start asynchronously and fetch the dataset after completion. Join catalogs with `id`, preserve `sourceUrl`, and compare prices only alongside `currency`. A product missing from a later search may reflect ranking or filter changes.

### FAQ

**Do I need a Gumroad account?** No. The Actor reads a public search response and does not authenticate to Gumroad. Your Apify account is used to run the Actor on Apify.

**Can I search more than one keyword?** Yes. Enter several strings in `searchQueries`. The Actor searches them in order and deduplicates repeated products by permalink ID. The global item limit still applies to the entire run.

**Can I browse without a keyword?** Yes. Supply a top-level category slug in `categories` or a tag in `tags`, and leave `searchQueries` empty. A target is required so the Actor does not run an unbounded search by accident.

**Why are some values null?** Search listings do not always include every optional attribute. The Actor keeps the field and returns `null` when the source did not provide a usable value. It does not replace missing ratings or quantity with a made-up zero.

**Does the description include the full product page text?** No. It is the preview returned by Gumroad search. Some previews end with an ellipsis. Visit the public `sourceUrl` if you need to read the current product page.

**Why does a category return broad results?** Gumroad may not recognize an unknown or nested taxonomy slug as a filter. Use a verified top-level slug and inspect the output. The Actor forwards the slug you provide; it does not invent a category label for each product.

**Why did a run return fewer items than requested?** There may be fewer matches, the search may have reached an empty page, or some malformed entries may lack required fields. The limit is the maximum number of valid, unique records to return.

**Does the Actor access private information?** No. The output contains public product and creator details exposed in search results. It does not scrape sales dashboards, customer records, or purchase history.

### Is it legal to scrape Gumroad?

Public product information can be accessed through Gumroad's public discovery search. Laws and website rules vary by location and use case, so review the requirements that apply to your project before redistributing or republishing data. Respect creators' rights and avoid presenting their listings in a misleading way. This Actor does not log in, access purchase records, or bypass access controls. It makes modestly paced requests and backs off when the service throttles or blocks a request. This Actor is not affiliated with or endorsed by Gumroad.

### Feedback

If you see a missing field, an unexpected null, or a search that appears too broad, share the input used, the run ID, and a few public product URLs. Include whether the issue occurs with a keyword or a category, the sort mode, and the approximate time of the run. Do not include private account data or credentials. This context helps distinguish a changed Gumroad search response from an input filter that the site did not apply.

# Actor input Schema

## `searchQueries` (type: `array`):

Keyword phrases to search, e.g. \["notion template"]. Supply searchQueries, categories, or tags; none is supplied automatically in API calls. Keywords, categories, tags and fileTypes form combinations. Blocked or empty searches return no rows; other searches continue.

## `categories` (type: `array`):

Top-level Gumroad category slugs, e.g. \["design", "software-development"]. Default \[] adds no category restriction. Supply keywords, categories, or tags; categories combine with every supplied keyword. Unknown or nested slugs may be ignored by Gumroad.

## `tags` (type: `array`):

Tag strings to browse or filter, e.g. \["notion"]. Default \[] adds no tag restriction. Tags work alone or with keywords/categories. Each tag creates a separate search combination; returned products do not include tag lists.

## `sort` (type: `string`):

Gumroad search order, e.g. "most_reviewed" for products with more reviews. Default "featured" uses Gumroad featured ordering; the prefilled example uses "most_reviewed". Choose one of the listed modes.

## `minPrice` (type: `integer`):

Optional integer lower price filter sent unchanged as Gumroad min_price, e.g. 10. Must be 0 or greater; omitted by default. This search filter uses Gumroad search units, while output priceCents uses each product currency in cents.

## `maxPrice` (type: `integer`):

Optional integer upper price filter sent unchanged as Gumroad max_price, e.g. 50. Must be 0 or greater; omitted by default. Combine with minPrice for a range; output priceCents uses each product currency in cents.

## `minRating` (type: `integer`):

Optional Gumroad minimum rating filter, e.g. 4. Accepts an integer from 1 to 4; omitted by default for any rating. Applied to each keyword/category/tag combination.

## `nativeTypes` (type: `array`):

Gumroad native product type strings, e.g. \["digital", "course", "ebook"]. Default \[] keeps all types. Matches the returned type case-insensitively; unknown types can yield no results. Applied before the shared maxItems limit.

## `fileTypes` (type: `array`):

File extensions to filter through Gumroad search, e.g. \["pdf", "blend"]. Default \[] keeps all file formats. Multiple extensions mean any listed extension, with one search per extension. Case and a leading dot are normalized. Requires keywords, categories, or tags. No per-product file list is returned.

## `minRatingCount` (type: `integer`):

Optional minimum public rating count, e.g. 100. Accepts an integer 0 or greater; omitted by default, including products with unavailable counts. When supplied, excludes unavailable counts and applies before maxItems.

## `freeOnly` (type: `boolean`):

Set true to keep products with priceCents equal to 0 in their own currency, e.g. true. Default false keeps all listed prices. Applied before maxItems; combine with payWhatYouWantOnly to also require flexible pricing.

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

Maximum unique matching products across all keyword, category, tag and file-type combinations, e.g. 20. Integer 1-10000, default 50. Filters apply before this shared limit. Returns fewer when matches run out or searches remain blocked.

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

Proxy settings for requests to Gumroad, e.g. {"useApifyProxy":true}. Default {"useApifyProxy":false} fetches directly. Enable Apify Proxy if requests remain blocked; retry attempts use fresh sessions. Persistent blocks return no rows for that search.

## `payWhatYouWantOnly` (type: `boolean`):

Set true to keep products with payWhatYouWant equal to true, e.g. true. Default false keeps both pricing modes. Applied before maxItems; combine with freeOnly to require a zero listed price as well.

## `sellerVerifiedOnly` (type: `boolean`):

Set true to keep products with sellerVerified equal to true, e.g. true. Default false includes unverified sellers and unavailable verification values. Applied before the shared maxItems limit.

## Actor input object example

```json
{
  "searchQueries": [
    "notion template"
  ],
  "categories": [],
  "tags": [],
  "sort": "most_reviewed",
  "nativeTypes": [],
  "fileTypes": [],
  "freeOnly": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "payWhatYouWantOnly": false,
  "sellerVerifiedOnly": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Scraped product records.

# 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 = {
    "searchQueries": [
        "notion template"
    ],
    "sort": "most_reviewed",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/gumroad-products-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 = {
    "searchQueries": ["notion template"],
    "sort": "most_reviewed",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/gumroad-products-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 '{
  "searchQueries": [
    "notion template"
  ],
  "sort": "most_reviewed",
  "maxItems": 20
}' |
apify call axiomworks/gumroad-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/gumroad-products-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/Zp2uhInoTuLB61Q1t/builds/9XfpMMyQcXBeHCRc3/openapi.json
