# Gap Inc Scraper (Gap, Old Navy, Banana Republic, Athleta) (`crawlerbros/gap-inc-scraper`) Actor

Scrape live product listings across Gap Inc's apparel & home-goods brands - Gap, Gap Factory, Old Navy, Banana Republic, and Athleta. Get prices, sale prices, colors, sizes, images, and ratings via the brands' shared public search API. No login, no cookies, no proxy required.

- **URL**: https://apify.com/crawlerbros/gap-inc-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Gap Inc Scraper (Gap, Old Navy, Banana Republic, Athleta, Gap Factory)

Scrape live product listings across Gap Inc's apparel & home-goods brands — **Gap**, **Gap Factory**, **Old Navy**, **Banana Republic**, and **Athleta**. Get real-time prices, sale prices and discount percentages, available colors and sizes, product images, and customer ratings — all structured and ready to use.

Whether you're tracking prices across Gap Inc's portfolio, building a deals/discount feed, monitoring stock of specific styles, or researching apparel trends, this actor gives you clean, structured access to every brand's live catalog through the same public search endpoint the brands' own websites use.

### Why not Kohl's?

Kohl's (kohls.com) sits behind an Akamai Bot Manager deployment that returns `403 Access Denied` to every non-browser request (confirmed via direct `httpx` and `curl_cffi` chrome131 TLS-impersonation attempts) and is well known to fingerprint/rate-limit even full-browser automation from datacenter IP ranges — reliably clearing it at zero cost would require a residential-proxy hard dependency, which this batch's build rules exclude. Gap Inc's five brand storefronts cover the same department-store apparel/home-goods category, share one clean public JSON API with no bot-wall at all, and are reachable reliably from plain datacenter IPs with zero cost — a materially more reliable target for the same use case.

### What this actor does

- **Five brands, one actor:** switch storefronts with the `brand` input — Old Navy, Gap, Gap Factory, Banana Republic, Athleta
- **US or Canada market** — `market: "ca"` switches to each brand's Canadian storefront (distinct catalog, CAD pricing, `gapcanada.ca` product URLs) for Old Navy, Gap, Banana Republic, and Athleta; Gap Factory has no Canadian storefront and always uses `us`
- **Keyword search** across each brand's live catalog (e.g. `jeans`, `t-shirt`, `dress`, `sneakers`)
- **Department filter** — Women / Men / Girls / Boys / Toddler / Baby / Gender Neutral / Maternity
- **Price range filter** and **on-sale-only** filter
- **Discount-type filter** — restrict to Sale (promo) vs. Clearance (markdown) pricing
- **Color and minimum review score filters** — both applied server-side by the upstream API
- **Additional facet filters (advanced)** — pass through any category-specific upstream facet (`fit=Skinny`, `wash=Light Wash`, `rise=High`, `sleeveLength=Short Sleeve`, `activity=Running`, `occasion=Wedding`, etc.) that the built-in dropdowns don't cover
- **Sort control** — featured (relevance), price, customer rating, biggest discount. Because the upstream API has no working server-side sort, `price`/`reviewScore`/`discount` are sorted client-side over a scanned candidate pool (up to 5× `maxItems`, capped at 500 products)
- **One record per color/SKU** — matches what a shopper actually adds to cart, each with its own price, images, and available sizes
- **No login, no cookies, no proxy required** — reads the brands' shared public search API directly

### Output per product

Every record includes:

- `productId`, `skuId` — the style ID and the specific color/SKU ID
- `name`, `brand`, `colorName` (the color family, e.g. `Blue`), `colorShade` (the specific marketing shade name within that family, e.g. `Navy`, `Medium Wash`, `Licorice` — only present when it differs from `colorName`)
- `effectivePrice`, `regularPrice`, `priceCurrency` (`USD` or `CAD`, per `market`), `percentageOff`, `onSale`, `discountType` (`Promo` / `Markdown` / `Regular`)
- `badges` — marketing badges the site itself shows (e.g. `Best Seller`), where present
- `promoMessage` — the live promo/discount banner copy shown on the tile (e.g. `40% off: limited time`, `Extra 50% off at checkout`), where present
- `videoUrl` — a product video, where the style has one
- `webProductType`, `webProductSubType` — the upstream category taxonomy (e.g. `womens tops`)
- `vendorId` — manufacturer/vendor of record
- `reviewScore`, `reviewCount` — where the style has customer reviews
- `totalSwatchCount` — total number of colors available for the style
- `freeShipping`
- `availableSizes` — sizes currently offered for this color
- `imageUrl` — highest-resolution product image available; `thumbnailUrl` when a distinct thumbnail exists; `imageUrls` — full multi-angle photo gallery (hero shot plus every distinct detail/alternate-view photo) when more than one is available
- `productUrl` / `sourceUrl` — the canonical, directly-loadable product page
- `recordType`, `scrapedAt`

