# Deraah Saudi Fragrance (`vixendata/deraah-saudi-fragrance`) Actor

Deraah Saudi perfume prices in SAR, stock, fragrance specifications and bundle contents from explicit URLs or bounded initial-category discovery.

- **URL**: https://apify.com/vixendata/deraah-saudi-fragrance.md
- **Developed by:** [Vixendata](https://apify.com/vixendata) (community)
- **Stats:** 2 total users, 1 monthly users, 71.4% 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

## Deraah Saudi Fragrance

Collect Deraah Saudi perfume prices, stock, fragrance specifications, and bundle contents as structured product rows. Useful for assortment checks, promotion snapshots, and fragrance research in SAR.

### What you get

- Product title, SKU/MPN, brand, canonical detail URL and image URLs
- Current SAR offer price and explicitly crossed-out regular price
- Source availability and nullable stock flag
- Source description, specifications, concentration, size text and scent-note sentences when present
- Bundle flag and separately listed bundle contents
- Source locale, source-text language classification and collection timestamp

Missing data stays null or empty. Source text is preserved, not translated. The language field is a conservative script heuristic: Arabic-only `ar`, Latin-only `en` for this English storefront, mixed `mixed`, otherwise `und`; it is not general-purpose language detection. No reviews, ratings, sales estimates or customer information are manufactured. No per-milliliter price is calculated. A package price is the entire package's price, never an individual bottle price.

The genuine fixture examples are Al-Sarim new spray 100 ml at 96 SAR (crossed-out 240 SAR), and Al-Fakhr Package at 288 SAR (crossed-out 824 SAR). The latter separately lists three fragrances. Prices are historical examples from 2026-10-07, not promises of current pricing.

### Inputs

Supply clean `https://www.deraahstore.com/en_sa/.../SKU.html` product URLs in `productUrls`, or set `discoverFromCategory` to true. Empty or omitted product URLs never inject example products. Without URLs or discovery, input fails clearly.

`maxProducts` defaults to 10, range 1–100. Explicit URLs have priority; discovered URLs follow. `requestDelaySeconds` defaults to 2, range 2–30, with longer robots delays respected.

Discovery reads only https://www.deraahstore.com/en_sa/perfumes/all-perfumes. The observed initial page supplied 12 product links. This is not all 348 displayed products: no load-more endpoint, API or pagination is used, and no complete-catalog coverage is claimed.

Ready-to-run tiny inputs are `INPUT.direct-smoke.json` and `INPUT.category-smoke.json`, each capped at one detail page. The direct run needs two requests (robots and detail), category run three (robots, category and detail), absent redirects.

### Output and limitations

The default dataset contains product rows; `RUN_SUMMARY` in the default key-value store records detail attempts, discovery coverage and errors. Individual ordinary HTTP/parse failures are reported and remaining URLs continue. Access blocks stop the whole host immediately. A zero-row run fails instead of appearing successful. `sample-output.json` contains parser output from sanitized genuine source fixtures, not a hosted run result.

JSON-LD matching the fetched product URL is authoritative for current price and stock. Regular price is taken only from unambiguous crossed-out price elements; the specification panel's reference “Price” is not treated as the current offer. Bundle detection is based on explicit package/set wording or a fragrance-count label; source contents remain separate strings. `promotionText` is currently null because no stable independent promotion-label selector is asserted.

### Responsible access

Only the exact HTTPS host and English Saudi product/category paths are accepted. Account, checkout, cart, search and wishlist paths are forbidden. Every run checks robots first; unavailable or invalid robots fails closed. Redirects stay in the same permitted URL class and recheck robots. No proxies, login, credentials, hidden APIs, CAPTCHA solving or bypass.

Concurrency is one. HTTP 401/403/429 or challenge pages stop without retries. Bounds: three redirect attempts per logical request, at most `3 * (maxProducts + 2)` HTTP requests, four MB per response, 50 MB total response bytes, 30-second HTTP timeout, up to 100 discovered URLs and 100 input URLs.

### Validation

Pinned Python runtime dependencies: Apify 4.0.2, Crawlee 1.10.4 and Pydantic 2.13.5. Fresh isolated installation and offline fixture/security/schema tests are recorded in `test-results.txt` and `runtime-freeze.txt`. Official Apify input and dataset metaschemas were validated. Fixtures retain only public product JSON-LD, specifications and crossed-out-price elements; provenance hashes are in `evidence/fixture-provenance.json`.

A bounded direct HTTP live check from this build environment stopped on DNS resolution before any response; see `evidence/live-check.json`. The upstream researcher separately obtained HTTP 200 category and both detail fixtures. Hosted runtime success remains to be established by the deployment owner. This package makes no claims of a completed hosted run.

For local tests, install `requirements.txt` plus `requirements-test.txt`, then run `python -m unittest discover -s tests -v`. Schema tests use the included official metaschema snapshots. Run the Actor with `python -m src` and normal Apify input storage.

# Actor input Schema

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

Clean English Saudi Deraah product URLs ending in numeric SKU.html. Up to 100; the editable example is not an API default.

## `discoverFromCategory` (type: `boolean`):

Read only the verified initial all-perfumes category. No load-more or full-catalog promise.

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

Maximum detail URLs attempted, explicit URLs first. Range 1–100.

## `requestDelaySeconds` (type: `integer`):

Minimum delay between requests, with longer robots delays honored. Range 2–30.

## Actor input object example

```json
{
  "productUrls": [
    "https://www.deraahstore.com/en_sa/oud/oriental-perfumes/10311111013100-1003.html"
  ],
  "discoverFromCategory": false,
  "maxProducts": 1,
  "requestDelaySeconds": 2
}
```

# 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.deraahstore.com/en_sa/oud/oriental-perfumes/10311111013100-1003.html"
    ],
    "maxProducts": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("vixendata/deraah-saudi-fragrance").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.deraahstore.com/en_sa/oud/oriental-perfumes/10311111013100-1003.html"],
    "maxProducts": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("vixendata/deraah-saudi-fragrance").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.deraahstore.com/en_sa/oud/oriental-perfumes/10311111013100-1003.html"
  ],
  "maxProducts": 1
}' |
apify call vixendata/deraah-saudi-fragrance --silent --output-dataset

```

## MCP server setup

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

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/qct8vApfxfcEag5Zm/builds/n1lwh9nVCJtObkib3/openapi.json
