# Target Scraper - Products, Prices, Stock & Reviews (`dami_studio/target-scraper`) Actor

Target scraper for target.com searches or Target links. Each row has the TCIN, title, brand, price and markdown, promotions, star rating, review count, shipping and pickup stock, images and link. Unrelated results for a term Target does not stock are dropped, not billed. $0.78 per 1,000 products.

- **URL**: https://apify.com/dami_studio/target-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 14 total users, 8 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 1,000 products

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

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

**Target scraper for a target.com search or a Target link, one row per product**: TCIN, title, brand,
today's price and any markdown, promotions, star rating and review count, whether it ships, whether
a nearby store has it for pickup, the images and the link.

A postcode sets the pickup store, but on every test run checked the price still came from Target's
online store (`pricedAtStoreId` 3991). And any one search or category stops at 1,227 products, which
is Target's own limit.

| | |
|---|---|
| **Input** | Search terms, or Target search, category, brand or product links |
| **Output** | One row per product: price and markdown, promotions, rating, review count, shipping and pickup stock, images, link |
| **Ceiling** | 2,000 products per run, and 1,227 per search or category |
| **Account needed** | None |
| **Price** | $0.78 per 1,000 products on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 6,400 |

### 🔍 What Target.com Product Scraper does

Each search term is run separately and every product it returns becomes a row. Category and brand
links work the same way, and pasted product links are fetched first, so a broad category can never
use up `maxItems` before the products you named.

Target never answers a search with "no matches". Ask for something it does not stock and it returns
a page of 28 products that have nothing to do with the question. So the first page of every keyword
search is checked against the words you typed, and if almost none of the titles mention them, you
get one free `NO_MATCH` note instead of 28 charges. The check was tuned on 66 real shopping terms,
none of which it rejected, including "bed sheets", where every product is titled "Sheet Set". It is
loose in the other direction on purpose: dropping a real result is worse than letting a weak one
through. Category and brand links skip the check.

Without a postcode you get Target's online view: shipping status, sold-out flags, delivery status and
a ship-by date, with the pickup fields left null. Add a postcode and the nearest store's pickup
status, name and unit count fill in. Three hundred products took 18 seconds on a test run.

### 📋 What data you get from each Target product

| What you get | Field |
|---|---|
| TCIN, title, brand and link | `tcin`, `title`, `brand`, `url` |
| Price, markdown and savings | `price`, `formattedPrice`, `regularPrice`, `comparisonPrice`, `onSale`, `savingsAmount`, `savingsPercent`, `priceType`, `priceNote` |
| Unit price on grocery and household items | `unitPrice`, `unitPriceSuffix` |
| Which store the price is for | `pricedAtStoreId` |
| Promotions | `promotions` |
| Star rating and review count | `rating`, `reviewCount` |
| Online and delivery stock | `onlineAvailability`, `soldOut`, `outOfStockInAllStores`, `scheduledDeliveryAvailability`, `shipsBy` |
| Pickup stock at the store nearest your postcode | `pickupAvailability`, `pickupStoreId`, `pickupStoreName`, `pickupQuantity` |
| Images | `primaryImage`, `images` |
| Shelf number, barcode and Target's classification | `dpci`, `upc`, `itemType`, `departmentId`, `classId`, `categoryId` |
| Product page bullets and specs | `highlights`, `specifications` |
| With full detail: the long description and the count at each star | `description`, `ratingDistribution` |
| Which search found it, and where | `searchTerm`, `position` |

### ▶️ How to scrape Target products

