# Fahrradkenner.de Bike Shop Reviews Scraper (`rainminer/fahrradkenner-de-scraper`) Actor

Extract verified Fahrradkenner.de customer reviews for German bike shops: star ratings, review text, service categories, trust badges, and dealer scores. Paste a location URL — no login, no coding. Export JSON/CSV, schedule runs, and pull Fahrradkenner Bewertungen via the Apify API.

- **URL**: https://apify.com/rainminer/fahrradkenner-de-scraper.md
- **Developed by:** [rainminer](https://apify.com/rainminer) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 2 total users, 2 monthly users, 90.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.49 / 1,000 reviews

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

![Fahrradkenner.de](https://www.fahrradkenner.de/favicon.ico)

### What does Fahrradkenner.de Reviews Scraper do?

**Fahrradkenner.de Reviews Scraper** extracts **verified customer reviews and trust ratings** for German bike shops from [Fahrradkenner.de](https://www.fahrradkenner.de/) — the industry portal for Radhändler reputation with 500,000+ customer voices. Paste a dealer location URL (for example `https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig`) and get structured review data without coding.

This Fahrradkenner API-style export is built for agencies, OEMs, and marketplace operators who need **Fahrradkenner Bewertungen** (bike-shop reviews) in JSON or CSV, not a screenshot of the public profile.

### What can this Fahrradkenner scraper do?

- Scrape **location profile reviews** from `/location/{slug}` pages (and `/ratings` pagination)
- Extract **star rating, review text, service category, reviewer name, and trust badges**
- Keep the portal's **newest-first order** via `reviewPosition`, plus `scrapedAt` and the shop's `reviewsSince` bound (Fahrradkenner publishes no per-review date)
- Attach **dealer name, city, address, phone, website, logo, and review counts** — Fahrradkenner's own (`verifiedReviewCount`) split from totals imported from Google, Facebook, or Trusted Shops (`externalRatings`)
- Cap results with **maxItems per start URL** (not a global crawl limit)
- Run on the **Apify platform**: scheduling, monitoring, dataset export, webhooks, and API access
- Work **without a login** and **without a proxy by default** (HTTP crawler, no browser)

### Why scrape Fahrradkenner.de reviews?

Use cases teams actually run:

1. **Dealer reputation monitoring** — Track Werkstatt vs Radkauf sentiment for local bike shops.
2. **OEM partner scorecards** — Compare Fahrradkenner ratings across authorized dealers in a region.
3. **Marketplace due diligence** — Vet a Radhändler before listing or onboarding.
4. **Agency reporting** — Feed verified reviews into monthly client dashboards.
5. **Competitive research** — See which shops in Bonn, Köln, München, or Hamburg lead on volume and stars.
6. **Service-quality analytics** — Slice comments by service category (workshop vs bike purchase).
7. **Trust-factor audits** — Count ID, regular-customer, and fairplay badges over time.
8. **Lead enrichment** — Attach public review stats and contact fields to a dealer CRM row.
9. **Alerting** — Schedule daily runs and flag rating drops or new low-star reviews.
10. **SEO / local content** — Research what customers praise or complain about in a city.
11. **M\&A / network expansion** — Screen multi-store groups by aggregate review count.
12. **Python / no-code pipelines** — Pull Fahrradkenner data via Apify API, then export Excel.

### What data can you extract from Fahrradkenner.de?

| Field | Description |
| --- | --- |
| reviewId | Unique review identifier |
| reviewDate | Review publication date (ISO 8601). `null` — Fahrradkenner does not publish per-review dates |
| reviewPosition | 1-based rank in Fahrradkenner's newest-first review order (1 = newest review on the profile) |
| scrapedAt | ISO 8601 timestamp of when this run read the review |
| locationName | Bike shop / dealer name |
| city | City from the location profile |
| reviewerName | Reviewer display name (when shown) |
| rating | Star rating (1–5) |
| text | Review body |
| serviceCategory | Service type (e.g. Werkstatt, Radkauf) |
| trustFactors | Verified trust badges (ID, reference, regular customer, fairplay, social login) |
| reviewUrl | Direct link to the review on Fahrradkenner |
| imageUrl / locationImageUrl | Dealer logo from the location profile (reviews have no photos) |
| aggregateRating | Headline score next to the shop name — blended across Fahrradkenner **and** the shop's other review sources |
| aggregateReviewCount | Headline review count — Fahrradkenner reviews **plus** reviews imported from other sources. Not the number of reviews you can scrape |
| verifiedRating | Fahrradkenner's own score from the rating seal ("Gesamtbewertung") |
| verifiedReviewCount | Number of Fahrradkenner reviews published individually — this is what the Actor can return |
| externalReviewCount | Reviews counted in the aggregate but held at another portal ("ohne Vertrauensfaktoren") |
| externalRatings | Per-source score and count, e.g. `[{ "source": "Google", "rating": 4.3, "reviewCount": 1183 }]` |
| reviewsSince | Date the shop started collecting Fahrradkenner reviews ("Bewertungen seit", ISO 8601) — the earliest possible date for any review of this shop |
| profileUrl | Fahrradkenner location page URL |

### Why a shop page shows more reviews than the Actor returns

The big number next to the shop name is **not** the number of reviews Fahrradkenner publishes. It adds the shop's own Fahrradkenner reviews to review **totals imported from other portals**, which the site shows only as a score and a count per source — never as individual reviews. Take [Bike Market, Rostock](https://fahrradkenner.de/location/rostock-bike-market):

| Number on the page | Field | Meaning |
| --- | --- | --- |
| 1779 Bewertungen | `aggregateReviewCount` | Headline total (209 + 1570) |
| 209 Bewertungen seit 27.10.2023 | `verifiedReviewCount` | Fahrradkenner reviews, listed one by one — **scrapeable** |
| 1570 Bewertungen ohne Vertrauensfaktoren | `externalReviewCount` | Google 1183 + facebook 13 + Trustedshops 374 — counts only |

So a full run of that shop returns ~209 reviews, not 1779, and the run log says so up front:

```
Bike Market , Rostock lists 209 Fahrradkenner review(s) that can be scraped individually.
A further 1570 review(s) come from Google, facebook, Trustedshops. Fahrradkenner publishes
only their score and count, so they are part of aggregateReviewCount (1779) but cannot be scraped.
```

Compare your item count against `verifiedReviewCount`, not `aggregateReviewCount`. It can land one or two short: Fahrradkenner occasionally repeats a review on two pagination pages, and the Actor drops the repeat rather than emitting a duplicate row. The run log names how many it skipped, and because `reviewPosition` mirrors the portal's listing slots, the skipped slot shows up as a gap in the numbering (the Rostock run returns 208 rows numbered 1–209, missing 16).

Some shop pages carry a headline count with nothing behind it at all — no Fahrradkenner reviews of their own, only imported ones. A run on such a shop returns zero rows and logs a warning naming the headline count, rather than finishing silently.

### How review dates work on Fahrradkenner

Fahrradkenner publishes **no date on a review**. There is no timestamp on the profile page, on `/ratings` pages, on the `?rating={id}` permalink, or in the page's structured data — the portal shows only reviewer, service category, stars, trust badges, and text. `reviewDate` is therefore `null` for every row, and the Actor never invents one. If Fahrradkenner starts rendering dates, `reviewDate` fills in automatically.

Three fields let you build a correct timeline anyway:

- **`reviewPosition`** — Fahrradkenner lists reviews newest-first ("Letzte Einzelbewertungen"). Position 1 is the newest review, so sorting by `reviewPosition` ascending gives you the true newest → oldest order within a run.
- **`scrapedAt`** — when the run saw the review. It is an **upper bound** on the real publication date.
- **`reviewsSince`** — the shop's "Bewertungen seit" date. It is a **lower bound** for every review of that shop.

If your database requires a non-null date column, map it explicitly instead of silently using import time:

```sql
-- honest fill: real date when the portal has one, observation time otherwise
review_posted_at = COALESCE(review_date, scraped_at)
-- and keep the ordering the portal actually guarantees
ORDER BY review_position ASC
```

`reviewsSince` lives on the shop profile page, so it is `null` only when you start a run directly on a deep `/ratings?page=N` URL. Start from `/location/{slug}` (or `/location/{slug}/ratings`) to always get it.

For dates close to reality, schedule the Actor **daily** with a small `maxItems`. New reviews appear at `reviewPosition` 1, so the first `scrapedAt` you record for a `reviewId` is within a day of its publication. `reviewPosition` is only comparable within a single snapshot — new reviews push older ones down — so store it per run alongside `scrapedAt`.

### How to scrape Fahrradkenner.de reviews

1. Open **Fahrradkenner.de Reviews Scraper** in Apify Console.
2. Add one or more **Fahrradkenner location URLs** under **Start URLs**.
3. Set **Maximum items** (reviews per URL). Keep it small for a test run.
4. Leave proxy off unless your network blocks the site.
5. Run the Actor and download results from the dataset tab (JSON, CSV, Excel, or HTML).

### Input

Fahrradkenner.de Reviews Scraper accepts **Start URLs**, **maxItems** (per start URL), and optional **proxy configuration**. See the **Input** tab in Apify Console for details.

Supported URLs:

- Location profile: `https://fahrradkenner.de/location/{slug}`
- Ratings pages: `https://fahrradkenner.de/location/{slug}/ratings?page=2`

The scraper follows paginated review listings automatically until `maxItems` is reached.

### Output example

```json
{
  "reviewId": "870af149478c16e60881",
  "reviewDate": null,
  "reviewPosition": 3,
  "scrapedAt": "2026-09-22T06:12:41.118Z",
  "locationName": "Radladen Hoenig & Röhrig , Bonn",
  "city": "Bonn",
  "reviewerName": null,
  "rating": 4,
  "text": "Außer der vereinbarten Zeit war alles ok.",
  "serviceCategory": "Werkstatt",
  "trustFactors": {
    "identification": false,
    "referenceNumber": false,
    "regularCustomer": true,
    "fairplay": false,
    "socialLogin": false
  },
  "reviewUrl": "https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig?rating=870af149478c16e60881#870af149478c16e60881",
  "locationImageUrl": "https://fahrradkenner.de/storage/media/images/809fa6d5-a10d-4224-9364-717ffdd90e98/604612.jpeg",
  "imageUrl": "https://fahrradkenner.de/storage/media/images/809fa6d5-a10d-4224-9364-717ffdd90e98/604612.jpeg",
  "aggregateRating": 4.8,
  "aggregateReviewCount": 1592,
  "verifiedRating": 4.8,
  "verifiedReviewCount": 816,
  "externalReviewCount": 776,
  "externalRatings": [
    { "source": "Google", "rating": 4.8, "reviewCount": 761 },
    { "source": "facebook", "rating": 4.6, "reviewCount": 15 }
  ],
  "reviewsSince": "2019-03-07T12:00:00.000Z",
  "profileUrl": "https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig"
}
```

You can download the dataset in JSON, CSV, Excel, or HTML.

### How much does scraping Fahrradkenner.de cost?

This Actor uses an HTTP crawler (no browser) and **no proxy by default**, keeping compute usage low.

You pay a **per-review** Store fee (see the Actor **Pricing** tab). Platform compute is included at the default HTTP / no-proxy settings — a short test with 5 reviews per URL usually finishes in under a minute.

### FAQ

**Is scraping Fahrradkenner.de legal?**\
Our scrapers collect only **public** review content shown on Fahrradkenner pages. You are responsible for complying with applicable laws (including GDPR) when processing personal data in reviews.

**Which URLs are supported?**\
Bike shop location pages under `/location/{slug}` — for example `/location/bonn-radladen-hoenig-rohrig`. The scraper follows paginated review listings automatically.

**Do I need the official Fahrradkenner API?**\
No. This Actor is a no-code Fahrradkenner data extractor. Paste public location URLs and export structured reviews.

**Are reviewer names always present?**\
No. Many Fahrradkenner reviews are published without a display name. Those rows still include rating, text, and trust factors.

**Does every review have a photo?**\
No. Reviews on Fahrradkenner typically have no customer photos. `imageUrl` is the **dealer logo** from the location profile.

**The shop page says 1779 reviews — why did I get 209?**\
Because 1570 of those are counted from Google, Facebook, or Trusted Shops and are never published individually on Fahrradkenner. Use `verifiedReviewCount` as the target for a full run — see [Why a shop page shows more reviews than the Actor returns](#why-a-shop-page-shows-more-reviews-than-the-actor-returns).

**Do Fahrradkenner reviews have a date?**\
No. The portal publishes no per-review date, so `reviewDate` is `null`. Use `reviewPosition` (newest-first rank), `scrapedAt` (upper bound), and `reviewsSince` (lower bound) instead — see [How review dates work on Fahrradkenner](#how-review-dates-work-on-fahrradkenner).

**How do I scrape Fahrradkenner reviews with Python?**\
Run the Actor from Apify Console or call it via the Apify API / `apify-client`. Schedule recurring exports for dealer monitoring.

Related rainminer review Actors: [Shopauskunft.de Reviews Scraper](https://apify.com/rainminer/shopauskunft-de-scraper), [eKomi.de Reviews Scraper](https://apify.com/rainminer/ekomi-de-scraper), [ShopVote.de Reviews Scraper](https://apify.com/rainminer/shopvote-de-scraper).

### Image Credit

Image credit: [fahrradkenner.de](https://www.fahrradkenner.de/)

# Actor input Schema

## `startUrls` (type: `array`):

Fahrradkenner.de bike shop location URLs (e.g. https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig).

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

Maximum number of reviews to return per start URL.

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

Proxy settings. The scraper works without a proxy in most regions.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig"
    }
  ],
  "maxItems": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (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 = {
    "startUrls": [
        {
            "url": "https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("rainminer/fahrradkenner-de-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 = {
    "startUrls": [{ "url": "https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig" }],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("rainminer/fahrradkenner-de-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 '{
  "startUrls": [
    {
      "url": "https://fahrradkenner.de/location/bonn-radladen-hoenig-rohrig"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call rainminer/fahrradkenner-de-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rainminer/fahrradkenner-de-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/fbK6ZJjr8BSDdZzKZ/builds/4De18ZxPzzEvpR22g/openapi.json
