# Fragrantica Scraper — Perfume Profiles & Notes (`khadinakbar/fragrantica-scraper`) Actor

Extract structured Fragrantica perfume profiles with brand, perfumer, note pyramid, main accords, rating, launch year, and source provenance. Use only with Fragrantica authorization. MCP-ready. $0.006 per saved profile.

- **URL**: https://apify.com/khadinakbar/fragrantica-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** E-commerce, Automation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 fragrantica perfume profile scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Fragrantica Scraper — Perfume Profiles & Notes

Extract structured perfume profiles from authorized Fragrantica product pages. The actor turns individual `/perfume/...html` URLs into comparison-ready JSON records containing the perfume name, brand, credited perfumer, launch year, main accords, top/middle/base notes, visible rating fields, bottle image, editorial description, and source provenance.

Use this actor for licensed fragrance-data research, catalog enrichment, assortment comparison, trend analysis, and internal product intelligence. It is deliberately narrow: v0.1 handles perfume profile pages, not search pages, designer pages, forums, or bulk review collection. That keeps its output stable for API and MCP consumers.

### Authorization and permitted use

Run this actor only where you have written authorization from Fragrantica or another applicable legal basis to access and commercially use the requested data. You are responsible for ensuring your input URLs, storage, downstream use, and redistribution comply with your agreement and applicable law. The actor does not accept login cookies, credentials, or attempts to circumvent access controls. If Fragrantica returns a Cloudflare challenge instead of a product page, the run reports an honest upstream failure rather than treating it as empty data.

### When to use it

Use this actor when you already have one or more authorized Fragrantica perfume URLs and need structured fields for a database, spreadsheet, RAG index, comparison workflow, or AI-agent task. Provide a full product URL such as:

`https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html`

Do not use it for perfume discovery from a keyword, extracting every fragrance by a designer, collecting community reviews, or scraping Fragrantica pages outside the `/perfume/` route. Those uses are out of scope for this initial private build.

### Output

Each dataset item is a normalized perfume profile. Fields are stable and documented in `.actor/dataset_schema.json`.

| Field | Description |
| --- | --- |
| `name`, `brand`, `brandUrl` | Perfume identity and designer provenance |
| `productId`, `sourceUrl`, `scrapedAt` | Stable source identifiers and extraction time |
| `gender`, `fragranceFamily`, `launchYear` | Core classification fields when present |
| `perfumers` | Credited nose or noses from the profile description |
| `mainAccords` | Ordered Fragrantica main accords |
| `topNotes`, `middleNotes`, `baseNotes` | Note pyramid arrays |
| `rating`, `ratingCount` | Visible user-rating fields when reliably present |
| `description`, `imageUrl` | Editorial profile text and primary bottle image URL |

Example record:

```json
{
  "sourceUrl": "https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html",
  "productId": "123",
  "name": "Tuscany Per Uomo Aramis for men",
  "brand": "Aramis",
  "gender": "men",
  "fragranceFamily": "Aromatic Fougere",
  "launchYear": 1984,
  "perfumers": ["Francis Deleamont"],
  "mainAccords": ["citrus", "aromatic", "fresh spicy"],
  "topNotes": ["Lemon", "Lavender", "Bergamot", "Lime"],
  "middleNotes": ["Anise", "Caraway", "Tarragon", "Orange Blossom"],
  "baseNotes": ["Leather", "Oakmoss", "Basil", "Patchouli"],
  "rating": null,
  "ratingCount": null,
  "scrapedAt": "2026-07-14T12:00:00.000Z"
}
````

Null values mean a field was not reliably displayed on that profile; empty arrays mean the corresponding note or accord list was not present. The actor never substitutes invented data for a missing field.

### Input

`startUrls` is an array of one or more authorized Fragrantica perfume URLs. Every URL must use HTTPS, host `www.fragrantica.com` or `fragrantica.com`, begin with `/perfume/`, and end in `.html`. Invalid URLs are skipped when valid URLs remain; a run with no valid input exits successfully as `INVALID_INPUT` with a clear diagnostic in `OUTPUT` and `RUN_SUMMARY`.

`maxResults` is a strict 1–100 cap on saved perfume records. The actor deduplicates repeated URLs before requesting them and never writes or bills more profile records than the cap. `proxyCountryCode` selects the Apify Residential proxy country (US, GB, or DE). `useApifyProxy` defaults to true and should stay enabled for cloud runs because Fragrantica may challenge direct automation traffic.

### Price and cost visibility

This private actor uses Pay per event + usage. The event charges are:

- Actor start: $0.00005 after valid input is accepted.
- Validated perfume profile saved: $0.006 per record.

Apify platform usage, including Residential Proxy usage, is charged separately to the user. Before any request, the run status message displays the maximum event-charge estimate implied by the cap. A one-profile run has event charges of approximately $0.00605 plus platform usage; five profiles have event charges of approximately $0.03005 plus platform usage. Profiles are charged only when a validated dataset row is persisted.

### Terminal outcome contract

The actor writes both `OUTPUT` and `RUN_SUMMARY` into the default key-value store for every terminal path. API and MCP consumers should read `OUTPUT` for the compact, stable summary and `RUN_SUMMARY` for safe diagnostics.

- `COMPLETE`: all requested valid profiles were saved.
- `PARTIAL`: useful profiles were saved, but some URLs failed, were invalid, or the event cap stopped additional work.
- `VALID_EMPTY`: valid pages were processed but yielded no usable profile.
- `INVALID_INPUT`: the request contains no valid Fragrantica perfume URL or an invalid cap.
- `UPSTREAM_FAILED`: Fragrantica returned challenges or requests failed after retries and no useful profile was saved.
- `CONFIG_ERROR`: a required deployment configuration is unavailable.

The first four outcomes finish as `SUCCEEDED`; the last two finish as `FAILED` so an upstream outage is never hidden behind a false success.

### JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('khadinakbar/fragrantica-scraper').call({
  startUrls: [{
    url: 'https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html',
  }],
  maxResults: 1,
  proxyCountryCode: 'US',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### cURL example

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~fragrantica-scraper/runs?token=$APIFY_TOKEN" \
  -H "content-type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html"}],
    "maxResults": 1,
    "proxyCountryCode": "US"
  }'
```