Fields the API doesn't return for a given style (e.g. no review data yet, no distinct thumbnail) are simply omitted — never sent as `null` or `"N/A"`.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `brand` | select | `on` | `on` Old Navy / `gap` Gap / `gapfs` Gap Factory / `br` Banana Republic / `at` Athleta |
| `market` | select | `us` | `us` (USD) / `ca` (CAD, Canadian storefront — not available for Gap Factory, falls back to `us`) |
| `searchQuery` | string | `new` | Free-text keyword. Required — the API has no keyword-less browse endpoint; combine a broad term like `new` with `department` to approximate category browsing |
| `department` | select | – | Women / Men / Girls / Boys / Toddler Girls / Toddler Boys / Baby Girls / Baby Boys / Gender Neutral / Maternity — server-side upstream facet, not re-verified client-side; a small number of cross-listed/adjacent-department items can appear, same as gap.com's own "Refine By" filter |
| `minPrice` / `maxPrice` | integer | – | USD price bounds on the effective (sale) price |
| `onSaleOnly` | boolean | `false` | Only products currently discounted below regular price |
| `priceType` | select | – | `PROMO` (sale) / `MARKDOWN` (clearance) / `REGULAR` (full price, no discount) — upstream discount-tier facet |
| `minReviewScore` | select | – | `1`–`4` (`4` = 4.0★ & up) — upstream review-score facet |
| `color` | select | – | Restrict to a color family (upstream color facet) |
| `additionalFacets` | array of `name=value` strings | – | Advanced: any other upstream facet, e.g. `fit=Skinny`, `wash=Light Wash`. Available facet names/values vary by category — check the "Refine By" sidebar on the matching gap.com/oldnavy.com/etc. site for your search keyword. An unrecognized facet name/value causes the upstream API to reject the whole request (0 records, no crash) rather than being ignored — remove `additionalFacets` first to confirm the base search works, then add facets one at a time |
| `sortBy` | select | `featured` | `featured` / `price` / `reviewScore` / `discount`. Non-`featured` values are sorted client-side (see notes above) — `newest` is not offered since the upstream API has no date-added field |
| `sortDir` | select | `desc` | `asc` / `desc` (ignored when `sortBy=featured`) |
| `maxItems` | integer | 50 | Max records to return (1–2000) |

#### Example: on-sale women's jeans at Old Navy

```json
{
  "brand": "on",
  "searchQuery": "jeans",
  "department": "Women",
  "onSaleOnly": true,
  "maxItems": 50
}
```

#### Example: Gap Canada storefront, price-sorted

```json
{
  "brand": "gap",
  "market": "ca",
  "searchQuery": "sweater",
  "sortBy": "price",
  "sortDir": "asc",
  "maxItems": 50
}
```

#### Example: Athleta clearance items with a minimum review score

```json
{
  "brand": "at",
  "searchQuery": "leggings",
  "priceType": "MARKDOWN",
  "minReviewScore": "4",
  "maxItems": 30
}
```

#### Example: advanced facet filter (skinny-fit, light-wash jeans)

```json
{
  "brand": "on",
  "searchQuery": "jeans",
  "additionalFacets": ["fit=Skinny", "wash=Light Wash"],
  "maxItems": 30
}
```

### Use cases

- **Price monitoring** — track effective prices, discount percentages, and promo messages across Gap Inc's brand portfolio over time
- **Deals & discount feeds** — filter `onSaleOnly` / `priceType` to build a live markdown/clearance feed
- **Competitive retail research** — compare pricing, sizing, and catalog breadth across Old Navy, Gap, Banana Republic, Athleta, and Gap Factory
- **Merchandising & assortment analysis** — pull `webProductType`/`webProductSubType` taxonomy and color/size availability by department
- **Cross-border pricing analysis** — compare US (USD) vs. Canada (CAD) pricing for the same styles via `market`
- **Review/rating aggregation** — collect `reviewScore`/`reviewCount` across a category to spot top-rated styles

### FAQ

**Does this actor need cookies, login, or a proxy?**
No. It reads the same public JSON search API (`api.gap.com/commerce/search/v2/product_listings`) that each brand's website calls client-side. No authentication or proxy configuration is required.

**Why is there one record per color instead of one per product?**
Each color is effectively a distinct purchasable item with its own price, images, and sizes on Gap Inc's sites — the same way you'd navigate to it on the storefront. `productId` is shared across all colors of the same style if you want to group them back together.

**Can I browse a whole department without a search term?**
The upstream API requires a non-empty keyword. Use a broad term such as `new`, `sale`, or a common noun (`tee`, `dress`, `jean`) together with the `department` filter to approximate a category browse.

**Which currency are prices in?**
USD by default (`market: "us"`). Set `market: "ca"` to query each brand's Canadian storefront instead — a distinct catalog with CAD pricing and `gapcanada.ca` product URLs. Gap Factory has no Canadian storefront, so `market: "ca"` with `brand: "gapfs"` automatically falls back to `us` (logged as a warning).

