# FairPrice Scraper – Singapore Grocery Prices & Products (`claude_code_reviewer/fairprice-scraper-en`) Actor

Scrape NTUC FairPrice (Singapore's largest grocery) without an API: product name, brand, price, original price, discount, promo, unit, category and stock. Bulk-paste keywords; export JSON/CSV/Excel. Ideal for grocery price monitoring and comparison.

- **URL**: https://apify.com/claude\_code\_reviewer/fairprice-scraper-en.md
- **Developed by:** [Chad](https://apify.com/claude_code_reviewer) (community)
- **Categories:** Agents, Lead generation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 search results

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/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

## FairPrice Scraper | Singapore Grocery Prices, Products & Discounts (No API, No Login)

Scrape **NTUC FairPrice** (fairprice.com.sg) supermarket product data: keyword-search listings, selling price, promo labels, brand, category, stock status and images. It reads FairPrice's **public JSON API** — no login, no API token, no browser — and outputs clean, structured snake_case data.

Singapore FMCG price intelligence is a proven B2B need — running the same set of keywords on a schedule builds a running SG supermarket price-tracking series.

---

### What you get

Every product returns the fields below (missing values are always `null` — no field is dropped):

| Field                  | Description                                                        |
| ---------------------- | ------------------------------------------------------------------- |
| `product_id`           | FairPrice product ID                                                 |
| `name`                 | Product name                                                          |
| `brand`                | Brand                                                                  |
| `price`                | Selling price (SGD)                                                   |
| `original_price`       | Original price (pre-promo MRP; `null` when there is no promotion)    |
| `discount_pct`         | Discount percentage (computed from price / original price; `null` when there is no promotion) |
| `price_per_unit`       | Unit price (planned for v1.1, currently always `null`)               |
| `unit_of_measure`      | Unit of measure, e.g. `1 L`, `500 g`                                  |
| `category`             | Main category name                                                    |
| `category_path`        | Full category path (planned for v1.1, currently always `null`)       |
| `in_stock`             | Whether the item is in stock                                          |
| `is_express_delivery`  | Whether express delivery is available (planned for v1.1, currently always `null`) |
| `promo_label`          | Promo copy, e.g. `*Buy 1* Save $0.35`                                 |
| `rating`               | Average rating (`null` when there are no reviews)                     |
| `review_count`         | Number of reviews                                                      |
| `image_urls`           | Array of product image URLs                                           |
| `product_url`          | Product page URL                                                       |
| `source_mode`          | Source mode (`search`)                                                 |
| `source_query`         | The keyword that triggered this row                                    |
| `scraped_at`           | Scrape timestamp (ISO 8601)                                            |

Fields marked "planned for v1.1" are already reserved in the output schema and will be populated in a future release once source data support is validated.

---

### Modes (v1.0 has search only)

| Mode          | What it does                                                    | Billing event      | Price  |
| ------------- | ---------------------------------------------------------------- | ------------------ | ------ |
| 🔎 **search** | Keyword search → product listings (price, promo, stock, category, images) | `search-listing` (per row) | $0.002 |

Each Run also charges a one-time `actor-start` fee of **$0.005**. All charges are billed **only after** data is successfully written to the dataset, and the Run log prints `total_items / charged / skipped` for reconciliation.

Product detail (single-product page scraping) is planned for **v1.1** — the `search` mode already returns brand, price, promo, category and image fields on every row, which covers most price-comparison and monitoring use cases in v1.0.

---

### Input fields

| Field                 | Type     | Required                        | Default    | Description                                                                                                          |
| ---------------------- | -------- | :-----------------------------: | :--------: | ------------------------------------------------------------------------------------------------------------------ |
| `keywords`             | string[] | one required (or `bulkInput`)   | —          | Search keywords; one concept per keyword works best. Up to **50** per run.                                          |
| `bulkInput`            | string   | optional                        | —          | **One per line** (press Enter, no quotes or commas). Merged into `keywords` at runtime. Fastest is to paste a column from Google Sheets / Excel. |
| `storeId`              | string   | optional                        | —          | Specify a FairPrice store to get that store's price/stock. Leave blank to use the default online warehouse.        |
| `maxItems`             | integer  | optional                        | `50`       | Max results per keyword (1-500).                                                                                    |
| `proxyConfiguration`   | object   | optional                        | off        | Advanced, usually left off — FairPrice has no Cloudflare / bot challenge.                                            |

---

### Examples

**🔎 Basic keyword search**

```json
{ "keywords": ["milk"], "maxItems": 30 }
````

**📋 Bulk keywords (one per line)**

```json
{ "keywords": ["coffee"], "bulkInput": "eggs\nrice\nolive oil", "maxItems": 20 }
```

**🏬 Specific store**

```json
{ "keywords": ["bread"], "storeId": "165", "maxItems": 50 }
```

**Sample output row**

```json
{
    "product_id": "1577586",
    "name": "RedMan UHT Full Cream Milk 3.5%",
    "brand": "Redman",
    "price": 3.13,
    "original_price": null,
    "discount_pct": null,
    "price_per_unit": null,
    "unit_of_measure": "1 L",
    "category": "UHT Milk",
    "category_path": null,
    "in_stock": true,
    "is_express_delivery": null,
    "promo_label": "*Buy 1* Save $0.35",
    "rating": null,
    "review_count": null,
    "image_urls": ["https://media.nedigital.sg/fairprice/90221204_XL1_..."],
    "product_url": "https://www.fairprice.com.sg/product/redman-uht-full-cream-milk-35-1577586",
    "source_mode": "search",
    "source_query": "milk",
    "scraped_at": "2026-07-04T00:00:00.000Z"
}
```

***

### Notes

- **Public data only.** No login and no FairPrice account required; it never accesses anything behind authentication.
- **No login / no API token.** Fill in the input and run — no keys to configure. Requests go straight to FairPrice's public JSON search endpoint.
- **JSON API + CheerioCrawler — no browser.** Keeps compute cost low and avoids the overhead of a headless browser.
- **Polite to the site.** Per-domain concurrency is capped at 5, failures retry with exponential backoff up to 3 times, and it auto-stops after 5 pages with no new data — no idle burn.
- **Prices and promotions reflect what FairPrice returns at scrape time** and will vary by store and by time of day.

***

### FAQ

**Q: Can it capture promo pricing?**
Yes — it returns the current selling price (`price`), the pre-promo original price (`original_price`), the computed discount percentage (`discount_pct`), and the promo copy (`promo_label`). When there is no active promotion, `original_price` and `discount_pct` are `null`.

**Q: Can I scrape prices for a specific store?**
Yes, set `storeId`. Leave it blank to use the default online warehouse.

**Q: Will it get blocked?**
FairPrice has no Cloudflare or bot challenge; direct datacenter requests work fine and a proxy generally isn't needed.

**Q: How is billing calculated?**
Each Run charges `actor-start` once ($0.005); each product listing charges `search-listing` ($0.002). Both are billed only after data is written to the dataset, and the Run log prints the actual charged count.

**Q: Do you support the product detail page (full single-product data)?**
v1.0 ships search-listing only. If demand is proven, a `detail` mode is planned for v1.1.

***

### Deploy

```bash
apify login              # first time: paste your Apify token (never written to the repo)
apify push               # build and upload to Apify Store
```

After publishing, set the PPE event prices in Apify Console → Monetization:
`actor-start` $0.005, `search-listing` $0.002.

***

### Disclaimer

This scraper only collects **publicly visible** FairPrice product search data, for price research and personal comparison-shopping use, not for any unauthorized commercial resale. Please ensure your use complies with FairPrice's Terms of Service and your local laws. This Actor makes no guarantee about the accuracy, timeliness or completeness of the data — always refer to the live FairPrice website for current prices and stock.

***

*FairPrice scraper, NTUC FairPrice, Singapore grocery prices, SG supermarket data, grocery price comparison Singapore, FMCG price monitoring, Singapore retail data*

# Actor input Schema

## `keywords` (type: `array`):

Product keywords to search for, e.g. milk, eggs, rice, coffee. One concept per keyword works best.

## `bulkInput` (type: `string`):

**One keyword per line** (press Enter for a new line, no quotes or commas). Automatically merged into the Keywords field above at runtime. Fastest way is to copy a whole column from Google Sheets / Excel.

## `storeId` (type: `string`):

Specify a FairPrice store to get that store's price/stock. Leave blank to use the default online warehouse. Most use cases can leave this blank.

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

Max results per keyword. More items = higher cost.

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

FairPrice is friendly to datacenter requests (no Cloudflare); it works without a proxy by default. Enable only if you hit blocks during heavy scraping.

## Actor input object example

```json
{
  "keywords": [
    "milk"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "keywords": [
        "milk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("claude_code_reviewer/fairprice-scraper-en").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 = { "keywords": ["milk"] }

# Run the Actor and wait for it to finish
run = client.actor("claude_code_reviewer/fairprice-scraper-en").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 '{
  "keywords": [
    "milk"
  ]
}' |
apify call claude_code_reviewer/fairprice-scraper-en --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "FairPrice Scraper – Singapore Grocery Prices & Products",
        "description": "Scrape NTUC FairPrice (Singapore's largest grocery) without an API: product name, brand, price, original price, discount, promo, unit, category and stock. Bulk-paste keywords; export JSON/CSV/Excel. Ideal for grocery price monitoring and comparison.",
        "version": "1.0",
        "x-build-id": "1lbM3O2RGurqmj6GX"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/claude_code_reviewer~fairprice-scraper-en/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-claude_code_reviewer-fairprice-scraper-en",
                "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/claude_code_reviewer~fairprice-scraper-en/runs": {
            "post": {
                "operationId": "runs-sync-claude_code_reviewer-fairprice-scraper-en",
                "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/claude_code_reviewer~fairprice-scraper-en/run-sync": {
            "post": {
                "operationId": "run-sync-claude_code_reviewer-fairprice-scraper-en",
                "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": {
                    "keywords": {
                        "title": "🔎 Keywords",
                        "maxItems": 50,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Product keywords to search for, e.g. milk, eggs, rice, coffee. One concept per keyword works best.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "bulkInput": {
                        "title": "📋 Bulk paste keywords",
                        "type": "string",
                        "description": "**One keyword per line** (press Enter for a new line, no quotes or commas). Automatically merged into the Keywords field above at runtime. Fastest way is to copy a whole column from Google Sheets / Excel."
                    },
                    "storeId": {
                        "title": "🏬 Store ID (optional)",
                        "type": "string",
                        "description": "Specify a FairPrice store to get that store's price/stock. Leave blank to use the default online warehouse. Most use cases can leave this blank."
                    },
                    "maxItems": {
                        "title": "📊 Max items per keyword",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Max results per keyword. More items = higher cost.",
                        "default": 50
                    },
                    "proxyConfiguration": {
                        "title": "🌐 Proxy (advanced, usually off)",
                        "type": "object",
                        "description": "FairPrice is friendly to datacenter requests (no Cloudflare); it works without a proxy by default. Enable only if you hit blocks during heavy scraping.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
