# Cash Converters Spain Scraper — Graded Stock (`reventadata/cashconverters-scraper`) Actor

Searches the Cash Converters Spain catalogue and returns priced, graded second-hand stock with its discount and its price when new. Pages to the end of the results instead of stopping at the first screen.

- **URL**: https://apify.com/reventadata/cashconverters-scraper.md
- **Developed by:** [reventadata](https://apify.com/reventadata) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 products

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

> **Unofficial.** This Actor is not affiliated with, authorised by, endorsed by, or in any
> way officially connected to Cash Converters. "Cash Converters" is a trademark of its
> respective owner and is used here only to describe what this tool reads. It reads the same
> public catalogue a browser does.

Cash Converters Spain Finder searches the [Cash Converters](https://www.cashconverters.es)
Spain catalogue and returns priced, graded second-hand stock — with the discount, the price
when new, and which store physically holds each unit.

### What data can you extract from Cash Converters Spain?

Cash Converters is a shop, not a marketplace. It grades its own stock (**Perfecto**, **Bueno**,
**Usado**), writes its own titles, and prices identically for the same model and grade across
every branch. That makes it the cleanest second-hand price signal in Spain — no seller prose to
interpret, no claims to verify.

This Actor pages the catalogue to the end rather than stopping at the first screen, and returns
one row per **physical unit**, not per model. A search for `iphone 13 mini` returns the same
phone from 18 different branches, each with its own link.

### Why scrape Cash Converters Spain?

- **Real pagination.** Walks every result page until the catalogue is exhausted.
- **Graded condition, not claimed condition.** Filter server-side on Perfecto / Bueno / Usado.
- **Saving against new.** Every row carries the struck-through new price and the difference.
- **Know where it is.** `storeId` says which branch holds the unit before you click.
- **Price benchmarking.** Because the chain prices by model and grade, one run gives you the
  professional resale price for a model — the number to judge a marketplace advert against.

### How to scrape Cash Converters Spain

1. Put one or more search terms in `searchQueries`. There is no default.
2. Optionally pick `conditions`, a price range, `minStorageGb` or `minDiscountPercent`.
3. Run it. Results land in the dataset, newest page last.

#### Input

| Field | Type | Meaning |
|---|---|---|
| `searchQueries` | array | One search per keyword. Required. |
| `conditions` | array | `a` Perfecto, `b` Bueno, `c` Usado. Empty means any. |
| `minPrice` / `maxPrice` | integer | Optional. Omitted entirely when left empty. |
| `minStorageGb` | integer | Read from the title. TB is converted, so 1TB counts as 1024. |
| `minDiscountPercent` | integer | The discount badge shown against the new price. |
| `requireKeywordMatch` | boolean | Drop items whose title lacks a query word. Default on. |
| `fetchDetails` | boolean | Open each item's product page to read its battery health. One extra request per result, so it is off by default. |
| `sortBy` | string | The site's own sort rules. Order only — it changes nothing about which items exist. |
| `maxItems` | integer | Hard cap on rows pushed. Default 1000. |

```json
{
    "searchQueries": ["iphone 13 mini"],
    "conditions": ["a", "b"],
    "minStorageGb": 128,
    "sortBy": "price-low-to-high",
    "maxItems": 200
}
```

#### Output

```json
{
    "title": "apple iphone 13 mini 128gb",
    "price": 330.95,
    "currency": "EUR",
    "condition": "Bueno",
    "discountPercent": 25,
    "priceWhenNew": 439.99,
    "savingVsNew": 109.04,
    "brand": "apple",
    "category": "teléfonos/móviles/apple/iphone 13 mini 128gb",
    "productId": "CC063_E734130_0",
    "storeId": "CC063",
    "url": "https://www.cashconverters.es/es/es/comprar/telefonos/moviles/apple/iphone-13-mini-128gb/?firstProduct=CC063_E734130_0",
    "imageUrl": "https://images.cashconverters.es/…",
    "matchedKeyword": "iphone 13 mini"
}
```

| Field | Meaning |
|---|---|
| `price` / `currency` | Asking price, excluding delivery. |
| `batteryHealth` | Measured health of **this unit**, from its product page. Only with `fetchDetails`. |
| `batteryHealthMin` | A stated floor rather than a measurement — the warranty minimum, usually 80. |
| `inStock` / `ratingValue` | Availability and customer rating from the product page. |
| `condition` | The shop's own grade. A fact, not a seller's claim. |
| `discountPercent` / `priceWhenNew` / `savingVsNew` | The badge, the new-price reference, and the difference. `priceWhenNew` is what the item costs new, not a former asking price. |
| `productId` / `storeId` | Unit id, and the branch holding it. `CC` codes are Spanish stores, `PT` codes are Portuguese stores selling through the same catalogue. |
| `url` | Links to this unit, not just the model — the `?firstProduct=` selector is kept deliberately. |
| `category` | The site's own category path. |

### Battery health, and the trap in it

Cash Converters states battery health **per unit**, in the product page's schema.org data. Three
units of the same model returned 76%, "over 80%" and "over 80%".

Descriptions carry two percentages, and they are not the same thing:

> *"Viene completamente operativo con **batería al 100%** y una **vida útil superior al 80%**"*

The 100% is how charged the phone happens to be. The health is the *over 80%* beside it. Reading
the first percentage as health reports a worn phone as perfect, so charge wording is excluded by
name here.

The second distinction is exactness. *"superior al 80%"* is the warranty floor, repeated across
most listings; *"el 87% de su capacidad"* is a measurement of that unit. They land in
`batteryHealthMin` and `batteryHealth` respectively, never merged.

### Notes and limits

- **One row per unit.** Rows that look duplicated are different physical phones in different
  branches. The chain prices by model and grade, so their prices genuinely match.
- **Grades are filtered one at a time.** Selecting two grades costs two passes.
- **An unknown grade returns an empty result set** rather than an error, so this Actor validates
  grades up front and fails the run instead of reporting "nothing in stock".
- **A 40-page-per-feed cap** stops a runaway keyword. When it bites it is reported in the log,
  never silently.

### How much does it cost to scrape Cash Converters Spain?

Pricing is pay-per-event: **$0.001 per result** written to the dataset (**$1.00 per 1,000
results**), plus **$0.00005** charged once when the run starts. There is no subscription —
you pay only for what you get.

### FAQ

**Is a proxy required to scrape Cash Converters Spain?** No. This Actor reads the catalogue
directly over plain HTTP; there is no `proxyConfiguration` field to set.

**Why do I see what looks like the same phone more than once?** Each row is one physical
unit, not one model. Cash Converters prices identically across every branch, so the same
model can legitimately appear several times — once per branch that holds a unit.

**Is the battery health figure a real measurement?** Only with `fetchDetails` on, and even
then read it next to `batteryHealthMin`: `batteryHealth` is a per-unit figure read from the
product page, while `batteryHealthMin` is the chain's warranty floor (usually 80%), repeated
on most listings rather than measured for that unit.

### More second-hand marketplace scrapers

| Actor | What it scrapes |
|---|---|
| [Wallapop Scraper](https://apify.com/reventadata/wallapop-scraper) | Wallapop, Spain — any keyword, phone mode with battery-health parsing |
| [Wallapop + Vinted + Milanuncios Scraper — Spain](https://apify.com/reventadata/wallapop-vinted-milanuncios-scraper) | Wallapop, Vinted and Milanuncios in Spain — one keyword, one merged table |
| [Milanuncios Scraper](https://apify.com/reventadata/milanuncios-scraper) | Milanuncios — 17 categories, condition, storage and battery-health filters |
| [Gumtree UK Scraper](https://apify.com/reventadata/gumtree-scraper) | Gumtree UK — any category, vehicle and phone details parsed from the ad's own text |
| [OLX Romania Scraper](https://apify.com/reventadata/olx-ro-scraper) | OLX Romania (olx.ro) — any keyword, no proxy required |
| [OLX Brazil Scraper](https://apify.com/reventadata/olx-scraper) | OLX Brazil (olx.com.br) — any category, structured attributes from the site's own detail chips |
| [Vinted Spain Scraper](https://apify.com/reventadata/vinted-scraper) | Vinted Spain (vinted.es) — any keyword or category, no proxy required |
| [Todocolección Scraper](https://apify.com/reventadata/todocoleccion-scraper) | Todocolección — collectibles, antiques and auctions, fixed-price and bidding modelled apart |
| [Back Market Spain Scraper](https://apify.com/reventadata/backmarket-scraper) | Back Market Spain — refurbished phones, laptops and tablets, priced against new |
| [eBay Spain Scraper](https://apify.com/reventadata/ebay-scraper) | eBay Spain (ebay.es) — active listings with seller type |

# Actor input Schema

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

One search per keyword. There is no default: an empty list fails the run rather than searching for something you did not ask for.

## `conditions` (type: `array`):

Cash Converters grades its own stock, so this is a fact rather than a seller's claim. Leave empty for any grade. One value per request, so each grade selected costs one extra pass. An unknown value returns an empty result set rather than an error, so unknown values fail the run.

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

Optional. Leave empty for no floor. Applied by the site itself, so it also narrows what the grid returns.

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

Optional. Leave empty for no ceiling. Applied by the site itself, so it also narrows what the grid returns.

## `minStorageGb` (type: `integer`):

Read from the title, where Cash Converters always puts capacity. Items that never state it are dropped when this is set. Leave empty to ignore storage. TB values are converted, so 1TB counts as 1024.

## `minDiscountPercent` (type: `integer`):

The discount badge the site shows against the price when new. Leave empty to ignore it.

## `requireKeywordMatch` (type: `boolean`):

The site's search is fuzzy - searching 'iphone 13 mini' also returns iPhone 13 and iPhone 13 Pro. This drops any item whose title does not contain every word of your query. Turn it off for broad exploration.

## `fetchDetails` (type: `boolean`):

Opens each item's product page to read its schema.org data. This is the only way to get battery health, which Cash Converters states per unit. Costs one extra request per result, so leave it off for broad price sweeps. Non-phone categories have no battery figure and the fields stay empty.

## `sortBy` (type: `string`):

The site's own sort rules. Leave empty for its default relevance order. Sorting does not change which items exist, only the order they are paged in.

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

Hard cap on rows pushed for the whole run.

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

Optional. The site lets an unproxied caller through as long as the request carries the X-Requested-With header, which this Actor always sends. Rotating the address still spreads out a large sweep.

## Actor input object example

```json
{
  "searchQueries": [
    "iphone"
  ],
  "conditions": [],
  "requireKeywordMatch": true,
  "fetchDetails": false,
  "sortBy": "",
  "maxItems": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `matches` (type: `string`):

Matching stock: price, grade, discount, price when new, and a link to the product page.

# 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": [
        "iphone"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("reventadata/cashconverters-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": ["iphone"] }

# Run the Actor and wait for it to finish
run = client.actor("reventadata/cashconverters-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": [
    "iphone"
  ]
}' |
apify call reventadata/cashconverters-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reventadata/cashconverters-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/LCAiKvVJkOm9f68Vu/builds/hBeFmZDTKaIlG4EvE/openapi.json
