# Playphone Oman Product Facts (`vixendata/playphone-oman-product-facts`) Actor

Public product and variant facts, SKU, exact OMR prices, inventory and initial catalog snapshot.

- **URL**: https://apify.com/vixendata/playphone-oman-product-facts.md
- **Developed by:** [Vixendata](https://apify.com/vixendata) (community)
- **Stats:** 2 total users, 1 monthly users, 77.8% 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

## Playphone Oman Product Facts

Read precise OMR prices, SKU, product/variant IDs and public inventory facts from Playphone Oman. Useful for product matching and bounded price/stock snapshots. No login or API keys for the source website. This independent tool is not affiliated with or endorsed by Playphone.

### Quick start

Use `smoke/direct.json` to read the selected black AirPods Max variant (two source requests including robots). Use `smoke/discovery.json` for one product from the initial public catalog page. Install `requirements.txt`, then run `python -m src.main` in an Apify environment. Offline tests: `python -m unittest discover -s tests -v`.

### Input

- `productUrls`: up to 100 public HTTPS www.playphone.om/product/slug URLs, no queries or fragments. Empty/omitted stays empty. Supply URLs or enable discovery.
- `discoverProducts`: default false. Reads public /products once and extracts its initial rendered products. At research time this exposed 32 products against a reported total of 346. No pagination, completeness or all-variant catalog coverage is claimed. Initial catalog membership and count can change.
- `includeAllVariants`: default false. Direct URLs return the requested slug only. Enable to extract all variants embedded in each requested product page. Other variants have `selectedVariant: false`; discovery is unaffected.
- `maxProducts`: maximum output variant records, 1–100, default 5. Variants count separately. Direct URLs run before discovery; discovery is skipped when the bound is already filled. Embedded variant order is source order when all variants are enabled.
- `maxRequests`: 2–150, default 15, including robots and redirects. Exhaustion fails rather than exceeding the budget.

### Output semantics

One row per variant ID. Current `storePrice` becomes `price`, exactly three decimal places, plus integer `priceBaisa` (OMR 63.9 → `63.900`, 63900 baisa). `originalPrice` retains the source field meaning, not a verified MSRP or historical price. Both raw numeric strings are preserved. Decimal conversion rejects negative, non-finite and overprecision prices.

`quantity` is the source inventory count; `stock` is derived only when quantity exists. `isOutOfStockSellable` and `isPreOrderAvailable` stay separate source flags, so out-of-stock inventory can still be sellable. Missing fields remain null and appear in `missingFields`. Availability is not a checkout or delivery promise. Listing data may lack brand and attributes; direct details contain richer facts. Rows include category names, attributes when present, image URLs, requested source URL, variant product URL, UTC timestamp and source mode. No long descriptions are copied.

The `OUTPUT` key-value record explains coverage and request counts. `catalogComplete` remains false. Dataset publication happens only after the whole bounded run succeeds; a failed source request does not silently publish an incomplete accumulation.

### Access and respectful fetching

Public website HTML and embedded rendered Next.js Flight/RSC data only. No private APIs, login, proxies, challenge solving, credentials or restriction bypass. Robots is loaded first and enforced on each request and redirect. Single-request pacing is at least one second and honors greater crawl-delay/request-rate directives. Redirects must retain the same allowlisted public host and path type. Actual HTTP errors including 401/403/429, active CAPTCHA/challenge pages, malformed data, changed identity/currency, byte limits and budget exhaustion stop without retries. HTML is capped at 12 MB; robots at 1 MB.

Research on 7 October 2026 found robots allowing public access and purchasing-focused terms at https://www.playphone.om/terms_and_condition without an identified scraping prohibition. This is not legal permission or a license.

### Validation and limitations

Sanitized real fixtures preserve relevant factual public props from one product detail and the 32-item initial listing; provenance and source hashes are in tests/fixtures/provenance.json. Synthetic regressions cover length-prefixed UTF-8 Flight records, missing stock, precision, redirects, budgets, robots and actual HTTP denials. Flight framing is parsed without evaluating JavaScript. Apify schemas are checked against official downloaded metaschemas. Fresh pinned runtime imports and offline tests are verified separately from hosted build/run validation.

No verified public pagination route is implemented. Use known product URLs for products beyond the initial listing; do not interpret the reported total as extracted coverage.

### Pricing

The price is $3 per 1,000 product rows saved to the default dataset, plus $0.00005 per run start, with usage included; check the Store pricing panel for the price applying to your run.

# Actor input Schema

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

Public https://www.playphone.om/product/slug URLs. Empty or omitted stays empty; discovery never inserts samples.

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

Extract the initial public /products listing only. Does not paginate or claim complete catalog coverage.

## `includeAllVariants` (type: `boolean`):

Direct URLs only: extract all variants embedded in the requested product page. Otherwise only the requested slug. Each variant counts toward maxProducts.

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

Bound on dataset records, including related variants.

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

Includes robots and redirects; reaching this budget stops the run.

## Actor input object example

```json
{
  "productUrls": [],
  "discoverProducts": true,
  "includeAllVariants": false,
  "maxProducts": 1,
  "maxRequests": 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": [],
    "discoverProducts": true,
    "includeAllVariants": false,
    "maxProducts": 1,
    "maxRequests": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("vixendata/playphone-oman-product-facts").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": [],
    "discoverProducts": True,
    "includeAllVariants": False,
    "maxProducts": 1,
    "maxRequests": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("vixendata/playphone-oman-product-facts").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": [],
  "discoverProducts": true,
  "includeAllVariants": false,
  "maxProducts": 1,
  "maxRequests": 2
}' |
apify call vixendata/playphone-oman-product-facts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vixendata/playphone-oman-product-facts"
        }
    }
}
```

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/0PHwvchhyQTQqYFK7/builds/VqkUdloLdH0xH3pEW/openapi.json
