# Trendyol Product Scraper (`khadinakbar/trendyol-product-scraper`) Actor

Scrape public Trendyol products by keyword, category URL, or product URL. Returns prices, ratings, sellers, stock, and images. Cookieless HTTP, MCP-ready.

- **URL**: https://apify.com/khadinakbar/trendyol-product-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** E-commerce, Automation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 product scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Trendyol Product Scraper

Turn a Trendyol keyword, search URL, category URL, or product URL into one dataset row per public product with title, brand, current and original price, discount, rating, review count, seller, stock flags, image URLs, category, and collection time. This workflow is built for marketplace analysts, price-monitoring teams, sourcing researchers, and AI agents that need a bounded Turkey-storefront catalog snapshot they can schedule and compare.

Reviews, Q\&A, and seller emails stay outside this listing-and-detail workflow. Direct product URLs already return the public product page. When enrichDetails is true, the Actor opens the product page for description, attributes, gallery, favoriteCount, and seller name.

### Best fit for this Actor

- Start with a Turkish or English product keyword such as `playstation` when you need ranked Trendyol search cards with TRY prices and ratings.
- Use `maxResults` as the spend cap: each saved product is one `product-scraped` event, plus Apify platform usage. The Console sample uses 1 product so a first run stays bounded.
- Continue with a neighboring marketplace Actor when the same brief needs another storefront after this Trendyol pass.

### Practical scenario

A sourcing analyst pastes `playstation`, keeps `maxResults` at 1, and optionally sets a rating floor. The dataset returns a public card with current and original TRY prices, discount, brand, rating, review count, stock and shipping flags, and the canonical product URL. The team can compare sellers on the same keyword, then schedule the same input to watch price movement. OUTPUT and RUN\_SUMMARY say whether collection finished, stopped at a charge cap, found no matches, or needs a later retry.

### Quick start input

```json
{
  "searchQueries": ["playstation"],
  "maxResults": 1,
  "maxPagesPerQuery": 1,
  "sort": "relevance",
  "enrichDetails": false
}
```

`searchQueries` accepts free-text keywords. Put search, category, or product pages in `startUrls`. `maxResults` defaults to 50 and permits at most 5,000 records across the whole run.

### Input reference

| Field | Type | What it controls |
| --- | --- | --- |
| `searchQueries` | string\[] | Product keywords such as `playstation`. Deduplicated. Put URLs in `startUrls`. |
| `startUrls` | string\[] | Public trendyol.com search (`/sr?q=`), category (`-c{id}`), or product (`-p-{id}`) pages. Seller `/magaza/` pages stay outside this Actor. |
| `maxResults` | integer | Saved-product cap, 1–5,000. Default 50. Prefill 1. This is the billed-row ceiling. |
| `maxPagesPerQuery` | integer | Listing pages per keyword or category URL, 1–50. Default 10. Prefill 1. |
| `sort` | enum | Listing order: `relevance`, `newest`, `price_asc`, `price_desc`, `best_seller`, `most_favorited`, `most_rated`. |
| `minPrice` / `maxPrice` | number | Optional current-price band in listing currency (TRY on the Turkey storefront). |
| `minRating` | number | Optional 0–5 public rating floor. |
| `inStockOnly` / `freeShippingOnly` / `fastDeliveryOnly` / `discountedOnly` | boolean | Optional client-side filters on public listing flags. |
| `enrichDetails` | boolean | When true, fetch each product page for description, attributes, gallery, favoriteCount, and seller name. Adds one `product-enriched` event per enriched row. |
| `proxyConfiguration` | object | Defaults to Apify Residential Turkey. Keep a residential route so public listing HTML is reachable. |

### What data you receive

Each dataset item is one public Trendyol product.

```json
{
  "productId": "800623487",
  "listingId": "example-listing",
  "productUrl": "https://www.trendyol.com/sony/example-p-800623487",
  "title": "Example Wireless Headphones",
  "brand": "ExampleBrand",
  "price": 1299.9,
  "originalPrice": 1599.9,
  "discountPercent": 19,
  "currency": "TRY",
  "rating": 4.7,
  "reviewCount": 1200,
  "sellerName": "Example Seller",
  "inStock": true,
  "freeShipping": true,
  "imageUrl": "https://cdn.dsmcdn.com/example.jpg",
  "sourceType": "search",
  "enriched": false,
  "scrapedAt": "2026-09-15T07:54:00.000Z"
}
```

