# Penny Scraper — German Grocery Weekly Offers & Prices (`studio-amba/penny-de-scraper`) Actor

Scrape weekly offer prices, discounts, unit prices and product images from penny.de, PENNY's German discount grocery chain (REWE Group). Browse by category or search by keyword. No login or cookies.

- **URL**: https://apify.com/studio-amba/penny-de-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result scrapeds

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/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Penny Scraper — German Grocery Weekly Offers & Prices

Scrape the weekly offer prices of [penny.de](https://www.penny.de), PENNY's German discount grocery chain (part of REWE Group). Get product names, current and original prices, discount percentages, unit prices and pack sizes as clean structured JSON. No login, no cookies, no browser automation.

Browse by category or search by keyword across the whole current week of offers. Built for price monitoring, discount tracking and grocery market research.

### What it does

PENNY does not run a full online shop — it publishes a weekly flyer of discounted and highlighted products by category (Top Angebote, Obst & Gemüse, Kühlregal, Fleisch & Wurst, and more). This actor reads penny.de's own offer API directly, so you get exactly the prices shown on the site: current price, the manufacturer's recommended price (UVP) or the previous own price (Streichpreis) when the item is discounted, the discount percentage, and the per-unit price ("Grundpreis").

- **Category browse** — pick one of PENNY's current-week offer categories (Top Angebote, Kühlregal, Fleisch & Wurst, Drogerie & Haushalt, …) and get every offer in it.
- **Keyword search** — pass a term (`kaffee`, `wurst`, `käse`) to search product names across every category in one run.
- **All categories** — leave both empty (or pick "All categories") to pull the entire current weekly flyer.

### Output

Each offer is one record:

```json
{
  "name": "KERRYGOLD Butter",
  "brand": "KERRYGOLD",
  "price": 1.79,
  "currency": "EUR",
  "originalPrice": 3.49,
  "discount": "-48%",
  "unit": "je 250 g",
  "pricePerUnit": "1 kg = 7.16",
  "priceRequiresApp": false,
  "sku": "ff592365-1ea2-4a4d-96d3-98690ed3e175",
  "category": "top-angebote",
  "url": "https://www.penny.de/angebote/top-angebote/kerrygold-butter",
  "imageUrl": "https://cdn.penny.de/dam/jcr:2c882cbe-6a01-4daf-9caa-1a23c1c3fb8d/6648720.png?impolicy=penny&imwidth=600",
  "inStock": true,
  "scrapedAt": "2026-07-26T14:20:53.719Z"
}
````

#### Fields

| Field | Description |
|-------|-------------|
| `name` | Product name |
| `brand` | Brand / manufacturer (derived from the product name) |
| `price` | Current offer price as a number |
| `currency` | Always `EUR` |
| `originalPrice` | UVP (recommended retail price) or previous own price, when shown |
| `discount` | Discount badge shown on the tile (e.g. `-48%`), or `null` |
| `unit` | Pack size / quantity (e.g. `je 250 g`, `je 1-kg-Schale`) |
| `pricePerUnit` | Base price per kg/l/piece (Grundpreis) |
| `priceRequiresApp` | `true` if the price only applies with the free PENNY app |
| `sku` | PENNY's internal product id |
| `category` | Offer category slug |
| `url` | Link to the offer detail page |
| `imageUrl` | Product image URL |
| `inStock` | Always `true` — offers are only listed while the store carries them |
| `scrapedAt` | ISO timestamp of the scrape |

### How to scrape Penny.de data

1. Open the actor and set a **Search Query** (for example `kaffee`) to search across every category — or leave it empty and pick a **Category** to browse one department.
2. Set **Max Results** to the number of offers you want.
3. Keep the default **Proxy Configuration** — penny.de has no anti-bot protection or geo lock.
4. Click **Start**. When the run finishes, download the dataset as JSON, CSV or Excel, or pull it from the API.

#### Input example — search by keyword

```json
{
  "searchQuery": "kaffee",
  "maxResults": 50
}
```

#### Input example — browse a category

```json
{
  "category": "kuehlregal",
  "maxResults": 100
}
```

#### Input example — full weekly flyer

```json
{
  "category": "",
  "maxResults": 500
}
```

Use `"category": ""` (the "All categories" option) to pull the complete current week of offers across every department in one run.

### Categories

| Slug | Department |
|------|-----------|
| `top-angebote` | Top Angebote (top offers) |
| `obst-und-gemuese` | Obst & Gemüse (fruit & veg) |
| `kuehlregal` | Kühlregal (chilled / dairy) |
| `suessigkeiten-und-snacks` | Süßigkeiten & Snacks |
| `fleisch-und-wurst` | Fleisch & Wurst (meat & cold cuts) |
| `butchers` | BUTCHER'S (fresh meat brand) |
| `weitere-angebote` | Weitere Angebote (more offers) |
| `drogerie-und-haushalt` | Drogerie & Haushalt (drugstore & household) |
| `getraenke` | Getränke (drinks) |
| `pflanzen-mo-sa` | Pflanzen (plants) |
| `dauerhaft-im-preis-gesenkt` | Dauerhaft im Preis gesenkt (permanently reduced) |

### Common use cases

- **Discount tracking** — monitor which PENNY products go on sale each week and by how much.
- **Price monitoring** — compare PENNY's weekly prices against EDEKA, ALDI, Lidl and other German grocers.
- **Unit-price comparison** — use the Grundpreis field to compare value across pack sizes and brands.
- **Market research** — build a week-over-week dataset of German discount-grocery pricing.

### Tips

- PENNY's offers rotate weekly (Monday–Saturday, with some categories on Thursday–Saturday or Friday–Saturday sub-periods). Run on a schedule to capture each new week.
- `priceRequiresApp: true` marks prices that only apply when paying with the PENNY app — worth keeping separate from walk-in prices in analysis.
- The `sku` field is PENNY's own product id and stays stable across weeks for the same product, which makes week-over-week price comparison possible.

### FAQ

**Does this need a login?**
No. The actor only reads publicly published offer data. No account, password or cookies are required.

**Is this the full PENNY assortment?**
No. PENNY does not run an online shop — this actor covers the weekly flyer of highlighted and discounted offers shown on penny.de, which is the same set of products and prices shown in the printed and in-app circular.

**Why is `originalPrice` sometimes missing?**
Not every offer has a reference price. Everyday "Aktion" items are listed at their normal price with no strike-through or UVP comparison — `originalPrice` and `discount` are `null` for those.

**Is this legal?**
The actor collects publicly available promotional pricing information. You are responsible for using the data in line with PENNY's terms and applicable law.

### Disclaimer

This actor is an independent tool and is not affiliated with, endorsed by, or connected to PENNY, REWE Group or penny.de. All product data belongs to its respective owners.

# Actor input Schema

## `searchQuery` (type: `string`):

Search for products by name across all offer categories (e.g., 'kaffee', 'wurst', 'käse'). When set, this searches across every category and the Category input below is ignored.

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

Browse one offer category instead of searching. Ignored if Search Query is set. Leave both empty to get this week's Top Angebote (top offers).

## `maxResults` (type: `integer`):

Maximum number of offers to return.

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

Proxy settings. penny.de has no anti-bot protection or geo lock, so the default Apify proxy works fine.

## Actor input object example

```json
{
  "searchQuery": "kaffee",
  "category": "top-angebote",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "searchQuery": "kaffee",
    "category": "top-angebote",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/penny-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 = {
    "searchQuery": "kaffee",
    "category": "top-angebote",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/penny-de-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQuery": "kaffee",
  "category": "top-angebote",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call studio-amba/penny-de-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=studio-amba/penny-de-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Penny Scraper — German Grocery Weekly Offers & Prices",
        "description": "Scrape weekly offer prices, discounts, unit prices and product images from penny.de, PENNY's German discount grocery chain (REWE Group). Browse by category or search by keyword. No login or cookies.",
        "version": "0.1",
        "x-build-id": "lnksutKJmphBexDc7"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/studio-amba~penny-de-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-studio-amba-penny-de-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/studio-amba~penny-de-scraper/runs": {
            "post": {
                "operationId": "runs-sync-studio-amba-penny-de-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/studio-amba~penny-de-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-studio-amba-penny-de-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQuery": {
                        "title": "Search Query",
                        "type": "string",
                        "description": "Search for products by name across all offer categories (e.g., 'kaffee', 'wurst', 'käse'). When set, this searches across every category and the Category input below is ignored."
                    },
                    "category": {
                        "title": "Category",
                        "enum": [
                            "",
                            "top-angebote",
                            "obst-und-gemuese",
                            "kuehlregal",
                            "suessigkeiten-und-snacks",
                            "fleisch-und-wurst",
                            "butchers",
                            "weitere-angebote",
                            "drogerie-und-haushalt",
                            "getraenke",
                            "pflanzen-mo-sa",
                            "dauerhaft-im-preis-gesenkt"
                        ],
                        "type": "string",
                        "description": "Browse one offer category instead of searching. Ignored if Search Query is set. Leave both empty to get this week's Top Angebote (top offers)."
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of offers to return.",
                        "default": 100
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Proxy settings. penny.de has no anti-bot protection or geo lock, so the default Apify proxy works fine."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