### Reliability and data quality

The crawler uses a consistent Residential proxy session, bounded retries, a single-request concurrency setting, and a semantic parser based on visible headings and note links. Every candidate record is normalized and validated before `Actor.pushData` writes it and charges the `profile-scraped` event. That coupling prevents billing a record that was not persisted. The actor records request errors, invalid records, warnings, terminal counts, and charge counts without exposing URLs with query parameters, cookies, authorization headers, or other secrets.

Fragrantica can change its markup or bot protection. The release process therefore includes a private cloud acceptance matrix across valid profile URLs, invalid input, result caps, proxy countries, concurrency, cold/warm runs, and data-schema checks. The release report records the observed canary sample rather than claiming it proves long-term production reliability.

### Support boundary

For an authorized production use case that needs search, designer catalogs, reviews, historical change tracking, or a licensed API integration, extend the private actor only after confirming those capabilities are covered by the Fragrantica authorization. Keep any new mode behind a schema field, an explicit output contract, and a new cloud acceptance matrix.

# Actor input Schema

## `startUrls` (type: `array`):

Use this when you have Fragrantica perfume-page URLs to extract. Enter full HTTPS URLs such as 'https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html'. Each URL must start with /perfume/ and end in .html. NOT for designer, note, forum, or search pages.

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

Use this to cap the number of valid perfume profiles saved in this run. Enter an integer from 1 to 100, for example 5. Defaults to 5 and the actor never charges more profile events than this cap. NOT a page-depth or review-count setting.

## `proxyCountryCode` (type: `string`):

Use this to choose the country for the Apify Residential proxy session. Select a two-letter country code such as 'US', 'GB', or 'DE'. Defaults to US and may affect regional site behavior. NOT a country filter for perfume results.

## `useApifyProxy` (type: `boolean`):

Use this to route requests through Apify Residential proxies, which is the reliable default for Fragrantica. Set true for cloud runs and false only when an authorized local network is intentionally used. Defaults to true. NOT a way to bypass authorization requirements.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html"
    }
  ],
  "maxResults": 5,
  "proxyCountryCode": "US",
  "useApifyProxy": true
}
```

# Actor output Schema

## `results` (type: `string`):

Validated Fragrantica perfume-profile records as structured JSON.

## `runSummary` (type: `string`):

Terminal outcome, counts, safe diagnostics, and charged events.

## `output` (type: `string`):

Compact terminal outcome for machine consumers.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html"
        }
    ],
    "proxyCountryCode": "US",
    "useApifyProxy": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/fragrantica-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 = {
    "startUrls": [{ "url": "https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html" }],
    "proxyCountryCode": "US",
    "useApifyProxy": True,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/fragrantica-scraper").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 '{
  "startUrls": [
    {
      "url": "https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html"
    }
  ],
  "proxyCountryCode": "US",
  "useApifyProxy": true
}' |
apify call khadinakbar/fragrantica-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=khadinakbar/fragrantica-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Fragrantica Scraper — Perfume Profiles & Notes",
        "description": "Extract structured Fragrantica perfume profiles with brand, perfumer, note pyramid, main accords, rating, launch year, and source provenance. Use only with Fragrantica authorization. MCP-ready. $0.006 per saved profile.",
        "version": "0.2",
        "x-build-id": "A8EGcXTATmJReYDqh"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/khadinakbar~fragrantica-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-khadinakbar-fragrantica-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/khadinakbar~fragrantica-scraper/runs": {
            "post": {
                "operationId": "runs-sync-khadinakbar-fragrantica-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/khadinakbar~fragrantica-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-khadinakbar-fragrantica-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "Fragrantica perfume URLs",
                        "type": "array",
                        "description": "Use this when you have Fragrantica perfume-page URLs to extract. Enter full HTTPS URLs such as 'https://www.fragrantica.com/perfume/Aramis/Tuscany-Per-Uomo-123.html'. Each URL must start with /perfume/ and end in .html. NOT for designer, note, forum, or search pages.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxResults": {
                        "title": "Maximum perfume profiles",
                        "type": "integer",
                        "description": "Use this to cap the number of valid perfume profiles saved in this run. Enter an integer from 1 to 100, for example 5. Defaults to 5 and the actor never charges more profile events than this cap. NOT a page-depth or review-count setting.",
                        "default": 5
                    },
                    "proxyCountryCode": {
                        "title": "Residential proxy country",
                        "enum": [
                            "US",
                            "GB",
                            "DE"
                        ],
                        "type": "string",
                        "description": "Use this to choose the country for the Apify Residential proxy session. Select a two-letter country code such as 'US', 'GB', or 'DE'. Defaults to US and may affect regional site behavior. NOT a country filter for perfume results.",
                        "default": "US"
                    },
                    "useApifyProxy": {
                        "title": "Use Apify Residential Proxy",
                        "type": "boolean",
                        "description": "Use this to route requests through Apify Residential proxies, which is the reliable default for Fragrantica. Set true for cloud runs and false only when an authorized local network is intentionally used. Defaults to true. NOT a way to bypass authorization requirements.",
                        "default": true
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
