# Uniqlo Sale Watch: US & Japan Product Prices (`superslowsloth/uniqlo-products`) Actor

Uniqlo US and Japan storefront products as flat rows: name, base and sale price, currency, discount percent when shown, sale flag and dates, gender, rating, colors, sizes, photo, URL. Search any terms or list the whole sale rack.

- **URL**: https://apify.com/superslowsloth/uniqlo-products.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 product scrapeds

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

## Uniqlo Sale Watch: US & Japan Product Prices

Read [Uniqlo](https://www.uniqlo.com)'s United States and Japan storefronts as
flat rows: product name, base price, sale price, currency, the Sale or
Limited-Time Offer flag with its dates, gender, rating, colors, sizes, photo and
the product link. Search any terms, or tick **Only products on sale** with no
terms to list the **whole sale rack** of a storefront. Schedule it daily and
diff the runs: that is a Uniqlo sale watch for both countries.

No account, no API key, no login, no browser. One request returns up to 100
products.

### Input

| Field | Notes |
|---|---|
| `region` | `us` (uniqlo.com/us, USD, sales tax not included) or `jp` (uniqlo.com/jp, JPY, consumption tax included). Default `us`. |
| `queries` | Search terms, one per line (`jacket`, `heattech`, `ウルトラライトダウン`). A product found by two terms is returned once, under the first. May be empty **only** together with `onlyOnSale`. |
| `onlyOnSale` | Keep only products carrying Uniqlo's Sale flag (値下げ in Japan) or its Limited-Time Offer flag (期間限定価格). Uniqlo applies this filter itself, so `maxItems` counts sale products. With no terms it lists the entire sale rack. |
| `maxItems` | Products to read per search term, or for the sale rack (default 100, up to 5,000). |
| `proxyConfiguration` | Apify proxy by default. |

A run needs a term or `onlyOnSale`. Uniqlo answers a search with neither as an
empty result, not as the catalogue, so there is no "list everything" mode and
the actor refuses such a run before it charges anything.

Search terms are matched by the storefront's own search in either language: on
Japan, `jacket` found 119 products and `ジャケット` 121 (measured 2026-10-11).

### Output

| Field | Notes |
|---|---|
| `query` | The search term that first found this product. Null on a sale-rack run. |
| `region`, `currency` | `us` / `jp` and the ISO currency the API states (`USD`, `JPY`). |
| `product_id`, `price_group`, `item_number` | Uniqlo's product id (`E487516-000`), its price group (`00`; a few products sell in `01` or `02` too) and the six-digit item number (`487516`). Id plus group is the row's identity. |
| `name`, `url` | The product name in the storefront's language and the absolute product page, `https://www.uniqlo.com/<region>/<language>/products/<id>/<group>`. |
| `gender` | `WOMEN`, `MEN`, `KIDS`, `BABY` or `UNISEX`. |
| `base_price`, `promo_price` | Uniqlo's `base` and `promo` prices as floats. `promo_price` is null on every product that is not marked down. |
| `price_includes_tax` | `false` on `us`, `true` on `jp`. Fixed by storefront. |
| `on_sale` | True when the product carries a Sale or Limited-Time Offer flag (or a promo price). Multibuy and "select colors/sizes" flags are not sales. |
| `discount_percent` | The markdown as a percentage, one decimal, **only when both prices exist and `promo_price` is below `base_price`**. See below. |
| `price_flags` | Every price flag on the product by code: `discount`, `limitedOffer`, `multibuy`, `colorSizeLimitedPrice`. |
| `sale_label` | The sale flag as the storefront words it: `Sale`, `Limited-Time Offer until 10/15`, `値下げ`. |
| `sale_started_at`, `sale_ends_at` | When the sale flag took effect and when it ends, ISO 8601 UTC. `sale_ends_at` is null for an open-ended sale. |
| `rating`, `review_count` | Average review rating (0-5) and the number of reviews. |
| `colors`, `sizes` | Color names and size names the product is offered in. |
| `image_url` | The main photo in the product's representative color. |
| `promotion_text` | The storefront's promotion text; null when empty. |

#### What the sale price is, and is not

This is the part to read before building on `discount_percent`. Uniqlo's API
sends a `promo` price on exactly the products that carry a Sale or
Limited-Time Offer flag, and no `promo` on any other. But on every sale product
measured, `promo` **equals** `base`, and the price the product had before the
markdown is not in the search response or the product detail at all (measured
2026-10-11 by walking the whole sale rack of each storefront: 377 US products
and 455 JP products, none with a `promo` different from `base`). So:

- `on_sale`, `sale_label`, `sale_started_at` and `sale_ends_at` are reliable:
  they say *which* products are marked down and since when.
- `discount_percent` is **null on every row today**, because it is computed
  only from a `promo` below `base`, and Uniqlo has not sent one. It is never
  estimated or guessed. If Uniqlo starts sending a pre-sale price the column
  fills with no change on your side.
- For the size of a markdown, keep a previous run and compare `base_price`
  per `product_id` + `price_group` across days: a sale watch built on diffs
  gets the amount from your own history.

#### Honest nulls

A field Uniqlo did not send is `null`, never `0` or `""`:

- `rating` is null for a product with no reviews (the API sends average `0` with
  count `0`, which is the absence of a rating); `review_count` is then `0`.
- `promo_price`, `sale_label` and the sale dates are null on a product that is
  not marked down.
- `promotion_text` is null when empty.

### Pricing

Pay per event:

- **$0.002** per run (`actor-start`), charged only after your input is
  validated, so a run that fails on bad input costs nothing.
- **$0.00035** per product row written (`product-scraped`), i.e. $0.35 per
  1,000 products.

### How it fetches

It calls the JSON API behind Uniqlo's own storefront
(`www.uniqlo.com/<region>/api/commerce/v5/<language>/products`), 100 rows per
request, with no cookie, token or special header. Measured 2026-10-11: HTTP 200
from a plain connection and from Apify datacenter addresses on both
storefronts. A 403, 429 or 5xx is treated as a refusal, the actor rotates to a
fresh address and retries.

Things worth knowing, all measured:

- **The sale filter is Uniqlo's.** `onlyOnSale` sends `flagCodes=discount,limitedOffer`
  and Uniqlo returns only those products. The sale rack is a moving target:
  the US storefront listed 402 such products and, an hour later, 377 (337 with the
  Sale flag, 40 with the Limited-Time Offer flag); JP listed 455 both times. An unknown flag value filters to nothing
  rather than being ignored, so a typo cannot return a confidently wrong dataset.
- **A refused request is HTTP 200.** Uniqlo reports a bad request as
  `{"status": "nok", "error": {"httpStatusCode": 400}}` in the body. The actor
  reads that: a 403, 429 or 5xx there is retried from a new address, anything else
  (an empty term, a page size over 100) fails that search without retrying.
- **Search totals are the search's own.** `jacket` reports 100 products on the US
  storefront, `shirt` 547, `women` 904; an offset past the total returns an empty
  page, which is where the actor stops.
- **Prices differ in tax treatment.** US prices exclude sales tax (it is added at
  checkout); JP prices include consumption tax. `price_includes_tax` says which.
- **Product links resolve.** A real product id answers 200 and an unknown one 404;
  the storefront redirects a wrong price group to the right one.
- **Counts move.** `total` changes as products are added and withdrawn, so a walk
  can show a product twice across a page boundary; it is returned once.

# Actor input Schema

## `region` (type: `string`):

Which Uniqlo storefront to read. 'United States' is uniqlo.com/us (prices in USD, sales tax not included). 'Japan' is uniqlo.com/jp (prices in JPY, consumption tax included); search terms are matched by the storefront's own search in either language (on Japan, jacket found 119 products and ジャケット 121, measured 2026-10-11).

## `queries` (type: `array`):

What you would type into the Uniqlo search box, one term per line (for example jacket, heattech or ウルトラライトダウン). Each term is searched and read separately. A product that two terms both find is returned once, under the first. Leave empty together with 'Only products on sale' to list the whole sale rack; with no terms and that box unticked there is nothing to search for.

## `onlyOnSale` (type: `boolean`):

Keep only products Uniqlo marks down: those carrying its Sale flag (値下げ in Japan) or its Limited-Time Offer flag (期間限定価格). Uniqlo applies this filter itself. With no search terms it lists the entire sale rack (377 products on the US storefront and 455 on Japan when measured on 2026-10-11; it changes through the day).

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

Read at most this many products for each search term (or for the sale rack). Uniqlo serves up to 100 per request and the largest search measured held about 900 products; values above 5000 are not accepted.

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

Apify proxy (automatic datacenter exits) is the default. A refused request (403, 429) is retried from a fresh address, which is what the proxy is for.

## Actor input object example

```json
{
  "region": "us",
  "queries": [
    "jacket"
  ],
  "onlyOnSale": false,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (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 = {
    "queries": [
        "jacket"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/uniqlo-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 = {
    "queries": ["jacket"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/uniqlo-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 '{
  "queries": [
    "jacket"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/uniqlo-products --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/uniqlo-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/tvAGGAUxdlVVe2XAU/builds/jvNKKIF9oh5w3c2AU/openapi.json
