# Marjane Mall Scraper (`badr_xba/marjane-mall-scraper`) Actor

All Marjane Mall products from Morocco's official sitemaps: name, brand, price, previous price, discount, stock, seller, categories, specs and images. Prices are compared between runs, so a daily schedule reports only what moved. Example: leave the input empty for a 1,000-product sample.

- **URL**: https://apify.com/badr\_xba/marjane-mall-scraper.md
- **Developed by:** [Badr Bouargan](https://apify.com/badr_xba) (community)
- **Categories:** E-commerce
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.75 / 1,000 results

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

## Marjane Mall Scraper – All Products & Prices

![Marjane Mall Scraper](https://api.apify.com/v2/key-value-stores/paDGjcmD1ZMsRJLZS/records/marjane-banner.png?signature=N7cbAs1G6n1mkKiTpjJu)

Extract **the entire catalog of [Marjane Mall](https://www.marjanemall.ma)**, Morocco's hypermarket marketplace — prices, promotions, stock, brands, sellers, categories, images and specifications — with **price tracking between runs** and optional e-mail alerts.

### Why this Actor

- **Complete catalog**: reads Marjane Mall's official product sitemaps, around 380,000 product pages.
- **Rich product data**: price, regular price, discount %, stock status and quantity, brand, seller (Marjane or a marketplace partner), full category path, images, specifications, short and long description.
- **Price tracking**: previous price, change in value and percent, new products, stock changes — remembered from one run to the next.
- **Respectful crawling**: follows `robots.txt`, identified bot, only sitemaps and product pages, never `/api/`, cart or account pages, limited speed.

### What you can do with it

- **Follow Moroccan retail prices**: around 380,000 product pages, refreshed as often as you like.
- **Catch promotions the day they start**: price, regular price and discount percent on every row.
- **Compare marketplace sellers**: Marjane's own listings against its partner sellers.
- **Watch a single department**: filter on *Category contains* for électroménager, informatique or any other.
- **Feed a price-comparison product**: images, brand, stock quantity, full category path and specifications.

### How it works

1. The Actor downloads the public sitemaps and builds the list of product pages.
2. Each page is parsed from its structured data, so a redesign of the site does not silently break the output.
3. Prices are compared with the previous run through a named key-value store that survives runs.
4. Filters are applied before saving, so you pay only for the rows you want.

### Step-by-step tutorial

1. Set **Max products** — `0` means the whole catalog. Start with `1000`.
2. Optionally add **Filters**: price range, minimum discount, in stock only, category contains, name contains, excluded words.
3. Keep the default **Proxy** setting (residential, Morocco — see the FAQ).
4. Press **Start**, then export as Excel, CSV or JSON.

#### Daily price monitoring

Switch on *Only changed products* and *E-mail alerts*, then create an Apify **Schedule**. Keep the same *Max products* value on each run so the comparison stays consistent.

### Input example

```json
{
  "maxItems": 1000,
  "minDiscountPercent": 15,
  "onlyInStock": true,
  "categoryKeywords": ["électroménager"],
  "trackPriceChanges": true,
  "onlyChangedProducts": false
}
```

### Output example

![Sample output](https://api.apify.com/v2/key-value-stores/paDGjcmD1ZMsRJLZS/records/marjane-output.png?signature=WGvQWsMJbNyjYbNyt8oz)

Every row as JSON:

```json
{
  "sku": "AAAAA32198",
  "gtin": "6111234567890",
  "name": "Tapis receveur de douche antidérapant blanc",
  "url": "https://www.marjanemall.ma/p/tapis-receveur-de-douche-anti-derapant-blanc-aaaaa32198",
  "price": 87,
  "regularPrice": 113,
  "discountPercent": 23,
  "currency": "MAD",
  "inStock": true,
  "seller": { "id": "700058", "name": "MARJANEMALL" },
  "categories": ["Maison", "Salle de bain"],
  "previousPrice": 99,
  "priceChangePercent": -12.1
}
```

### Pricing

Pay per product returned, shown on the Actor's pricing tab; proxy and compute are included. This Actor uses a residential proxy because Marjane Mall blocks datacenter addresses, which makes it more expensive to run than a plain sitemap crawler — the price reflects that, and there is nothing extra to pay on your side.

### FAQ

**Can I get the whole catalog?** Yes — set *Max products* to `0`. Roughly 380,000 pages exist, so run a smaller job first to size the dataset and the duration.

**Why a residential proxy?** Marjane Mall refuses datacenter IP addresses. The default setting already selects the right group; changing it usually results in empty runs.

**How does price tracking work?** Each product's last price is stored under its SKU. On the next run you get `previousPrice`, `priceChange`, `priceChangePercent`, plus flags for new products and stock changes.

**Why did an e-mail alert not arrive?** Actors started from Apify Store run with limited permissions and cannot send mail on your behalf. Copy the Actor into your account and switch to full permissions, or plug in a Slack, webhook or Zapier integration. The changed products are always in the dataset.

**Can I follow only one category?** Yes — use *Category contains*, for example `électroménager` or `informatique`.

### Integrations

- **Schedules**: a daily run with *Only changed products* becomes a promotions feed.
- **API**: JSON, CSV or Excel exports for every run.
- **Webhooks**: trigger your pricing tool as soon as new data lands.
- **No-code tools**: Google Sheets, Slack, Zapier and Make from the Integrations tab.

### Support

Open an issue on the Actor's **Issues** tab: bugs, missing fields, or a filter you need.

**Did this Actor do the job?** Leaving a short review on its Store page takes a minute and helps other people find it — and tells me which feature to build next.

### Legal

This Actor reads **public** product pages and sitemaps, respects `robots.txt`, identifies itself honestly and limits its request rate. It collects product data, not personal data. How you reuse prices and product information is your responsibility.

### En français

Extrait **tout le catalogue de Marjane Mall** : prix, promotions, stock, marques, vendeurs, catégories, images, caractéristiques. L'Actor lit les sitemaps officiels (environ 380 000 pages produit), respecte le `robots.txt`, se présente sous une identité de robot honnête et limite sa vitesse. Il mémorise les prix d'un run à l'autre, signale les baisses, les retours en stock et les nouveautés, et peut vous alerter par e-mail. Filtres : prix, remise minimum, en stock uniquement, mots-clés de catégorie ou de nom, exclusions.

# Actor input Schema

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

Nombre de fiches produit à visiter. Mettez 0 pour tout le catalogue (~380 000 fiches, environ 2 jours à 120 requêtes/minute). Commencez petit pour tester.

## `minPrice` (type: `integer`):

Ne garder que les produits à ce prix ou plus (dans la devise du site).

## `maxPrice` (type: `integer`):

Ne garder que les produits à ce prix ou moins.

## `minDiscountPercent` (type: `integer`):

Ne garder que les produits en promotion d'au moins ce pourcentage (ex. 30).

## `onlyInStock` (type: `boolean`):

Exclure les produits en rupture de stock.

## `categoryKeywords` (type: `array`):

Garder les produits dont une catégorie contient un de ces mots (ex. téléphone, électroménager). Accents et majuscules ignorés.

## `nameKeywords` (type: `array`):

Garder les produits dont le nom contient un de ces mots (ex. samsung, iphone).

## `excludeKeywords` (type: `array`):

Exclure les produits dont le nom contient un de ces mots (ex. coque, reconditionné).

## `trackPriceChanges` (type: `boolean`):

Mémorise le prix et le stock de chaque produit pour les comparer au run suivant : ancien prix, variation, nouveaux produits, changement de stock.

## `onlyChangedProducts` (type: `boolean`):

N'enregistrer que les nouveaux produits et ceux dont le prix ou le stock a changé depuis le dernier run. Idéal avec un run programmé chaque jour.

## `sendEmailAlerts` (type: `boolean`):

À la fin du run, envoie un récapitulatif des changements à l'adresse e-mail de votre compte Apify. ⚠ Limite d'Apify : un Actor lancé depuis l'Apify Store tourne en « Limited permissions » et n'a pas le droit d'envoyer d'e-mails — l'envoi échouera et le run le dira dans son journal. Les changements restent de toute façon dans les résultats (champs priceChange, priceChangePercent, stockChanged, isNewProduct). Pour vraiment recevoir les e-mails, copiez cet Actor dans votre compte et passez-le en permissions complètes, ou branchez une intégration Apify (Slack, webhook, Zapier).

## `alertMinPriceDropPercent` (type: `integer`):

Signaler les produits dont le prix a baissé d'au moins ce pourcentage depuis le dernier run.

## `alertBackInStock` (type: `boolean`):

Signaler les produits qui étaient en rupture et sont de nouveau disponibles.

## `alertNewProducts` (type: `boolean`):

Signaler aussi les produits jamais vus. Attention : au premier run, tous les produits sont nouveaux.

## `botContact` (type: `string`):

E-mail ou URL permettant à Marjane Mall de vous contacter (recommandé). Il est ajouté au User-Agent du robot. Si vous laissez vide, l'adresse de l'Actor sur Apify est utilisée.

## `maxRequestsPerMinute` (type: `integer`):

Vitesse maximale (1 requête ≈ 1 produit). Restez raisonnable pour ne pas surcharger le site ; plafonnée à 200.

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

Marjane Mall n'est accessible que depuis certains pays (dont le Maroc) et refuse les serveurs Apify : gardez le proxy RESIDENTIAL avec le pays Maroc. En local depuis le Maroc, vous pouvez le désactiver.

## Actor input object example

```json
{
  "maxItems": 300,
  "onlyInStock": false,
  "trackPriceChanges": true,
  "onlyChangedProducts": false,
  "sendEmailAlerts": false,
  "alertMinPriceDropPercent": 10,
  "alertBackInStock": true,
  "alertNewProducts": false,
  "maxRequestsPerMinute": 120,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "MA"
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Tableau des produits avec image, prix, remise, stock, marque, vendeur et lien.

## `allFields` (type: `string`):

Données complètes de chaque produit, y compris description, caractéristiques et images.

# 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 = {
    "maxItems": 300,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "MA"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("badr_xba/marjane-mall-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 = {
    "maxItems": 300,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "MA",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("badr_xba/marjane-mall-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 '{
  "maxItems": 300,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "MA"
  }
}' |
apify call badr_xba/marjane-mall-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,badr_xba/marjane-mall-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/OuacAGn6PtcYat6cb/builds/1e79r9cNi4D4VCSDI/openapi.json