**What happens if my `searchQuery` doesn't match any product?**
For most unmatched or obscure keywords, the upstream API returns zero products and the actor reports 0 records with a clear status message. For a small number of very generic or nonsense keywords, Gap Inc's search API itself silently falls back to a broad, unfiltered catalog listing instead of returning zero results (you can reproduce this by querying `api.gap.com/commerce/search/v2/product_listings` directly) — this is upstream search behavior, not something the actor can reliably detect or override, since the API gives no signal distinguishing a true match from a fallback listing.

# Actor input Schema

## `brand` (type: `string`):

Which Gap Inc storefront to search.

## `market` (type: `string`):

Which country storefront to query. `ca` (Canada) returns a distinct catalog/pricing (CAD) and is available for Old Navy, Gap, Banana Republic, and Athleta; Gap Factory has no Canadian storefront and always falls back to `us` (a warning is logged).

## `searchQuery` (type: `string`):

Free-text keyword, e.g. `jeans`, `t-shirt`, `dress`. Required — the upstream API has no keyword-less browse endpoint. Use a broad term like `new` combined with the `department` filter to approximate category browsing. Note: the upstream search API does fuzzy/recommendation-based matching, not strict filtering — English apparel terms (`jeans`, `dress`) match well, but misspelled, non-English, or nonsense keywords may fall back to generic trending products for that brand rather than returning zero results.

## `department` (type: `string`):

Filter to a department/demographic (server-side upstream facet, not re-verified client-side). Overwhelmingly accurate, but the upstream search API occasionally includes a small number of cross-listed/adjacent-department items (e.g. a men's item appearing in a Women-filtered result) the same way gap.com's own "Refine By" department filter does. Leave empty for all.

## `minPrice` (type: `integer`):

Only include products whose lowest sale price is at least this amount.

## `maxPrice` (type: `integer`):

Only include products whose lowest sale price is at most this amount.

## `onSaleOnly` (type: `boolean`):

Only include products currently discounted below their regular price.

## `priceType` (type: `string`):

Restrict results to a specific discount tier (server-side filter, upstream facet). Leave empty for all products.

## `minReviewScore` (type: `string`):

Only include products with at least this average review rating (server-side filter, upstream facet). Leave empty for all products.

## `color` (type: `string`):

Restrict results to a color family (server-side filter, upstream facet). Leave empty for all colors.

## `additionalFacets` (type: `array`):

Extra upstream search facets as `name=value` strings, e.g. `fit=Skinny`, `wash=Light Wash`, `rise=High`, `sleeveLength=Short Sleeve`, `activity=Running`, `occasion=Wedding`. The available facet names/values vary by category and search keyword — run without this first, then check the "Refine By" filter sidebar on the matching gap.com/oldnavy.com/etc. site for the exact facet names for your keyword.

## `sortBy` (type: `string`):

Result ordering. `price` is a genuine server-side sort (verified monotonic across the full paginated catalog) so it covers every matching product, not just a sample. `reviewScore`/`discount` have no working server-side equivalent, so those are applied client-side over a scanned candidate pool (up to 5x `maxItems`, capped at 500) instead. `newest` is not offered — the upstream API exposes no reliable date-added field to sort on.

## `sortDir` (type: `string`):

Ascending or descending. Ignored when sortBy=featured.

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

Hard cap on emitted product records.

## Actor input object example

```json
{
  "brand": "on",
  "market": "us",
  "searchQuery": "new",
  "department": "",
  "onSaleOnly": false,
  "priceType": "",
  "minReviewScore": "",
  "color": "",
  "additionalFacets": [],
  "sortBy": "featured",
  "sortDir": "desc",
  "maxItems": 50
}
```

# Actor output Schema

## `products` (type: `string`):

Dataset containing all scraped products.

# 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 = {
    "brand": "on",
    "market": "us",
    "searchQuery": "new",
    "department": "",
    "onSaleOnly": false,
    "priceType": "",
    "minReviewScore": "",
    "color": "",
    "additionalFacets": [],
    "sortBy": "featured",
    "sortDir": "desc",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/gap-inc-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 = {
    "brand": "on",
    "market": "us",
    "searchQuery": "new",
    "department": "",
    "onSaleOnly": False,
    "priceType": "",
    "minReviewScore": "",
    "color": "",
    "additionalFacets": [],
    "sortBy": "featured",
    "sortDir": "desc",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/gap-inc-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 '{
  "brand": "on",
  "market": "us",
  "searchQuery": "new",
  "department": "",
  "onSaleOnly": false,
  "priceType": "",
  "minReviewScore": "",
  "color": "",
  "additionalFacets": [],
  "sortBy": "featured",
  "sortDir": "desc",
  "maxItems": 50
}' |
apify call crawlerbros/gap-inc-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HsGXdJ5PQFDAIbP19/builds/1rDBlEggQTgBaZh6h/openapi.json
