# Epic Games Store Scraper - Game Prices & Discounts (`superslowsloth/epic-games-store`) Actor

Epic Games Store catalogue with price, list price and discount in any country's currency, one flat row per game, edition, add-on or demo: title, sale end date, release date, seller, developer, genres, platforms, images, URL. Sale-only, free-only, search, category and price sorts.

- **URL**: https://apify.com/superslowsloth/epic-games-store.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 game 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

## Epic Games Store Scraper - Game Prices & Discounts

Read the [Epic Games Store](https://store.epicgames.com) catalogue for any
country and get one flat row per game, edition, add-on, demo or app: current
price, list price, discount amount and percent, **when the sale ends**, release
dates, seller, developer, publisher, categories, genres, platforms, store art
and the store link. Turn on the sale-only switch and schedule it, and it is an
**Epic Games Store sale alert**; run the same search in several countries and
it is a **PC game price comparison across countries**.

No account, no API key, no login, no browser. One request returns 40 offers.

### Input

| Field | Notes |
|---|---|
| `country` | Two-letter ISO country (default `US`). Prices come back in that country's currency: US in USD, DE in EUR, JP in JPY, GB in GBP, BR in BRL. A code Epic does not recognise fails the run with Epic's own message. |
| `locale` | Language of titles and descriptions (default `en-US`; `de`, `fr`, `ja`, `pt-BR` ...). Text only: it never changes prices or currency. |
| `keywords` | Optional search, as typed into the store search box (`witcher`). Empty reads the whole catalogue. |
| `category` | `all` (default; what the store's browse page lists: games, editions, bundles, add-ons, demos, apps), `games` (games, editions and bundles), `base-games` (standard editions only). |
| `onlyOnSale` | Only offers Epic currently discounts. |
| `onlyFree` | Only offers that cost nothing right now (free-to-play, demos, free add-ons, 100%-off promotions). |
| `sort` | `newest-release` (default, the store's own order), `price-asc`, `price-desc`, `title-asc`. The price sorts use the **list** price, before any discount, because that is how Epic sorts. |
| `maxItems` | Offers to return (default 100, up to 10,000). |
| `proxyConfiguration` | Apify **residential** proxy by default. See "How it fetches". |

### Output

| Field | Notes |
|---|---|
| `country_code`, `locale` | What the run asked for. |
| `offer_id`, `namespace` | Epic's offer id (the same in every country, so it is the key to join countries on) and its catalogue namespace (a game and its add-ons share one). |
| `title`, `description`, `url` | Title, short store description, and the `https://store.epicgames.com/p/...` store page the browse card links to. |
| `categories` | Epic's category paths: `games/edition/base`, `games/edition`, `addons/durable`, `games/demo`, `applications` ... This is what tells a base game from an edition, an add-on or a demo. |
| `seller`, `developer`, `publisher` | As the store shows them. |
| `price`, `original_price`, `currency` | Current price and list price as numbers in `currency`. Epic sends integer minor units with the currency's decimals (2 for USD, 0 for JPY); these are converted, so `23.99` USD and `2384` JPY. |
| `discount_amount`, `discount_percent`, `is_discounted`, `sale_ends_at` | The sale as an amount, as a whole percent of the list price, a flag, and the end of the promotion as an ISO timestamp. |
| `is_free` | The current price is 0. |
| `voucher_discount` | A voucher Epic applied to the quoted price (0 on everything measured). |
| `price_formatted`, `original_price_formatted` | The prices exactly as the store displays them (`$23.99`, `¥2,384`; Epic shows a free offer as `0`). |
| `release_date`, `pc_release_date`, `effective_date` | ISO timestamps as Epic sends them. |
| `is_code_redemption_only` | Sold only as a redemption code. |
| `genres`, `platforms`, `tags`, `tag_ids` | Genre names (`Action`, `Indie`), platforms (`Windows`, `Mac OS`), every named tag including features (`Single Player`, `Achievements`), and Epic's raw tag ids. |
| `image_wide_url`, `image_tall_url`, `thumbnail_url` | Store art. Nothing is downloaded. |

#### Honest nulls

A field Epic did not send is `null`, never `0` or `""`:

- `discount_percent` is null for an offer whose list price is 0 (a demo, a
  free-to-play game): a percent of nothing has no meaning. It is `0` for a
  priced offer that is not on sale, because Epic states a zero discount there.
- `sale_ends_at` is null when the offer is not on sale.
- Every price field is null for an offer Epic sends without a price block (none
  measured so far; the actor asks only for priced offers, as the store does).
- `genres`, `platforms` and `tags` are null, not empty, in the rare run where
  Epic's tag-name list could not be read; `tag_ids` is still filled then. An
  empty list means the offer has no tag of that kind (many add-ons have no
  genre).
- `url` is null if Epic gives an offer no page slug (none measured).
- `discount_percent` is computed from Epic's discount and list price (Epic
  sends no percent field) and rounded to a whole number.

### 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.0007** per offer row written (`game-scraped`), i.e. $0.70 per 1,000
  offers.

### How it fetches

The store's browse page is built from a GraphQL query (`searchStoreQuery`) that
the page itself runs; the actor sends that same query, 40 offers per request,
with the country as a parameter. Measured on 2026-10-18:

- **The country is a parameter, not the proxy's location.** The browse page
  itself renders the catalogue of whatever country the visitor's address is in:
  nine residential fetches came back as DE, AL, US, DE, IT, US, BR, US and LC,
  in EUR, USD and BRL, and a `country=US` URL parameter was ignored. The query
  the actor sends answered US in USD, DE in EUR, JP in JPY, GB in GBP and BR in
  BRL from every address tried. Every row carries the currency Epic priced it
  in.
- **Residential proxy by default.** Cloudflare refused 4 of 4 Apify datacenter
  fetches of the browse page that day (and 7/10, 6/10 on earlier probes);
  residential passed 20 of 21 GraphQL requests, the one miss a dropped
  connection that the actor retries from a fresh address. The GraphQL query
  answered 8 of 8 datacenter requests too, so a datacenter proxy may work and
  costs less, but it has been measured once only.
- **Light on bandwidth.** About 0.15 MB per page of 40 offers, against about
  1.1 MB for the browse page.
- **Self-healing query id.** Epic identifies the query by a hash that changes
  when it redeploys the store. If Epic stops recognising it, the actor reads the
  current one from the store's own browse page (once per run) and carries on.
- **Result reach.** Epic lets one query reach 10,000 offers (it clamps the
  offset at 9,960), though it reports about 13,400 matching the empty search in
  the US. The actor logs when it stopped at that point; a search term, a
  category or the sale filter reaches the rest.
- **The catalogue size differs by country** (13,391 offers for the US, 13,253
  for JP, 12,058 for DE, 11,845 for BR), so the same query is not the same set
  everywhere.
- A 403, 429, 5xx, challenge page or dropped connection is treated as a
  refusal: the actor rotates to a fresh address and retries. An offer that
  shows up on two pages is returned and charged once.

# Actor input Schema

## `country` (type: `string`):

The two-letter ISO country whose Epic Games Store prices to read (US, GB, DE, FR, JP, BR ...). Epic prices every game per country and answers in that country's currency (US in USD, DE in EUR, JP in JPY, GB in GBP, BR in BRL). The currency is reported on every row. A code Epic does not recognise makes the run fail with Epic's own explanation.

## `locale` (type: `string`):

The language for titles and descriptions, as a language tag (en-US, de, fr, ja, pt-BR ...). It changes the text only, never the prices or the currency.

## `keywords` (type: `string`):

Only offers matching this text, as you would type it into the Epic store search box (for example witcher or hollow knight). Leave empty to read the whole catalogue.

## `category` (type: `string`):

'Everything' is what the store's browse page lists: games, editions, bundles, add-ons, demos and apps. 'Games and editions' leaves out add-ons, demos and apps. 'Base games only' keeps just the standard edition of each game.

## `onlyOnSale` (type: `boolean`):

Return only offers Epic currently discounts. Run it on a schedule for a sale alert.

## `onlyFree` (type: `boolean`):

Return only offers that cost nothing right now: free-to-play games, demos, free add-ons and 100%-off promotions.

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

The order Epic lists the results in. 'Release date, newest first' is the store's own browse order. The price sorts order by the LIST price, before any discount, because that is how Epic sorts.

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

Read at most this many offers, 40 per request. Epic lets one query reach at most 10,000 offers however many it reports matching, so values above 10000 are not accepted; a search term, category or sale filter reaches the rest.

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

Apify residential proxy is the default: Cloudflare refused most Apify datacenter addresses on the Epic store in testing. A refused request (403, 429, a dropped connection) is retried from a fresh address. The country you choose above sets the prices, not the proxy's location, so no proxy country is needed.

## Actor input object example

```json
{
  "country": "US",
  "locale": "en-US",
  "category": "all",
  "onlyOnSale": false,
  "onlyFree": false,
  "sort": "newest-release",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "country": "US",
    "locale": "en-US",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/epic-games-store").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 = {
    "country": "US",
    "locale": "en-US",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/epic-games-store").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 '{
  "country": "US",
  "locale": "en-US",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call superslowsloth/epic-games-store --silent --output-dataset

```

## MCP server setup

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

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/0XmCNhRk040rYqcQc/builds/s4VbzerrcaNZaIfCh/openapi.json
