# Buycycle.com — Used Bike Finder (`inovaflow/buycycle-hunter-pw`) Actor

Search Buycycle — Europe's largest used bike marketplace. Filter by brand, size, price, year, and condition. Get curated highlights, deal scores, and new-listing alerts.
Want more bike marketplaces rolled into the same Actor? Email hello@inovaflow.io and we'll add them.

- **URL**: https://apify.com/inovaflow/buycycle-hunter-pw.md
- **Developed by:** [inovaflow](https://apify.com/inovaflow) (community)
- **Categories:** E-commerce
- **Stats:** 14 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.10 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Buycycle Used Bike Finder & Deal Tracker 🚴

[![Apify Actor](https://apify.com/actor-badge?actor=inovaflow/buycycle-hunter-pw)](https://apify.com/inovaflow/buycycle-hunter-pw)

Search **[buycycle.com](https://buycycle.com)** — Europe's largest used bike marketplace — and pull back clean, structured listings filtered by brand, size, price, year, condition, groupset, and more. Built for cyclists hunting deals, shops tracking inventory, and price-watchers monitoring specific models.

***

### What this Actor does

Buycycle has tens of thousands of used road, gravel, MTB, and e-bikes for sale across 29 countries — but their search UI gets clunky once you're combining filters, and there's no native way to be notified when a specific bike pops up. This Actor wraps their search in a clean, schedulable interface that returns:

- **Structured JSON** for every listing (brand, model, year, size, price, MSRP, discount %, wishlist count, "high demand" flag, image, link, and more)
- **Curated highlights** so you see only the listings that matter (biggest discounts, cheapest per model, best value, popular bikes, etc.)
- **New-listing tracking** that flags bikes added since your last run — perfect for daily monitoring with email or Slack notifications

### Why use it

- **One place, every filter.** Search any combination of country, brand, frame size, price range, model year, condition, frame material, brake type, shifting type, e-bike vs analog, frameset vs complete bike, and seller type — all in a single run.
- **Spot real deals automatically.** The "Best value" highlight strategy ranks bikes by a composite score combining discount %, model freshness, and condition. The "Skip overpriced" strategy filters out anything more than 1.5× the median price for your search.
- **Get notified when new bikes show up.** The "New listings only" mode remembers what it saw last run and only returns bikes that weren't there before. Pair it with Apify's [integrations](https://apify.com/integrations) to fire a Slack or email notification only when something genuinely new appears.
- **29 countries, 3 currencies.** Buycycle ships internationally — search the German marketplace from the US, or the Swiss marketplace from Spain. Currency (EUR, USD, CHF) is preserved in the output. Proxy region is automatically matched to the marketplace you pick, which keeps Cloudflare happy and reduces blocks.

### Features

| | |
|---|---|
| 🔍 Free-text + filters | Combine keyword search with any of 14 filter categories |
| 🌍 29 marketplaces | All Buycycle countries (DE, FR, IT, ES, US, CH, …) |
| 💰 Deal scoring | Composite score combines discount %, year, condition |
| 🔔 New-listing detection | Per-search dedup memory, perfect for daily monitoring |
| 🛡️ Cloudflare-aware | Geo-matched residential proxies + browser fingerprinting |
| 📊 Two datasets | Curated `Output` for notifications, full `full-results` for analysis |
| 📝 Markdown summary | Human-readable summary stored in the run's key-value store |

### Input

All inputs are optional. The minimal valid run is no input at all (it'll search the German marketplace with default settings).

The most common inputs you'll set:

- **Search keyword** — free-text like `"canyon aeroad"`, `"tarmac sl7"`, `"pinarello"`. Leave blank to browse using filters only.
- **Country** — pick the marketplace. Defaults to Germany (largest pool). The Actor automatically routes its requests through a residential proxy in the same country — this looks like a real local shopper to Cloudflare and significantly reduces blocks.
- **Brands / Frame size / Price range / Year range / Conditions** — narrow down what you want.
- **Highlights filter** — choose how the main `Output` dataset is curated. Defaults to `None — return full list`. Switch to `New listings only` for monitoring use cases.
- **Max pages to crawl** — safety cap. Each page is roughly 50 bikes. Default is 2 (~100 bikes), max is 50 (~2500 bikes).

See the **Input** tab for the full list of fields with descriptions.

### Output

Two datasets are produced on every run:

#### `Output` (default dataset)

The curated set, filtered by the **Highlights filter** you chose. This is what notifications fire on. With the default `None — return full list` strategy, this contains every bike found.

#### `full-results` (storage dataset)

The complete, unfiltered crawl — always available regardless of highlight strategy. Use this for analysis, archival, or if you want to query results yourself.

#### Per-bike fields

```json
{
  "itemId": "182734",
  "brand": "Canyon",
  "name": "Aeroad CFR Disc Di2",
  "priceBase": 4200,
  "priceTotal": 4452,
  "buyerProtectionFee": 252,
  "currency": "EUR",
  "msrp": 7999,
  "isDiscounted": true,
  "discountPct": 44,
  "size": "M",
  "year": 2022,
  "groupset": "Shimano Dura-Ace Di2",
  "wishlistCount": 87,
  "isHighDemand": true,
  "imageUrl": "https://.../",
  "productUrl": "https://buycycle.com/en-de/bike/...",
  "pageNum": 1,
  "scrapedAt": "2026-04-13T10:22:31.123Z",
  "searchKeyword": "canyon aeroad"
}
```

Additional fields appear depending on the highlight strategy:

- **`isNew`** — only present when using the `New listings only` strategy. `true` if the listing wasn't seen on the previous run with the same filters.
- **`dealScore`** — only present when using the `Best value` strategy. Composite score combining discount %, model freshness, and condition.

#### Run summary

A human-readable Markdown summary is also stored at `summary-markdown` in the key-value store, and a structured `OUTPUT` record holds the cheapest bike, biggest discount, most popular bike, and total counts.

### Highlight strategies

The **Highlights filter** is the most powerful feature. It controls which bikes land in the main `Output` dataset (and therefore which bikes trigger notifications if you've wired any up). Pick one strategy per run:

- **None — return full list.** Every bike found goes into Output. Default.
- **New listings only (vs last run).** Tracks itemIDs from the previous run with the same filters and only returns bikes that weren't there before. First run returns the full result set as the baseline. **This is the strategy to use for daily monitoring.**
- **Discounted bikes.** Only bikes with at least *N*% off MSRP. Set the threshold via the `Minimum discount %` field.
- **Cheapest per model variant.** Groups bikes by normalized name + year and returns only the cheapest of each — great for catching multiple sellers offering the same bike.
- **Best value (composite deal score).** Ranks all bikes by a weighted score combining discount %, model freshness, and condition, then returns the top 20.
- **Skip overpriced (above 1.5× median).** Drops outliers — useful when one mistitled or rare-spec listing is skewing the price range.
- **Popular.** Only bikes wishlisted by at least *N* users. Set the threshold via the `Minimum wishlist count` field.

### Use cases

**1. Daily deal alerts for a specific bike.** Set the keyword to `"canyon aeroad"`, country to your local marketplace, highlights filter to `New listings only`, schedule the actor for daily runs, and connect a [Slack integration](https://apify.com/apify/slack). You'll get a ping the moment a new Aeroad shows up.

**2. Inventory tracking for shops.** Search by brand and condition (`Brand new with guarantee`), set `Sold by` to `Shop / dealer`, and run weekly to track what your competitors have in stock.

**3. Market analysis.** Run with no keyword, max pages set to 50, and `None — return full list` to pull a 2500-bike sample of the entire marketplace. Export to CSV and analyze price distributions, popular brands, average discounts.

**4. Frame hunting.** Set `Frameset only`, pick a brand, and monitor for rare framesets in your size.

### How proxies work

Buycycle is protected by Cloudflare, so this Actor uses Apify residential proxies and automatically matches the proxy country to the marketplace country you pick. You don't need to configure anything — it just works.

### Actor permissions

When running this Actor, select **Full permissions** in the run options. The "New listings only" highlight strategy uses a named key-value store to remember which bikes it saw on previous runs — this requires Full permissions to create and access across runs. Limited permissions will cause dedup memory to reset every run, breaking the monitoring feature.

If you're not using the "New listings only" strategy, Limited permissions should work fine — but Full permissions is the safer default.

### Run time

Buycycle uses advanced bot protection. This Actor works through it using residential proxies and browser fingerprinting, which means each page load takes 15–60 seconds including retries. A typical 2-page run finishes in 1–3 minutes. This is normal — the Actor is designed to be patient rather than fast.

### Limitations

- **Detail pages aren't scraped.** Only the search-results cards. If you need full bike specs, contact info, or seller history, this Actor doesn't currently fetch those — let us know if it'd be useful.
- **The dedup memory is per-search.** If you change any filter (other than `Max pages` or the highlights strategy), you'll start a fresh baseline.
- **Only English locales.** Buycycle has localized versions, but the URL builder uses the `en-*` slug for every country to keep parsing consistent.
- **Cloudflare can still occasionally block runs.** If you see 0 results, retry — the Actor uses a fresh browser fingerprint each time and usually succeeds within 1–2 retries.

### Want more bike marketplaces?

Reach out to <hello@inovaflow.io> if you'd like to see other used-bike marketplaces (chainreactioncycles, bikeexchange, marktplaats, etc.) rolled into the same Actor — or built as separate Actors that share the same output schema. We're actively expanding this.

### Feedback & support

Built and maintained by [Inovaflow](https://inovaflow.io), a Prague-based integration engineering team. Have an idea, request, or bug report? Open an issue on the Actor page or reach out directly — feedback shapes the roadmap.

### License

ISC

# Actor input Schema

## `model` (type: `string`):

Free-text keyword to search buycycle.com. Leave blank to browse by filters only.

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

Order listings before collection. Default lowest-price.

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

Marketplace country. Sets currency, seller pool, and proxy region. Default Germany (de).

## `locationScope` (type: `string`):

Limit results by seller location relative to the chosen country. Leave empty for worldwide.

## `brands` (type: `array`):

Filter to specific bike brands. Leave empty for all brands.

## `frameSizes` (type: `array`):

Filter by frame size (seat-tube length). Leave empty for all sizes.

## `priceMin` (type: `integer`):

Lower price bound in the marketplace currency (incl. buyer protection fee). Leave empty for no minimum.

## `priceMax` (type: `integer`):

Upper price bound in the marketplace currency (incl. buyer protection fee). Leave empty for no maximum.

## `yearMin` (type: `integer`):

Only include bikes from this model year or newer. Leave empty for no lower year limit.

## `yearMax` (type: `integer`):

Only include bikes from this model year or older. Leave empty for no upper year limit.

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

Filter by buycycle condition grade (Fair → Brand new with guarantee). Leave empty for all conditions.

## `frameMaterials` (type: `array`):

Filter by frame material. Leave empty for all materials.

## `brakeTypes` (type: `array`):

Filter by brake type. Leave empty for all brake types.

## `shifts` (type: `array`):

Filter by shifting type. Electronic = Di2/eTap/EPS; Mechanical = cable. Leave empty for all.

## `isFrameset` (type: `string`):

Leave empty to include both. Pick a value to limit to one type.

## `isMotor` (type: `string`):

Leave empty to include both. Pick a value to limit to one type.

## `sellerType` (type: `array`):

Filter by seller type (private individual or shop/dealer). Leave empty for both.

## `highDemandOnly` (type: `boolean`):

Return only listings with buycycle's 'High demand' badge. Default off.

## `maxPages` (type: `integer`):

Safety cap on pagination; ~50 bikes per page. Default 2 (max 50).

## `returnOnly` (type: `string`):

Curates the main Output dataset. Full crawl always saved to Storage → 'full-results'. Default all.

## `minDiscountPct` (type: `integer`):

Active when Highlights filter = 'Discounted bikes'. Minimum discount off MSRP. Default 20%.

## `minWishlistCount` (type: `integer`):

Active when Highlights filter = 'Popular'. Minimum number of wishlists. Default 20.

## Actor input object example

```json
{
  "model": "canyon aeroad",
  "sortBy": "lowest-price",
  "country": "de",
  "locationScope": "continent",
  "brands": [],
  "frameSizes": [],
  "conditions": [],
  "frameMaterials": [],
  "brakeTypes": [],
  "shifts": [],
  "sellerType": [],
  "highDemandOnly": false,
  "maxPages": 2,
  "returnOnly": "all",
  "minDiscountPct": 20,
  "minWishlistCount": 20
}
```

# Actor output Schema

## `summary` (type: `string`):

The formatted run summary rendered right here — curated highlights, deal scores, and new-listing alerts.

## `results` (type: `string`):

One row per listing found — export to CSV, JSON or Excel from the Console.

# 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 = {
    "model": "canyon aeroad",
    "country": "de",
    "locationScope": "continent"
};

// Run the Actor and wait for it to finish
const run = await client.actor("inovaflow/buycycle-hunter-pw").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 = {
    "model": "canyon aeroad",
    "country": "de",
    "locationScope": "continent",
}

# Run the Actor and wait for it to finish
run = client.actor("inovaflow/buycycle-hunter-pw").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 '{
  "model": "canyon aeroad",
  "country": "de",
  "locationScope": "continent"
}' |
apify call inovaflow/buycycle-hunter-pw --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,inovaflow/buycycle-hunter-pw"
        }
    }
}

```

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/RNflPa8ERCSgbqzv3/builds/uubc4lIjFfqwKv2ui/openapi.json