1. Open [Target.com Product Scraper](https://apify.com/dami_studio/target-scraper) and click **Try
   for free**.
2. Type what you want into **Search terms**, or paste pages into **Target URLs**.
3. Set **Maximum products**.
4. For pickup stock at a store, fill in **US postcode (optional)**.
5. Click **Start**, then download the dataset as JSON, CSV or Excel.

The sample row appears only when a run has no search terms and no links. It is not charged.

### 💰 How much does it cost to scrape Target products?

**$0.78 per 1,000 products** on the Free plan. Paid plans pay a little less: $0.77 on Starter, $0.76 on Scale and $0.75 on Business. Stock and full detail cost
nothing extra. On the free plan, the $5 Apify gives you each month covers about 6,400 products.

Not charged: the sample row, every note listed further down, the unrelated products behind a
`NO_MATCH`, and a product that turns up under two searches, which is delivered once. If you set a
maximum cost for the run, it stops there and says so in its status.

### 📥 What you give it

```json
{
  "searchTerms": ["air fryer"],
  "zipCode": "55403",
  "maxItems": 12
}
```

| Field | Default | What it is |
|---|---|---|
| `searchTerms` | none | What to look up, one per line, such as `air fryer` or `paper towels`. |
| `startUrls` | none | Target search pages, category and brand pages (`/-/N-5xtg6`) and product pages (`/-/A-92084780`), mixed freely. Product links always come back with the full description. |
| `maxItems` | `50` | 1 to 2,000 products across everything above. You pay per product, so this bounds the bill. |
| `zipCode` | none | A five-digit US postcode. Sets the store for pickup stock. |
| `includeAvailability` | `true` | Whether each product ships, is sold out and, with a postcode, is on the shelf for pickup. |
| `includeFullDetail` | `false` | Adds the long description, the barcode and the star-by-star review count. A large run takes noticeably longer with it on. |
| `proxyConfiguration` | none | Only for your own servers, which are used as given. Leave it alone otherwise. |

A category link is a node id: in `target.com/c/anything/-/N-5xtg6`, the `5xtg6` is what matters.

### 📤 What you get back

A real row from a run on 20 September 2026 with postcode 55403, with the image, highlight and
specification lists cut short:

```json
{
  "tcin": "92084780",
  "title": "Gourmia Digital 3qt Air Fryer with Guided Cooking Prompts Black/Stainless Steel Finish",
  "brand": "Gourmia",
  "url": "https://www.target.com/p/digital-3qt-air-fryer-with-guided-cooking-prompts-black-stainless-steel-finish/-/A-92084780",
  "price": 39.99,
  "formattedPrice": "$39.99",
  "regularPrice": 39.99,
  "comparisonPrice": null,
  "onSale": false,
  "savingsAmount": null,
  "savingsPercent": null,
  "unitPrice": null,
  "unitPriceSuffix": null,
  "priceType": "reg",
  "priceNote": null,
  "pricedAtStoreId": "3991",
  "promotions": [],
  "rating": 4.18,
  "reviewCount": 471,
  "onlineAvailability": "IN_STOCK",
  "soldOut": false,
  "outOfStockInAllStores": false,
  "pickupAvailability": "IN_STOCK",
  "pickupStoreId": "1375",
  "pickupStoreName": "Mpls Nicollet Mall",
  "pickupQuantity": 6,
  "scheduledDeliveryAvailability": "IN_STOCK",
  "shipsBy": "2026-09-21",
  "primaryImage": "https://target.scene7.com/is/image/Target/GUEST_6ec22cbf-b531-4468-86ce-f0194548211b",
  "images": ["https://target.scene7.com/is/image/Target/GUEST_6ec22cbf-b531-4468-86ce-f0194548211b"],
  "dpci": "072-04-6561",
  "upc": null,
  "itemType": "Electric Fryers",
  "departmentId": "72",
  "classId": "4",
  "categoryId": "ncrpx",
  "highlights": [
    "3-quart air fryer can cook for one or a few",
    "8 One-Touch Cooking Functions eliminate guesswork"
  ],
  "specifications": [
    "Dimensions (Overall): 10.47 Inches (H) x 11.46 Inches (W) x 8.98 Inches (D)",
    "Capacity (Volume): 3 Quart"
  ],
  "description": null,
  "ratingDistribution": null,
  "searchTerm": "air fryer",
  "position": 1,
  "scrapedAt": "2026-09-20T00:46:59.705Z"
}
```

A marked-down product from another real run, price fields only:

```json
{
  "tcin": "94986645",
  "price": 99.99,
  "regularPrice": 99.99,
  "comparisonPrice": 159.99,
  "onSale": true,
  "savingsAmount": 60,
  "savingsPercent": 38
}
```

| Field | How to read it |
|---|---|
| `tcin` | Target's product number, the digits after `A-` in a product link. Stable, so use it to join runs. |
| `price`, `regularPrice`, `comparisonPrice`, `onSale` | On a markdown, the old price is in `comparisonPrice` and `regularPrice` equals the current one. Read `onSale` first. |
| `unitPrice`, `unitPriceSuffix` | Grocery and household items, such as `$0.36` and `/ounce`. |
| `pricedAtStoreId` | Which store the price is for. `3991` is Target's online store. |
| `promotions` | Each with `message`, `promotionId`, `type`, `thresholdType`, `thresholdValue`, `rewardType` and `rewardValue`. |
| `pickupQuantity` | Needs a postcode, and can be null while the status says in stock; `pickupAvailability` is the reliable one. |
| `upc`, `description`, `ratingDistribution` | Need full detail or a pasted product link. |

### 🧾 Reading the output

Real product rows have no `charged` field. The free rows carry `charged: false`, so dropping those
leaves only products.

| Row | How to spot it | Billed |
|---|---|---|
| A product | A `tcin` and no `charged` field | yes |
| The sample | `_sample: true` and `charged: false` | no |
| A note | `_diagnostic: true`, `charged: false`, with an `errorCode`, an `error` and a `hint` | no |

The sample looks like a real product row, so filter on `_sample` or `charged` rather than on the
fields.

| `errorCode` | What it means |
|---|---|
| `NO_MATCH` | Target stocks nothing for that term and answered with unrelated products, which were left out. The note carries a `relevance` score. |
| `NO_RESULTS` | Target returned no products for that term or link. |
| `NOT_FOUND` | No product behind that TCIN. They change when Target merges or retires a listing. |
| `BAD_URL` | Not a Target search, category, brand or product link. |
| `ZIP_NOT_FOUND` | No store near that postcode. The run carries on with online prices. |
| `LIMIT_REACHED` | `maxItems` was used up before that search or those links, so they were not fetched. |
|`TARGET_UNREACHABLE`, `FAILED` | Target did not answer that part of the run. Re-running usually clears it. |
| `NOT_SERVED` | This product was not served this run. Re-run it later. Runs before 13 October 2026 wrote `BLOCKED` here. |
| `TIME_LIMIT` | The run got close to its time limit and stopped on its own. The products delivered before that are complete and charged. Give the run more time, or ask for fewer products, to get the rest. |

A note never fails the run, `TIME_LIMIT` included: a run the time limit stopped before any product came back still ends as succeeded, with an amber status message.

### 💡 What people use it for

- Watching a fixed list of products. Paste their links, schedule the run, and the rows line up on
  `tcin` from one run to the next.
- Catching markdowns across a category, using `onSale` and `comparisonPrice`.
- Checking whether one store has an item on the shelf before driving there.
- Pulling DPCI, UPC and Target's classification for a product list.

### 🚧 What it does not do

- **No review text.** The star average, the review count and, with full detail, the count at each
  star.
- **Pickup stock for one store only,** the nearest to your postcode. Checking forty stores is a
  different job.
- **No store-level prices, as far as testing shows.** `pricedAtStoreId` read 3991 on every row of
  every test run checked, with a postcode or without.
- **No variants as rows.** A shirt in six colours is one row, the one Target shows in the listing.
- **Nothing behind a sign-in.** No Circle member pricing, no order history.
- **target.com only.** Target Australia is a different company.
- **No sponsored placements.** Paid slots in the results are skipped, so this is the wrong tool for
  studying ads.
- **Prices move.** A row is what target.com showed at `scrapedAt`.
- It is not an official Target tool. Dami's Studio is independent and is not affiliated with or endorsed by Target, or by any other company named on this page.

### 🧭 Which retail scraper do you need?

| If you want | Use |
|---|---|
| Target products with promotions and pickup stock | This one |
| Lowe's products with store price, stock and specs | [Lowe's Product Scraper](https://apify.com/dami_studio/lowes-scraper) |
| Amazon products by keyword or ASIN, with the on-page reviews | [Amazon Scraper](https://apify.com/dami_studio/amazon-scraper) |
| A Shopify store's whole catalogue | [Shopify Products Scraper](https://apify.com/dami_studio/shopify-products-scraper) |
| Restock and price-drop alerts on stores that publish product data, such as Shopify or WooCommerce shops | [Product Price & Stock Monitor](https://apify.com/dami_studio/structured-product-price-stock-monitor) |

### ❓ Questions people ask

#### Do I need a Target account or an API key?

No. Nothing is signed in and there is no key to get.

#### Can I scrape a whole Target category?

Up to 1,227 products of it, which is Target's own ceiling. For more, search the sub-categories
separately.

#### Why did my search give a note instead of products?

Target had nothing matching and answered with unrelated items, so they were left out rather than
billed. If you think that was wrong, a category or brand link fetches the products with no check.

#### What is a TCIN, and what is a DPCI?

The TCIN is Target's product number online and the one to join on. The DPCI is its shelf number in
stores.

#### Why is pickupQuantity null when the item is in stock?

Target does not publish a unit count for every item. Trust `pickupAvailability`.

#### Can I call it from code or connect it to an AI assistant?

The [API tab](https://apify.com/dami_studio/target-scraper/api/python) has code for Python, JavaScript and the CLI.
MCP clients like Claude and ChatGPT use `https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/target-scraper`;
coding assistants can load [our skill
file](https://api.apify.com/v2/key-value-stores/BTBHU3DdiuoF4JOsK/records/apify-ecommerce-SKILL.md). All three bill
your Apify account at the same price.

#### Is scraping Target legal?

It reads what target.com shows anyone who is not signed in. Apify's write-up on
[the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) is a good starting
point, and we are not lawyers.

### 🆘 If something breaks

Open the **Issues** tab on the actor page and send the input you used and the run ID; the note rows
in the dataset usually name the reason already.

# Actor input Schema

## `searchTerms` (type: `array`):

What to look up on target.com, one per line — "air fryer", "lego", "paper towels". Each term is searched separately and every product it returns becomes a row.

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

Paste Target pages instead of typing terms. Search pages (https://www.target.com/s?searchTerm=air+fryer), category and brand pages (…/-/N-5xtg6) and single product pages (…/-/A-92084780) all work, mixed together. Product links always come back with the full description.

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

Hard cap on products returned across everything above. You pay per product, so this is what bounds the bill. Target stops any one search or category at 1,227 products.

## `zipCode` (type: `string`):

A five-digit US postcode, for example 55403. It picks the nearest Target store for pickup stock. It does not change the price: on every test run with a postcode, prices still came from Target's online store (pricedAtStoreId 3991). Leave it empty if you do not need pickup stock.

## `includeAvailability` (type: `boolean`):

Look up whether each product ships, is sold out, and — when a postcode is set — whether it is on the shelf for pickup. Costs one extra request per 30 products.

## `includeFullDetail` (type: `boolean`):

Fetch each product's own page data for the long description and the star-by-star review breakdown. This is one extra request per product, so a 500-product run takes noticeably longer. Product links pasted into "Target URLs" always get this regardless.

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

Optional. Leave this alone unless you need the run to go out through a particular network. Your own proxy servers are used exactly as given.

## Actor input object example

```json
{
  "searchTerms": [
    "air fryer"
  ],
  "startUrls": [],
  "maxItems": 50,
  "includeAvailability": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One dataset row per Target product: TCIN, title, brand, URL, current and regular price, sale flags and unit price, promotions, star rating and review count, shipping and pickup stock, images, DPCI, UPC, item type and category ids, and the on-page highlight and specification bullets. Empty input, an unrecognised URL or a search that returns nothing writes an uncharged sample or diagnostic row instead.

# 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 = {
    "searchTerms": [
        "air fryer"
    ],
    "startUrls": [],
    "maxItems": 50,
    "zipCode": "",
    "includeAvailability": true,
    "includeFullDetail": false,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/target-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 = {
    "searchTerms": ["air fryer"],
    "startUrls": [],
    "maxItems": 50,
    "zipCode": "",
    "includeAvailability": True,
    "includeFullDetail": False,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/target-scraper").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 '{
  "searchTerms": [
    "air fryer"
  ],
  "startUrls": [],
  "maxItems": 50,
  "zipCode": "",
  "includeAvailability": true,
  "includeFullDetail": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call dami_studio/target-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/target-scraper"
        }
    }
}
```

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/SqwCZ7MQmk9vThiwK/builds/ZaoEjaLRis0immbPp/openapi.json