The default key-value store also contains:

- `OUTPUT` — `outcome`, message, saved count, warnings, and charged event counts.
- `RUN_SUMMARY` — pages fetched, sessions, filters, duplicates, and terminal diagnostics.

`COMPLETE`, `PARTIAL`, `VALID_EMPTY`, and `INVALID_INPUT` finish successfully. `UPSTREAM_FAILED` is the honest terminal state when valid work received no usable marketplace HTML after residential session rotation.

### Use through the API

```bash
curl "https://api.apify.com/v2/acts/khadinakbar~trendyol-product-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries":["playstation"],"maxResults":1}'
```

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('khadinakbar/trendyol-product-scraper').call({
  searchQueries: ['playstation'],
  maxResults: 1,
  minRating: 4.5,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Use with AI agents through Apify MCP

> Search public Trendyol listings for playstation, save at most 1 product, and return title, product URL, current and original TRY price, discount, brand, rating, review count, seller, and collection time. Inspect OUTPUT.outcome before treating an empty dataset as a real no-match.

Tell the agent to keep `maxResults` small on the first call, preserve `productUrl` as provenance, and read `RUN_SUMMARY` when the outcome is `PARTIAL` or needs a later retry. Current MCP client setup: https://mcp.apify.com

### Connect the workflow

After a Trendyol price snapshot, then use [Jumia Product Scraper](https://apify.com/khadinakbar/jumia-product-scraper) when the same brief needs African marketplace prices instead of Turkey catalog cards.

Continue with [AliExpress Product Search Scraper](https://apify.com/khadinakbar/aliexpress-product-search-scraper) when the job is AliExpress listing cards rather than Trendyol search results.

### Pricing

This Actor uses **Pay per event** plus Apify **platform usage**. Open the live Pricing tab for current event names and amounts. `maxResults` is the predictable cap on `product-scraped` events before platform compute and proxy usage. A product is validated before it is persisted and charged, so only accepted rows receive the product event. Detail enrich adds `product-enriched` when `enrichDetails` is true.

### Best results

- Provide Turkish marketplace language when that matches shopper intent (`spor ayakkabi`, `kulaklik`).
- Start with a focused sample (`maxResults` 1–10) and inspect `OUTPUT` before raising the cap.
- Keep Apify Residential Turkey as the default proxy so public listing HTML is reachable.
- Use a category URL ending in `-c` plus a numeric id, or a product URL containing `-p-` plus a numeric id, when you already have a specific catalog path.

### Builder's note

I found that Trendyol listing cards live in `window["__single-search-result__PROPS"].data.products`, while category pretty-URLs leave that array empty until rewritten to `/sr?wc={id}`. I also found that a garbage keyword still returns unrelated cards through `MULTILINGUAL_SEARCH`, so I built the no-match check around resolved-query drift plus token overlap instead of treating any non-empty page as a hit. Seller names usually arrive from the product page, which is why listing rows keep `sellerId` and enrich fills `sellerName`.

### Responsible use

Use this Actor for lawful collection and analysis of public marketplace information. Follow applicable laws and site terms, and keep the workflow on public listing data you are authorized to collect. Trendyol is a trademark of its owner. This independent Actor is not affiliated with, associated with, or endorsed by Trendyol.

# Changelog

This Actor's version history is a separate document: https://apify.com/khadinakbar/trendyol-product-scraper/changelog.md

# Actor input Schema

## `searchQueries` (type: `array`):

Free-text Trendyol searches such as 'playstation' or 'spor ayakkabi'. Each keyword is searched separately and paginated up to maxPagesPerQuery. Defaults to an empty list when you only pass startUrls. NOT a URL — put search, category, or product pages in startUrls.

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

Public trendyol.com URLs. A /sr?q= search or category URL ending in -c{id} is paginated; a product URL containing -p-{id} is one product. Seller /magaza/ pages are rejected. NOT for bare keywords — use searchQueries.

## `maxResults` (type: `integer`):

Hard cap on billed products across all queries and URLs. The run stops when this count is reached. Default 50, max 5000. At $0.003/product, 50 listing rows are about $0.15 plus platform usage. This is the cost ceiling, not Trendyol's catalog size.

## `maxPagesPerQuery` (type: `integer`):

How many listing pages (about 36 products each) to paginate for each keyword or category/search URL. Default 10, max 50. Lower it to sample the first page; raise it for deeper coverage. Bounded again by maxResults.

## `sort` (type: `string`):

Trendyol listing order for keyword and category searches. relevance is the storefront default. newest, price\_asc, price\_desc, best\_seller, most\_favorited, and most\_rated map to Trendyol sst values. Ignored for direct product URLs.

## `minPrice` (type: `number`):

Keep products whose shown current price is at or above this number in the listing currency (TRY on the Turkey storefront). Leave empty for no floor. This is a client-side filter on saved rows, not a Trendyol checkout coupon.

## `maxPrice` (type: `number`):

Keep products whose shown current price is at or below this number in the listing currency. Leave empty for no ceiling. Use with minPrice for a band. Direct product URLs that miss the band are skipped, not billed.

## `minRating` (type: `number`):

Keep products with average Trendyol rating at or above this value, for example 4.5. Leave empty to keep unrated items. Ratings are public listing averages, not a quality guarantee.

## `inStockOnly` (type: `boolean`):

When true, skip products Trendyol marks out of stock. Default false keeps unknown stock. Stock is the public listing flag, not a warehouse API.

## `freeShippingOnly` (type: `boolean`):

When true, keep only products whose listing shows free cargo. Default false. This uses the public freeCargo badge, not a shipping quote.

## `fastDeliveryOnly` (type: `boolean`):

When true, keep only products with a public fast-delivery or rush-delivery badge. Default false. Same-day promises can change after scrape time.

## `discountedOnly` (type: `boolean`):

When true, keep products whose original price is higher than the current price. Default false. Uses listing original vs current, not a coupon code.

## `enrichDetails` (type: `boolean`):

When true, open each product page for description, attributes, gallery, favoriteCount, and seller name. Adds $0.004 per enriched product on top of $0.003 listing. Leave false for fast price/rating cards.

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

Proxy used for all requests. Trendyol is behind Cloudflare, so the Actor defaults to Apify Residential Turkey. Override only with another residential proxy; datacenter IPs return 403 challenge pages.

## Actor input object example

```json
{
  "searchQueries": [
    "playstation",
    "spor ayakkabi"
  ],
  "maxResults": 1,
  "maxPagesPerQuery": 1,
  "sort": "relevance",
  "inStockOnly": false,
  "freeShippingOnly": false,
  "fastDeliveryOnly": false,
  "discountedOnly": false,
  "enrichDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "TR"
  }
}
```

# Actor output Schema

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

Default dataset items: title, brand, price, rating, seller, images, and source URL.

## `summary` (type: `string`):

Compact OUTPUT record with outcome, itemsPushed, chargedEventCounts, and warnings.

## `runSummary` (type: `string`):

Diagnostic RUN\_SUMMARY mirroring OUTPUT plus session and page counters.

# 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 = {
    "searchQueries": [
        "playstation"
    ],
    "maxResults": 1,
    "maxPagesPerQuery": 1,
    "sort": "relevance",
    "inStockOnly": false,
    "freeShippingOnly": false,
    "fastDeliveryOnly": false,
    "discountedOnly": false,
    "enrichDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/trendyol-product-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 = {
    "searchQueries": ["playstation"],
    "maxResults": 1,
    "maxPagesPerQuery": 1,
    "sort": "relevance",
    "inStockOnly": False,
    "freeShippingOnly": False,
    "fastDeliveryOnly": False,
    "discountedOnly": False,
    "enrichDetails": False,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/trendyol-product-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 '{
  "searchQueries": [
    "playstation"
  ],
  "maxResults": 1,
  "maxPagesPerQuery": 1,
  "sort": "relevance",
  "inStockOnly": false,
  "freeShippingOnly": false,
  "fastDeliveryOnly": false,
  "discountedOnly": false,
  "enrichDetails": false
}' |
apify call khadinakbar/trendyol-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/trendyol-product-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/2JMa4nhWhXkGP0tjf/builds/RsNlignu7y9XjwdVb/openapi.json
