# German Pharmacy PZN Price Comparison (`truenorth/german-pharmacy-pzn-monitor`) Actor

Compare Shop Apotheke and DocMorris by PZN or keyword in one normalized dataset with EUR prices, availability, EAN, and product URLs.

- **URL**: https://apify.com/truenorth/german-pharmacy-pzn-monitor.md
- **Developed by:** [TrueNorth](https://apify.com/truenorth) (community)
- **Categories:** E-commerce
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 1,000 pharmacy price snapshots

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.

- **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

## German Pharmacy PZN Price Comparison

Compare current Shop Apotheke and DocMorris offers from one input and receive one normalized Apify dataset. Search by German Pharmazentralnummer (PZN) or keyword; every result uses the same 13-field contract for EUR price, list price, savings, availability, pack size, brand, manufacturer, European Article Number (EAN), and product URL.

Use this Actor for German pharmacy PZN price comparison, a PZN scraper, a German pharmacy price monitor, a Shop Apotheke scraper, a DocMorris scraper, pharmacy availability data, or a German medicine price dataset by PZN. Use exact PZN or keyword input to monitor pharmacy stock by PZN and build a normalized pharmacy product dataset. It supports two pharmacies—not the full German pharmacy market—and produces current snapshots, not price history.

### Why use it?

- Compare two major German online pharmacies without joining different source schemas.
- Preserve eight-digit PZNs and leading zeroes as strings.
- Query 1–100 exact PZNs or keywords per run.
- Filter out-of-stock offers or retain them for availability monitoring.
- Export strict records to JSON, CSV, Excel, databases, and downstream Apify workflows.

### Input example

```json
{
  "searchTerms": ["03161577", "ibuprofen"],
  "pharmacies": ["shop-apotheke", "docmorris"],
  "maxItems": 1000,
  "includeOutOfStock": true
}
```

| Field | Required | Default | Meaning |
| --- | --- | --- | --- |
| `searchTerms` | Yes | — | 1–100 PZNs or keywords. Seven-digit PZNs are left-padded; eight-digit PZNs preserve leading zeroes. |
| `pharmacies` | No | Both | `shop-apotheke`, `docmorris`, or both. Execution order stays Shop Apotheke, then DocMorris. |
| `maxItems` | No | `1000` | Global unique-record cap from 1 to 10,000 across all terms and pharmacies. |
| `includeOutOfStock` | No | `true` | Keep or remove records currently marked out of stock. |

Other numeric lengths and all-zero PZNs fail validation. Duplicate normalized terms and duplicate pharmacy/PZN results are removed.

### Output example

```json
{
  "pharmacy": "DocMorris",
  "pzn": "03161577",
  "ean": null,
  "title": "IBUHEXAL AKUT 400 50 St",
  "brand": "IbuHEXAL",
  "manufacturer": "Hexal AG",
  "packSize": "50 St",
  "price": 6.49,
  "listPrice": 13.45,
  "savingsPercent": 52,
  "inStock": true,
  "url": "https://www.docmorris.de/ibuhexal-akut-400/03161577",
  "scrapedAt": "2026-07-24T20:31:40.000Z"
}
```

Each dataset item contains exactly `pharmacy`, `pzn`, `ean`, `title`, `brand`, `manufacturer`, `packSize`, `price`, `listPrice`, `savingsPercent`, `inStock`, `url`, and `scrapedAt`. Prices are numeric EUR values. Missing optional source values are explicit `null`. One UTC `scrapedAt` value is shared by every record in a run.

### Use cases

- Compare Shop Apotheke and DocMorris prices for known PZNs.
- Monitor German medicine prices and current stock on a schedule.
- Build procurement, catalog, assortment, or market-research datasets.
- Feed normalized pharmacy product data into analysis and business intelligence tools.

Useful German searches include PZN Preisvergleich, Apotheken Preisvergleich, Arzneimittel Preisvergleich, Medikamentenpreise vergleichen, Shop Apotheke Preisvergleich, and DocMorris Preisvergleich.

### Pricing

Pay-Per-Event (PPE): USD 3.00 per 1,000 price snapshot records through `per-1000-price-snapshots`. Apify platform usage costs are passed to users. Final run cost depends on output volume and platform resources.

### Reliability and limits

The Actor calls public Shop Apotheke and DocMorris Algolia search endpoints directly with Node.js—no browser. Requests use 10-second attempt timeouts and at most three attempts. Network failures and HTTP 408, 425, 429, 500, 502, 503, and 504 are retried. Blocks, non-JSON responses, malformed payloads, invalid envelopes, and upstream schema drift fail the complete run. Output is validated before dataset writes in batches of at most 500.

Shop Apotheke keyword responses can include marketplace master records without a 7- or 8-digit PZN. These records are counted and skipped because every output item requires a real PZN. Products that expose a malformed PZN still fail loudly, and exact-PZN searches retain strict validation.

The Actor does not order products, provide medical advice, compare shipping, cover every German pharmacy, or maintain historical prices. Product data can change after collection. It is not affiliated with, endorsed by, or sponsored by Shop Apotheke or DocMorris.

### Local development

Requires Node.js 22 and pnpm 10.13.1.

```sh
corepack enable
pnpm install --frozen-lockfile
pnpm run check
pnpm test
apify run
```

Live exact-PZN checks are opt-in:

```sh
pnpm run test:live
```

Private fixture mode requires `NODE_ENV=test`, `PZN_MONITOR_FIXTURE_DIR`, and `APIFY_IS_AT_HOME` not equal to `1`. Fixture mode is not public input and fails with `FIXTURE_MODE_FORBIDDEN` in Apify Cloud.

# Actor input Schema

## `searchTerms` (type: `array`):

Enter 1–100 PZNs or keywords. Keep PZNs as strings so leading zeroes are preserved.

## `pharmacies` (type: `array`):

Pharmacies to query. Execution order is always Shop Apotheke, then DocMorris.

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

Global maximum number of unique records across all terms and pharmacies.

## `includeOutOfStock` (type: `boolean`):

Include normalized records currently marked out of stock.

## Actor input object example

```json
{
  "pharmacies": [
    "shop-apotheke",
    "docmorris"
  ],
  "maxItems": 1000,
  "includeOutOfStock": true
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("truenorth/german-pharmacy-pzn-monitor").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("truenorth/german-pharmacy-pzn-monitor").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 '{}' |
apify call truenorth/german-pharmacy-pzn-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=truenorth/german-pharmacy-pzn-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/BGvLEkYvyqhorGhj6/builds/xclWg3oFt9QskpPcJ/openapi.json
