# Catena.ro Scraper — Romanian Pharmacy Prices & Offers (`studio-amba/catena-ro-scraper`) Actor

Scrape promotional product prices from catena.ro, Romania's largest pharmacy chain. Extract names, brands, discounted and original prices, categories, and images from Catena's current campaigns.

- **URL**: https://apify.com/studio-amba/catena-ro-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.

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

## Catena.ro Scraper

Scrape promotional product prices from [catena.ro](https://www.catena.ro), Romania's largest pharmacy chain by revenue. Extracts product name, brand, discounted and original price, discount percentage, category, image, and description from Catena's live seasonal campaigns.

### Why use this actor?

Catena is the biggest pharmacy chain in Romania, with hundreds of stores nationwide. Price monitoring tools, deal aggregators, and market research teams tracking the Romanian pharmacy and cosmetics/dermocosmetics retail market can use this actor to pull structured, up-to-date pricing data without manually browsing Catena's site.

### Important: how pricing works on catena.ro

Catena.ro does **not** operate as a normal online store. Most product pages show "*Pentru pret te asteptam in cea mai apropiata farmacie Catena*" ("For the price, we're waiting for you at your nearest Catena pharmacy") instead of a checkout price — Romanian pharmacy retail commonly keeps final pricing in-store rather than online.

The one place catena.ro **does** publish real numeric prices is on its seasonal promotional campaign pages (`catena.ro/oferte/{campaign}`), for example:

```
-40% Preț întreg: 105.40 Lei
Preț redus: 63.24 Lei
```

This actor automatically discovers the currently live campaigns from the [Catena offers hub](https://www.catena.ro/oferte) and scrapes every product that has a numeric discounted price attached. Products that only carry a quantity promo (e.g. "Plătești 2, primești 3" — buy 2 get 3) with no per-unit price are skipped, since they have no price to report.

### How to scrape Catena.ro data

1. Open the actor and leave `searchQuery` empty to pull every currently discounted product across all live campaigns, or set it to a keyword (brand or product type) to filter results — for example `avene`, `vichy`, `bioderma`, or `crema`.
2. Set `maxResults` to the number of products you want (default 100).
3. Keep `includeProductDetails` on (default) so each product's own page is fetched for its canonical brand name and full category breadcrumb.
4. Run the actor. Results appear in the default dataset, one row per product, ready to export as JSON, CSV, or Excel.
5. For a narrower run, pass specific `catena.ro/oferte/{campaign}` URLs via `offerUrls` instead of auto-discovery.

Because Catena's campaigns rotate with the season, re-run the actor periodically to catch new promotions and price changes.

### Input

| Field | Type | Required | Description |
|-------|------|----------|--------------|
| `searchQuery` | String | No | Filter products by keyword matched against the product name (e.g. a brand like `avene`) |
| `offerUrls` | Array | No | Specific `catena.ro/oferte/{campaign}` URLs to scrape instead of auto-discovering current campaigns |
| `maxResults` | Integer | No | Maximum number of products to scrape (default: 100) |
| `includeProductDetails` | Boolean | No | Fetch each product's own page for canonical brand + category breadcrumb (default: true) |
| `proxyConfiguration` | Object | No | Apify proxy configuration. **RESIDENTIAL is required** — catena.ro serves a stripped page with no products to Apify's shared datacenter proxy pool |

### Output

Each result contains:

| Field | Type | Example |
|-------|------|---------|
| `name` | String | `"Cleanance gel de curatare ten acneic, 200 ml, Avene"` |
| `brand` | String | `"Avene"` |
| `price` | Number | `63.24` |
| `originalPrice` | Number | `105.40` |
| `currency` | String | `"RON"` |
| `discount` | String | `"-40%"` |
| `url` | String | Full product page URL |
| `imageUrl` | String | Primary product image URL |
| `category` | String | `"Acnee > Curatare ten"` |
| `itemDescription` | String | Product description text |
| `campaign` | String | Name of the promotional campaign the product was found in |
| `scrapedAt` | String | ISO 8601 timestamp |

### Example output

```json
{
    "name": "Cleanance gel de curatare ten acneic, 200 ml, Avene",
    "brand": "Avene",
    "price": 63.24,
    "originalPrice": 105.4,
    "currency": "RON",
    "discount": "-40%",
    "url": "https://www.catena.ro/cleanance-gel-de-curatare-ten-acneic-200-ml-avene",
    "imageUrl": "https://www.catena.ro/assets/uploads/product_images/thumbs/3163a-328770139204-cleanance-gel-curatare-200ml_183x144.jpg",
    "category": "Acnee > Curatare ten",
    "itemDescription": "Un gel de curatare purificator, usor spumant, pentru pielea grasa si/sau predispusa la acnee.",
    "campaign": "Campania Frumusetii la Catena - reduceri de pana la 40% la cosmetice si dermatocosmetice",
    "scrapedAt": "2026-08-01T09:29:01.574Z"
}
```

### Cost estimate

This actor uses lightweight HTTP requests (Cheerio, no browser rendering) against a plain server-rendered site. A run of 100 products with `includeProductDetails` on uses roughly 110–120 requests total (one campaign listing page plus one detail page per product) and typically completes in under two minutes on the default 1 memory unit. No paid third-party services (e.g. Bright Data) are required — Apify's RESIDENTIAL proxy group is sufficient.

### Limitations

- Catena.ro only publishes numeric prices on its seasonal promotional campaigns, not across its full catalogue. This actor reports exactly the products Catena prices online — it does not estimate or infer prices for reservation-only products.
- Campaigns rotate throughout the year, so the exact set of available products and brands changes over time. Re-run the actor to pick up the current campaigns.
- EAN/barcode is not exposed anywhere on catena.ro's public pages and is therefore not included in the output.
- Product availability by individual pharmacy location is not covered by this actor — that requires Catena's separate "find in pharmacy" locator flow.

### Legal

This actor only accesses publicly available data. It does not bypass any login, paywall, or access control. Use responsibly and in accordance with catena.ro's terms of service.

### Related Scrapers

- [Aponeo Scraper](https://apify.com/studio-amba/aponeo-scraper) — German online pharmacy products and prices
- [Newpharma Scraper](https://apify.com/studio-amba/newpharma-scraper) — Belgian online pharmacy products and prices
- [Farmacia Tei Scraper](https://apify.com/studio-amba/farmacia-tei-scraper) — Romanian pharmacy chain products and prices
- [DocMorris Scraper](https://apify.com/studio-amba/docmorris-scraper) — European online pharmacy products and prices
- [Dr. Max Scraper](https://apify.com/studio-amba/drmax-scraper) — Central European pharmacy chain products and prices

### FAQ

**Does this actor need a login or Catena account?**
No. It only reads publicly visible campaign pages.

**Can it scrape the full Catena catalogue, including non-discounted products?**
No — catena.ro simply does not publish a price for most of its catalogue online (see "Important: how pricing works" above). This actor scrapes every product that does carry a real, published price.

**How often do the campaigns change?**
Catena runs several seasonal campaigns in parallel and refreshes them periodically. Schedule this actor to run daily or weekly to keep pricing data current.

# Actor input Schema

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

Filter products by keyword (matched against the product name, e.g. a brand or product type). Leave empty to scrape all current promotional offers.

## `offerUrls` (type: `array`):

Specific catena.ro/oferte/{campaign} URLs to scrape instead of auto-discovering the current campaigns from the offers hub. Most users should leave this empty.

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

Maximum number of products to scrape

## `includeProductDetails` (type: `boolean`):

Fetch each product's own page for the canonical brand name and full category breadcrumb (one extra request per product). Recommended: on.

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

Apify proxy configuration. Catena.ro serves a stripped-down page with no products to Apify's shared datacenter proxy pool, so RESIDENTIAL is required.

## Actor input object example

```json
{
  "searchQuery": "avene",
  "maxResults": 5,
  "includeProductDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "RO"
  }
}
```

# 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": "avene",
    "maxResults": 5,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "RO"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/catena-ro-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": "avene",
    "maxResults": 5,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "RO",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/catena-ro-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 '{
  "searchQuery": "avene",
  "maxResults": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "RO"
  }
}' |
apify call studio-amba/catena-ro-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/catena-ro-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/foDGIVOP1PtArgZEQ/builds/q5gmnop6tcFdgtlHM/openapi.json
