# AppSumo Deals Scraper and New Lifetime-Deal Alert (`superslowsloth/appsumo-deals`) Actor

Every AppSumo deal as one flat row: name, price, list price, discount %, codes left, start date, live or ended, rating and review count, features, URL. Filter to live deals started in the last N days, by rating, price or keyword.

- **URL**: https://apify.com/superslowsloth/appsumo-deals.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 deal scrapeds

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

## AppSumo Deals Scraper and New Lifetime-Deal Alert

Every deal on [AppSumo](https://appsumo.com), one flat row each: name, price,
list price, discount %, codes left, start date, whether it is live or ended,
rating and review count, feature list, deal URL. Filter to **live deals that
started in the last N days** and schedule the run daily for a new lifetime-deal
alert feed, or turn the filters off and pull the whole catalogue (about 4,400
deals, back to 2017).

No account, no login, no API key. It reads the public JSON API AppSumo's own
site uses.

### Input

| Field | Notes |
|---|---|
| `maxItems` | Return at most this many deals, **newest start date first**, after every filter (default 100). |
| `onlyLive` | Default on: only deals AppSumo currently lists as on sale. Off also returns the expired ones (about 88% of the list). |
| `startedWithinDays` | Only deals that went on sale in the last N days. The new-deal alert filter. |
| `startedAfter` | Only deals that went on sale on or after this date (`2026-10-01`, or a full ISO timestamp). With `startedWithinDays` the later date wins. |
| `minRating` | Minimum average rating, 0 to 5. Deals with no reviews have no rating and are left out when this is set. |
| `minReviews` | Minimum number of reviews. |
| `maxPrice` | Maximum price in US dollars. |
| `search` | Words that must all appear in the deal's name or URL slug, any case. Name only: see "What the list does not have". |
| `proxyConfiguration` | **Required**, Apify datacenter proxy by default. A run with no proxy stops before it fetches or charges anything. |

#### Every run reads the whole list

AppSumo's API takes `page` and `per_page` and nothing else. Measured on
2026-10-13: `ordering`, `sort` and the other filter parameters tried are
ignored, so there is no server-side way to ask for "newest" or "live". The
actor therefore reads **every page** (44 pages of 100 for the 4,368 deals
listed that day), filters and sorts locally, and only then writes rows.

- **You are charged per row written, not per page fetched.** A filter that
  leaves 9 deals costs 9 rows plus the start fee, even though 44 pages were
  read.
- A full sweep takes about 6 minutes (352 s measured from this VM, 44 of 44
  pages, no retries): the API answers an uncached page in 6 to 10
  seconds, and a page is about 2 MB of JSON (about 460 KB compressed on the
  wire, so roughly 20 MB of proxy traffic per run).
- `per_page` above 100 is not used. 101 works; 250 and 1000 answered HTTP 502
  after 15 to 30 seconds.
- The list shifts while it is being paged (new deals arrive at the top), so a
  deal at a page boundary can show up on two pages and another can be skipped.
  Measured on the same day: 4,368 rows read, 4,361 distinct deals. The actor
  dedupes by `deal_id`; a skipped one is picked up by the next run.
- If a page cannot be read after the retries, the run goes on with the rest,
  logs `sweep has holes`, and a newer deal may be missing. The run fails only
  if the first page, which carries the page count, cannot be read.

### Output

| Field | Notes |
|---|---|
| `deal_id`, `slug`, `url`, `name` | AppSumo's numeric id, the `/products/<slug>/` slug, the deal page, the product name. |
| `status`, `is_live` | `status` is AppSumo's `browse_deal_status`: `current` (on sale) or `expired`. `is_live` is true exactly when it is `current`. |
| `has_started`, `has_ended`, `availability` | AppSumo's own flags and `in stock` / `out of stock`. They are not the same as `status`: a deal listed as "coming soon" is expired and has neither started nor ended. |
| `price`, `original_price`, `discount_percent` | US dollars. `discount_percent` is `round(100 * (1 - price / original_price))`, computed here. `price` 0.0 is a free deal, as sent. |
| `codes_remaining`, `uses_codes` | Unsold codes. 0 means sold out. See "Honest nulls". |
| `plan_type` | The default plan's type: `Lifetime Deal`, `Limited License`, `Digital Download` or `One Time Purchase`. |
| `is_marketplace` | True for a deal from AppSumo's marketplace programme rather than a vendor-negotiated launch, as sent. |
| `start_date`, `end_date` | When the deal went on sale, and when it ends, as AppSumo prints them (ISO-8601 with its Central-time offset). `end_date` is null on most deals, ended ones included. |
| `rating`, `review_count` | Average of the 1 to 5 ratings, and how many reviews. |
| `features` | The bullet list of what the deal includes. Empty when AppSumo lists none. |
| `product_url`, `image_url`, `logo_url` | The vendor's site, the deal image, the product logo. |

#### Honest nulls

A field AppSumo did not give is `null`, never `0` or `""`.

- `rating` is null for a deal with no reviews, not 0 stars (AppSumo sends null).
- `original_price` is null where AppSumo shows no list price. The API sends
  `0.0` there (537 of 4,368 deals); that is "none shown", and `discount_percent`
  is null with it.
- `codes_remaining` is null on a deal with no code pool (`uses_codes` false:
  AppSumo's licensing deals). The API sends 0 for those whether or not the deal
  can be bought: 253 of the 542 live deals on 2026-10-13 were "in stock" with 0.
  Reading that as "sold out" would be wrong, so it is null. A positive number is
  passed through; 0 on a deal that does use codes is a real sell-out.
- `start_date` is passed through untouched. One old deal (Vectera) carries a
  start date in 2030. Such a deal is never counted as "started within N days".

#### What the list does not have

The API's list has no **category**, no **tagline** or **description**, and only
the default plan's price. So there is no category filter, `search` matches the
name and slug only, and a column of nulls was not added in their place.

### Pricing

Pay per event:

- **$0.002** per run (`actor-start`), charged only after your input is
  validated, so a run that fails on bad input costs nothing.
- **$0.00069** per deal row written (`deal-scraped`), i.e. $0.69 per 1,000
  deals. Deals read and filtered out are not charged.

For reference, the other AppSumo scrapers on the Store charge $0.001 per deal.

### How it fetches

The API is public JSON. The actor presents a browser's TLS fingerprint
(curl_cffi, current Chrome) through Apify datacenter proxy. Plain curl from an
ordinary connection and a curl_cffi probe through Apify datacenter proxy both
got HTTP 200; a probe's 200 only proves the probe's client, so the actor uses
the impersonating client rather than assuming a plain one works from the
platform.

HTTP 403, 429, 202 and 5xx, and a 200 that is not a deals page (a challenge, an
error body), are retried from a fresh exit address. A genuine 404 (the API
answers `{"detail":"Invalid page."}` for a page past the end) and any other
status are not retried.

# Actor input Schema

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

Return at most this many deals, newest start date first, after every filter below has been applied. You are charged per deal returned, never for deals that were read and filtered out. The run reads AppSumo's whole list (about 44 pages) either way, because the API cannot sort or filter.

## `onlyLive` (type: `boolean`):

Keep only deals AppSumo currently shows as on sale (its browse_deal_status is 'current'). Turn it off to also return the several thousand expired deals, which is a historical catalogue rather than an alert feed.

## `startedWithinDays` (type: `integer`):

Keep only deals that went on sale in the last N days, counted from the moment the run starts. This is the new-deal alert filter: schedule the run daily with 1, or weekly with 7. Leave empty for no limit. A deal whose start date is in the future is not counted as started.

## `startedAfter` (type: `string`):

Keep only deals that went on sale on or after this date, written 2026-10-01 or as a full ISO-8601 timestamp (UTC when it has no offset). Combined with 'Started within the last N days', the later of the two dates wins. Leave empty for no limit.

## `minRating` (type: `number`):

Keep only deals whose average rating (1 to 5) is at least this. Deals with no reviews have no rating and are left out whenever this is set. Leave empty for no limit.

## `minReviews` (type: `integer`):

Keep only deals with at least this many reviews. Leave empty for no limit.

## `maxPrice` (type: `number`):

Keep only deals priced at or below this many US dollars. Leave empty for no limit.

## `search` (type: `string`):

Keep only deals whose name or URL slug contains every word written here, ignoring case: 'seo' or 'email verifier'. AppSumo's list has no description or category to search, so this matches the product name only. Leave empty for no filter.

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

Required. AppSumo's API was verified through Apify datacenter proxy, which is the default; a run with the proxy switched off stops before it fetches or charges anything. A full sweep is about 20 MB of compressed traffic.

## Actor input object example

```json
{
  "maxItems": 100,
  "onlyLive": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

No description

# 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 = {
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/appsumo-deals").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 = { "proxyConfiguration": { "useApifyProxy": True } }

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/appsumo-deals").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 '{
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/appsumo-deals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/appsumo-deals"
        }
    }
}
```

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/B0i7IevSALkTVkIIU/builds/I8TfvuS9DnReY0mkH/openapi.json
