# Almanea Saudi Products (`vixendata/almanea-saudi-products`) Actor

Extract public Saudi product identifiers, SAR prices, availability and Arabic specifications from Almanea. Verified bounded sitemap discovery.

- **URL**: https://apify.com/vixendata/almanea-saudi-products.md
- **Developed by:** [Vixendata](https://apify.com/vixendata) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 91.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 successfully parsed product rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Almanea Saudi Products

Private evaluation Actor for public Almanea Saudi product data. Arabic-first: exact source titles, brand and specifications are preserved. HTML `lang=en` is not treated as proof of English. Country SA identifies the storefront; SAR is required in the source offer.

### Input

Supply `productUrls` as an array of exact HTTPS www.almanea.sa product URLs, or set `discoverProducts: true`. There are no default product samples. Discovery works when URL keys are omitted or empty. It reads only the publicly verified `https://www.almanea.sa/best-sellers-c-7698-sitemap.xml`, not an unbounded sitemap index, CMS/category pages or protected APIs. Namespace-aware parsing ignores image URLs. The full-catalog index is not traversed.

Defaults: 5 products, 10 total requests, 4,000,000 sitemap bytes. Hard maxima: 100 products, 120 requests, 8,000,000 sitemap bytes. Robots has a 1 MB cap and product pages a 3 MB cap. Request budget includes redirects and robots. Sitemap discovery streams XML and closes the response as soon as the product cap is reached; it never builds a full sitemap tree. Concurrency is one, with at least one second between requests and any declared robots crawl delay or request-rate spacing. Protego 0.7.0 evaluates wildcard and end-anchor robots rules. Input errors fail before networking. See `smoke-direct.json` and `smoke-discovery.json` for tiny exact smoke inputs. Discovery deliberately selects the first valid URLs; it is a sample, not a complete catalog.

### Output

One row per unique requested product URL: title, brand, string SKU/GTIN/MPN, description, color, current SAR price, explicit ListPrice only, source availability, nullable inStock, images, source specifications, observed language, country and timestamp. Arabic titles yield `ar`; other titles yield `und`. No invented ratings, list prices, inventory counts or store-level stock. JSON-LD's first SAR offer is used when several offers exist; this does not enumerate variants. Missing fields remain null or empty. Images are linked, not fetched.

The default dataset contains only extracted products. Key-value store `OUTPUT` reports completed/partial/failed, requests, row count and errors. Empty extraction is failed, not successful; a fatal source stop preserves previous rows as partial. SDK execution fails the run when no products were extracted. Reaching a request/byte limit can leave partial output; raise limits only within your budget.

### Safety and limitations

Only strict same-host HTTPS product and verified sitemap URL shapes are fetched. No queries, credentials, alternate ports, account routes, proxies or login. Every redirected destination is checked before fetching and checked against cached robots. Robots must be readable and valid; fail closed otherwise. HTTP 401/403/429, detected challenges, unsafe redirects and oversized responses stop the source. No retries or bypass. Robots User-Agent is `AlmaneaPublicProductActor/0.1`.

Robots, sitemap and the included genuine sanitized Philips product fixture were verified 2026-10-07. Fixture SKU 150306202999023, GTIN 8720389003165, SAR229/current and SAR279/list. Prices and availability change. Products must unambiguously match the final URL or its SKU identifier, including after redirects. Only source Product JSON-LD is supported; website changes can yield a clear extraction failure. Indexed Store searches found no relevant competitor, but that is not exhaustive; willingness to pay is unvalidated. This Actor is not affiliated with Almanea. Respect site terms and applicable law.

### Development

Python 3.12 Docker runtime; pinned Apify 4.0.2 / Crawlee 1.10.4 / Pydantic 2.13.5. Crawlee is compatibility-pinned; network extraction uses bounded Python stdlib transport. Install `requirements.txt`, then `python -m src.main`. For offline tests install `jsonschema` and run `python -m unittest discover -s tests -v`. Metadata tests additionally use the independently archived official Apify metaschemas under the review workspace. No paid calls, console changes or publication are performed by these tests.

# Actor input Schema

## `productUrls` (type: `array`):

Explicit HTTPS www.almanea.sa/product/...-p-ID URLs. The editable example is not an API default; empty or omitted API URLs stay empty.

## `discoverProducts` (type: `boolean`):

Read the verified best-sellers product sitemap, selecting a bounded number of product URLs; no category or CMS crawling.

## `maxProducts` (type: `integer`):

Maximum unique product URLs attempted.

## `maxRequests` (type: `integer`):

Total request budget, including robots, redirects, sitemap and products.

## `maxSitemapBytes` (type: `integer`):

Response byte cap for the verified sitemap; oversize responses stop the source.

## Actor input object example

```json
{
  "productUrls": [
    "https://www.almanea.sa/product/philips-3000-series-steam-iron-2600-watts-dst3041-36-p-150306202999023"
  ],
  "discoverProducts": false,
  "maxProducts": 1,
  "maxRequests": 3,
  "maxSitemapBytes": 4000000
}
```

# Actor output Schema

## `results` (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 = {
    "productUrls": [
        "https://www.almanea.sa/product/philips-3000-series-steam-iron-2600-watts-dst3041-36-p-150306202999023"
    ],
    "maxProducts": 1,
    "maxRequests": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("vixendata/almanea-saudi-products").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 = {
    "productUrls": ["https://www.almanea.sa/product/philips-3000-series-steam-iron-2600-watts-dst3041-36-p-150306202999023"],
    "maxProducts": 1,
    "maxRequests": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("vixendata/almanea-saudi-products").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 '{
  "productUrls": [
    "https://www.almanea.sa/product/philips-3000-series-steam-iron-2600-watts-dst3041-36-p-150306202999023"
  ],
  "maxProducts": 1,
  "maxRequests": 3
}' |
apify call vixendata/almanea-saudi-products --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vixendata/almanea-saudi-products"
        }
    }
}
```

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/VkZhMzphTnzzGtHDV/builds/nXm5faMIcNhdRwt2h/openapi.json
