# Trendyol $0.8💰 URL | Keyword | Review Scraper (`abotapi/trendyol-scraper`) Actor

From $0.8/1K. Pull structured product data, ratings, badges, seller info, full reviews, and Q\&A from trendyol.com. Search by keyword with filters, use any URL (search, category, store, product), or run reviews-only mode on a product list.

- **URL**: https://apify.com/abotapi/trendyol-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Developer tools, Automation
- **Stats:** 49 total users, 5 monthly users, 81.1% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.80 / 1,000 results

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?

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

## Trendyol Product Scraper, Reviews & Q\&A

Pull structured product data, ratings, badges, seller details, full review streams and Q\&A pairs from Trendyol, Turkey's largest online marketplace. Search by keyword with rich filters, paste any Trendyol URL (search, category, store or product page), or run reviews-only mode against a list of products. ~50 normalized fields per product, low compute footprint (runs comfortably under 256 MB), and granular per-event pricing so reviews-only runs stay cheap.

### Why this scraper

- Browse Trendyol's **own campaign tiers** — Red / Orange / Yellow (deepest-to-lightest discount, the site's own color-coded merchandising taxonomy) plus the rotating **Flash sale** pool — as a first-class picker in search mode, combinable with a keyword for the color tiers. Every product gets a real `isOnSpecial` + `savingsAmount` derived straight from the site's own strikethrough price, never fabricated.
- Three modes in one actor: keyword **search**, paste-any-URL, or **reviews-only** (one row per review).
- \~30 lean fields by default; **opt into `fetchDetails=true` for ~60 fields per product** including the full attribute spec list, merchant info (name, official name, city, seller score, logo), category tree, web brand, favorite count, max installment, tax %, refundable flag, department / merchandising unit, English category translations, full promotion list, winner variant with barcode + stock + tag details. URL-mode product pages always emit the rich shape.
- Filters that round-trip to the site: price range, minimum rating, sort (best match / best seller / newest / price asc / desc / most rated / most favourited), free shipping, fast delivery, official seller, coupons, in stock.
- Auto-detects all four Trendyol page shapes when you paste URLs: search results, category, seller store, single product.
- Reviews mode paginates the public review feed up to your configured cap, with rate, comment, reviewer name, language, mediaFiles, likes count and timestamps.
- Lower price than the leading alternative actor in the Apify Store: full product records are billed per result; reviews are billed per row at a fraction of the per-product rate.

### Modes at a glance

| Mode | What it takes | What you get |
|---|---|---|
| `search` | One or more keywords plus optional filters | Product records (one row each) |
| `url` | Any Trendyol URL (search, category, store, or single product) | Product records (one row each) |
| `reviews` | A list of product URLs or numeric content IDs | Review records (one row per review) |

### Data you get (product record)

> Sample shape, values are illustrative placeholders, not from a live listing.

| Field | Example | Notes |
|---|---|---|
| `kind` | `"product"` | Always `"product"` for product rows |
| `contentId` | `100000001` | Stable Trendyol product ID |
| `id` | `100000001` | Listing variant ID (often equal to contentId) |
| `groupId` | `100000000` | Product group ID; same group means same product, different colours |
| `url` | `"https://www.trendyol.com/sample-brand/sample-product-p-100000001"` | Direct URL to the product page |
| `name` | `"Sample Product Title"` | Listing title |
| `brand` | `"Sample Brand"` | Display brand name |
| `brandId` | `1000` | Numeric brand ID |
| `category.id` | `1000` | Category ID |
| `category.name` | `"Sample Category"` | Category display name |
| `price.current` | `0.00` | Discounted / current price |
| `price.original` | `0.00` | Strikethrough price (recommended retail) |
| `price.discountPercent` | `0.0` | Computed discount percentage |
| `price.currency` | `"TL"` | Storefront currency |
| `rating.score` | `0.0` | Average rating (0 to 5) |
| `rating.totalRatings` | `0` | Total rating count (only when `fetchReviews=true`) |
| `rating.totalComments` | `0` | Total written reviews (only when `fetchReviews=true`) |
| `rating.breakdown` | `{"5": 0, "4": 0, "3": 0, "2": 0, "1": 0}` | Rating bucket counts (only when `fetchReviews=true`) |
| `seller.id` | `100000` | Merchant ID |
| `seller.name` | `"Sample Seller"` | Merchant / store display name |
| `image` | `"https://cdn.dsmcdn.com/.../000000000-800x600.jpeg"` | Primary thumbnail |
| `images` | `["https://cdn.dsmcdn.com/.../000000000-800x600.jpeg"]` | Image gallery |
| `stock` | `0` | Reported stock count |
| `inStock` | `true` | Convenience boolean derived from stock |
| `freeCargo` | `false` | Free shipping flag |
| `fastDelivery` | `false` | Fast-delivery badge |
| `officialSeller` | `false` | Verified official seller badge |
| `sameDayShipping` | `false` | Same-day shipping flag |
| `rushDelivery` | `false` | Rush-delivery flag |
| `hasCoupon` | `false` | Collectable coupon at checkout |
| `hasCodePromo` | `false` | Promo-code applies |
| `hasFlashSale` | `false` | Flash-sale badge |
| `isOnSpecial` | `false` | Real strikethrough discount on this card (`price.original > price.current`), never fabricated |
| `savingsAmount` | `null` | `price.original − price.current` when `isOnSpecial`, else `null` |
| `specialsCategory` | `null` | Echoes the `specialsCategory` input value when the record came from the specials picker, else `null` |
| `isInfluencerPreferred` | `false` | Influencer-preferred label |
| `dealBadge` | `null` | Deal label string (when present) |
| `stripBadge` | `null` | Strip badge label (when present) |
| `promotions` | `[]` | Raw promotion objects |
| `stamps` | `[]` | Raw stamp objects |
| `badges` | `[]` | Raw simplified-badge objects |
| `socialProof` | `{}` | Raw socialProof block from the SERP |
| `variantId` | `0` | Variant ID (size / colour) |
| `variantValue` | `""` | Variant display value |
| `boutiqueId` | `0` | Boutique ID |
| `campaignId` | `0` | Campaign ID |
| `listingId` | `""` | Internal listing handle |
| `itemNumber` | `0` | Item number |
| `reviews` | `[]` | Embedded review array (only when `fetchReviews=true`) |
| `qna` | `[]` | Q\&A entries (only when `fetchQna=true`) |
| `scrapedAt` | `"2026-01-01T00:00:00.000Z"` | ISO timestamp |
| `changeType` | `"NEW"` | Only present when `incrementalMode=true`: one of `NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED`, `EXPIRED` |
| `changedFields` | `[]` | Only present when `incrementalMode=true`: names of the fields that changed vs. the last run (`UPDATED` only) |
| `firstSeenAt` | `"2026-01-01T00:00:00Z"` | Only present when `incrementalMode=true`: when this product was first tracked under this state key |
| `lastSeenAt` | `"2026-01-01T00:00:00Z"` | Only present when `incrementalMode=true`: when this product was last seen |

### Extra fields when `fetchDetails=true` or URL is a product page

> Sample shape, values are illustrative placeholders.

| Field | Example | Notes |
|---|---|---|
| `productCode` | `"AB-0000-X"` | Internal SKU code |
| `productGroupId` | `100000000` | Product group ID (variants share this) |
| `isGlobalBrand` | `false` | Global-brand flag |
| `webBrand` | `{ "id": 1000, "name": "Sample Brand", "url": "/sample-brand-x-b1000" }` | Web brand block |
| `gender` | `{ "id": 1, "name": "" }` | Gender ID |
| `webCategory` | `{ "id": 100000, "name": "Sample Category" }` | Detail-level category |
| `webCategoryTree` | `[{ "id": 1, "name": "...", "level": 1 }]` | 4-level category tree (for breadcrumbs) |
| `categoryTree` | `[{ "id": 1, "name": "...", "parent": 0 }]` | Internal category graph |
| `categoryHierarchy` | `"Top/Sub/Leaf"` | Path string |
| `categoryTopRankings` | `[{ "name": "bestSeller", "order": 1 }]` | Category-level rankings |
| `businessUnit` | `{ "id": 100000, "name": "Sample Unit", "isDigitalGoods": false }` | Trendyol's internal merchandising group |
| `attributes` | `[{ "key": { "id": 0, "name": "Color" }, "value": { "id": 0, "name": "Red" }, "searchable": true, "isStarred": true }]` | Full spec list (varies by category) |
| `favoriteCount` | `0` | Site-wide favorite count |
| `tax` | `0` | Tax rate (%) |
| `maxInstallment` | `0` | Max installments allowed at checkout |
| `isRefundable` | `true` | Refund eligibility |
| `uxLayout` | `"Sample Layout"` | UI variant flag |
| `filterableLabelIds` | `["00000000-0000-0000-0000-000000000000"]` | Internal label UUIDs |
| `englishTranslation` | `{ "productName": "...", "brandName": "...", "webBrandCategoryGenders": {} }` | English category + brand mapping |
| `merchantDetails.id` | `100000` | Merchant ID |
| `merchantDetails.name` | `"Sample Seller"` | Display name |
| `merchantDetails.officialName` | `"Sample Seller LTD"` | Registered legal name |
| `merchantDetails.taxNumber` | `"0000000000"` | Tax / VKN identifier |
| `merchantDetails.registeredEmailAddress` | `"sample@hs01.kep.tr"` | KEP (registered electronic mail) address |
| `merchantDetails.cityName` | `"İstanbul"` | Merchant city |
| `merchantDetails.countryName` | `"TÜRKİYE"` | Merchant country |
| `merchantDetails.sellerScore` | `{ "value": 0.0, "color": "#000000" }` | Trust score |
| `merchantDetails.corporateInvoiceApplicable` | `false` | Corporate invoicing supported |
| `merchantDetails.logoUrl` | `"https://cdn.dsmcdn.com/seller-store/uploads/100000/sample.jpeg"` | Merchant logo |
| `merchantDetails.codEligible` | `false` | Cash-on-delivery enabled |
| `merchantDetails.stickerIds` | `[0, 0]` | Sticker IDs |
| `merchantDetails.*` | — | Plus any additional keys Trendyol exposes on the merchant object (forwarded verbatim) |
| `campaign` | `{ "id": 0, "name": "Sample Campaign", "startDate": "2026-01-01T00:00:00", "endDate": "2026-12-31T00:00:00", "stockTypeId": 0 }` | Campaign metadata |
| `detailPromotions` | `[{ "id": 0, "name": "Sample Promo", "discountType": 0, "promotionDiscountType": "Cargo", "isApplied": true, "promotionEndDate": "2026-12-31T00:00:00" }]` | Per-promotion detail |
| `winnerVariant.itemNumber` | `0` | Winning variant's item number |
| `winnerVariant.listingId` | `"00000000000000000000000000000000"` | Internal listing handle |
| `winnerVariant.barcode` | `"0000000000000"` | Product barcode |
| `winnerVariant.quantity` | `0` | Stock quantity |
| `winnerVariant.maxSaleLimit` | `0` | Max units per order |
| `winnerVariant.rushDeliveryDuration` | `0` | Rush delivery hours |
| `winnerVariant.tagDetails` | `[{ "tag_id": 0, "tag": "...", "display_name": "...", "searchable": true }]` | Promotional tags |

### Data you get (review record, reviews mode)

> Sample shape, values are illustrative placeholders, not from a live listing.

| Field | Example | Notes |
|---|---|---|
| `kind` | `"review"` | Always `"review"` for review rows |
| `id` | `400000000` | Review ID |
| `productContentId` | `100000001` | Parent product content ID |
| `productUrl` | `"https://www.trendyol.com/.../sample-product-p-100000001"` | Parent product URL |
| `rate` | `0` | 1 to 5 |
| `comment` | `"Sample review text appears here."` | Review body |
| `userFullName` | `"**** ****"` | Reviewer (Trendyol redacts most names) |
| `isElite` | `false` | Trendyol Elite badge |
| `isInfluencer` | `false` | Influencer flag |
| `likesCount` | `0` | Helpfulness votes |
| `language` | `"tr"` | Review language |
| `createdAt` | `1700000000` | Unix epoch (ms) |
| `mediaFiles` | `[]` | Photos / videos attached |
| `scrapedAt` | `"2026-01-01T00:00:00.000Z"` | ISO timestamp |

### Specials / campaign tiers

Trendyol runs its own perpetual discount program with a color-coded severity taxonomy: **Red** (kırmızı kampanya — deepest cuts), **Orange** (turuncu kampanya), **Yellow** (sarı kampanya), plus a separate **Flash sale** pool that rotates hourly. Pick one with the `specialsCategory` input:

- `red-deals` / `orange-deals` / `yellow-deals` — combine freely with a keyword, price range and sort, same as a plain search (they're the site's own `tag=` facet on the ordinary search endpoint).
- `flash-sale` — a curated, rotating pool (the site itself resolves "what's on flash sale right now"); browse-only, does not combine with a keyword.
- Reachable in **URL mode** too with zero extra setup: paste `https://www.trendyol.com/sr?tag=kirmizi_kampanya_urunu` (or `turuncu_kampanya_urunu` / `sari_kampanya_urunu`) or `https://www.trendyol.com/flas-indirimler`.

Not every item in a campaign tier carries an actual markdown (some are simply featured) — `isOnSpecial`/`savingsAmount` reflect the real per-card price comparison, not tier membership.

```json
{
  "mode": "search",
  "specialsCategory": "red-deals",
  "maxListings": 20
}
```

### How to use

#### Search by keyword

```json
{
  "mode": "search",
  "queries": ["iphone 15", "macbook"],
  "minPrice": 5000,
  "maxPrice": 50000,
  "minRating": "4",
  "sortBy": "PRICE_BY_ASC",
  "freeCargoOnly": true,
  "maxListings": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "TR"
  }
}
```

#### Paste any Trendyol URL

```json
{
  "mode": "url",
  "urls": [
    "https://www.trendyol.com/sr?q=iphone+15&pi=1",
    "https://www.trendyol.com/cep-telefonu-x-c103498",
    "https://www.trendyol.com/magaza/sample-store-m-100000",
    "https://www.trendyol.com/apple/sample-product-p-100000001"
  ],
  "maxPages": 3,
  "maxListings": 100,
  "fetchReviews": true,
  "fetchQna": true
}
```

#### Reviews-only

```json
{
  "mode": "reviews",
  "productInputs": [
    "356251114",
    "https://www.trendyol.com/apple/sample-product-p-100000001"
  ],
  "maxReviewsPerProduct": 200,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "TR"
  }
}
```

### Input parameters

| Parameter | Type | Default | Notes |
|---|---|---|---|
| `mode` | string | `"search"` | One of `search`, `url`, `reviews` |
| `queries` | string\[] | `[]` | search mode only |
| `specialsCategory` | string | `""` | search mode only; one of `red-deals`, `orange-deals`, `yellow-deals`, `flash-sale` — see "Specials / campaign tiers" above |
| `urls` | string\[] | `[]` | url mode only |
| `productInputs` | string\[] | `[]` | reviews mode only; URL or numeric content ID |
| `maxReviewsPerProduct` | integer | `200` | Cap per product in reviews mode |
| `sortBy` | string | `"BEST_SCORE"` | `BEST_SELLER`, `NEWEST`, `PRICE_BY_ASC`, `PRICE_BY_DESC`, `MOST_RATED`, `MOST_FAVOURITE`. Search mode only |
| `minPrice` | integer | (none) | Price filter, applied after fetch. Search and URL modes |
| `maxPrice` | integer | (none) | Price filter, applied after fetch. Search and URL modes |
| `minRating` | string | `"0"` | One of `0`, `1`, `2`, `3`, `4`, `4.5`. Search and URL modes |
| `freeCargoOnly` | bool | `false` | Drop products without free shipping. Search and URL modes |
| `fastDeliveryOnly` | bool | `false` | Keep only products with fast-delivery badge. Search and URL modes |
| `officialSellerOnly` | bool | `false` | Keep only verified official sellers. Search and URL modes |
| `couponsOnly` | bool | `false` | Keep only items with collectable coupons. Search and URL modes |
| `inStockOnly` | bool | `true` | Drop out-of-stock items. Search and URL modes |
| `maxPages` | integer | `5` | Pages per query / URL (0 = unlimited within `maxListings`) |
| `maxListings` | integer | `50` | Total cap across queries / URLs (0 = unlimited) |
| `fetchDetails` | bool | `false` | Pull rich detail-page fields per product (~25 extra fields per record) |
| `fetchReviews` | bool | `false` | Attach review summary + first batch to each product |
| `fetchQna` | bool | `false` | Attach answered Q\&A to each product |
| `maxQnaPerProduct` | integer | `20` | Q\&A cap per product when `fetchQna=true` |
| `proxyConfiguration` | object | residential TR | Datacenter works; residential pinned to TR is the most reliable |
| `resumeFromRunId` | string | (none) | search/url modes only. Paste a previous run ID or dataset ID to continue an interrupted crawl without re-collecting (or re-billing) products already gathered there |
| `incrementalMode` | bool | `false` | search/url modes only. Turn on for daily/recurring monitoring of the same search or URL set — classifies every product as `NEW`/`UPDATED`/`UNCHANGED`/`REAPPEARED`/`EXPIRED` against the actor's own saved state |
| `stateKey` | string | (auto) | incremental mode only. Name a monitoring campaign, or leave empty to derive a key automatically from mode/queries/urls/filters |
| `emitUnchanged` | bool | `false` | incremental mode only. Also return (and bill) products with no change since the last run |
| `emitExpired` | bool | `false` | incremental mode only. Also return (and bill) products no longer found, once a run has fully scanned every tracked query/URL |

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape — the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record — not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Output example (search / url mode)

> Sample shape, values are illustrative placeholders, not from a live listing.

```json
{
  "kind": "product",
  "contentId": 100000001,
  "id": 100000001,
  "groupId": 100000000,
  "url": "https://www.trendyol.com/sample-brand/sample-product-p-100000001",
  "name": "Sample Product Title",
  "brand": "Sample Brand",
  "brandId": 1000,
  "category": { "id": 1000, "name": "Sample Category" },
  "price": {
    "current": 0,
    "original": 0,
    "recommendedRetail": 0,
    "discountPercent": 0,
    "currency": "TL"
  },
  "rating": { "score": 0, "totalRatings": 0, "totalComments": 0, "breakdown": {} },
  "seller": { "id": 100000, "name": "Sample Seller" },
  "image": "https://cdn.dsmcdn.com/mnresize/400/-/sample/000000000-800x600.jpeg",
  "images": ["https://cdn.dsmcdn.com/mnresize/400/-/sample/000000000-800x600.jpeg"],
  "stock": 0,
  "inStock": true,
  "freeCargo": false,
  "fastDelivery": false,
  "officialSeller": false,
  "sameDayShipping": false,
  "rushDelivery": false,
  "hasCoupon": false,
  "hasCodePromo": false,
  "hasFlashSale": false,
  "isInfluencerPreferred": false,
  "promotions": [],
  "stamps": [],
  "badges": [],
  "scrapedAt": "2026-01-01T00:00:00.000Z"
}
```

### Output example (reviews mode)

> Sample shape, values are illustrative placeholders, not from a live listing.

```json
{
  "kind": "review",
  "id": 400000000,
  "productContentId": 100000001,
  "productUrl": "https://www.trendyol.com/sample-brand/sample-product-p-100000001",
  "rate": 0,
  "comment": "Sample review text appears here.",
  "userFullName": "**** ****",
  "isElite": false,
  "isInfluencer": false,
  "likesCount": 0,
  "language": "tr",
  "createdAt": 1700000000,
  "mediaFiles": [],
  "scrapedAt": "2026-01-01T00:00:00.000Z"
}
```

### Plan and proxy

- **Apify Datacenter** (free-tier and every paid tier, prefilled default). Just tick Use Apify Proxy and leave Apify Proxy Groups empty. Works for casual runs; the actor warns at startup that this configuration is non-deterministic on this site.
- **Apify Residential, country = TR** (Starter plan and above, recommended for reliability). Set Apify Proxy Groups to Residential and country to TR. Returns full Turkish inventory consistently.
- **Bring-your-own proxies**. Paste a list of `http://user:pass@host:port` URLs into the Custom proxies field and untick Use Apify Proxy.

If a run returns 0 items because of an insufficient proxy plan, the actor sets a status message with a clear diagnosis + the upgrade link — it never pushes a billable error record to the dataset, so a failed/empty run is never charged for a result you didn't get.

### Resume & recurring updates (search / url modes)

Two different, complementary features (not available in reviews-only mode):

- **Resume** (`resumeFromRunId`) continues ONE specific interrupted crawl. Paste the run ID or dataset ID of a previous run and this run skips every product it already collected there — no duplicate rows, no double billing.
- **Incremental mode** (`incrementalMode=true`) is for scheduling this actor daily/weekly against the SAME search or URL set. The actor remembers its own baseline (keyed by `stateKey`, or an automatic hash of mode/queries/urls/filters) and classifies every product as `NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED`, or `EXPIRED`. By default only `NEW`/`UPDATED`/`REAPPEARED` are returned; turn on `emitUnchanged`/`emitExpired` to also get (and pay for) those rows. `EXPIRED` rows are only produced once a run has fully scanned every tracked query/URL — not when `maxListings` capped it, or when Resume was used that run.

```json
{
  "mode": "search",
  "queries": ["iphone 15"],
  "incrementalMode": true,
  "maxListings": 0,
  "maxPages": 0
}
```

Leaving `incrementalMode` off (the default) keeps every existing input and output byte-for-byte identical to before this feature existed.

# Actor input Schema

## `mode` (type: `string`):

search = discover products by keyword + filters. url = paste Trendyol URLs (search, category, store or product page). reviews = take a list of product URLs / IDs and dump their reviews only.

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

One or more keywords. Each runs as a separate search; the per-query budget is split evenly across them.

## `specialsCategory` (type: `string`):

Browse one of Trendyol's own campaign tiers instead of (or combined with) a keyword search. Red/Orange/Yellow are the site's own discount-severity color tiers (kırmızı/turuncu/sarı kampanya — red is deepest); Flash sale is the site's rotating hourly deal pool (browse-only, does not combine with a keyword). Leave as 'No filter' for a plain keyword search.

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

Site-native sort. BEST\_SCORE is the default Trendyol relevance ranking.

## `urls` (type: `array`):

Paste any Trendyol URLs. Supported page types: search results (/sr?q=…), category (/<slug>-x-c<id>), seller store (/magaza/<slug>-m-<id>), single product (/<brand>/<slug>-p-<contentId>), a campaign-tier search (/sr?tag=…), or the flash-sale hub (/flas-indirimler). Pagination walks forward from the page number embedded in the URL (default page 1).

## `productInputs` (type: `array`):

Either a full Trendyol product URL ending in /…-p-<contentId>, or just the numeric content ID. One row per review. Use maxReviewsPerProduct to cap how many you pull from each.

## `maxReviewsPerProduct` (type: `integer`):

Hard cap per product. The site exposes thousands of reviews per popular product; a sensible cap keeps cost and runtime predictable.

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

Minimum price in storefront currency (TL for TR, EUR/USD for international).

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

Maximum price in storefront currency.

## `minRating` (type: `string`):

Drop products rated below this threshold.

## `freeCargoOnly` (type: `boolean`):

Drop products that don't include free shipping.

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

Keep only products with the fast-delivery tag.

## `officialSellerOnly` (type: `boolean`):

Keep only products from sellers with the verified-official badge.

## `couponsOnly` (type: `boolean`):

Keep only products that currently offer a collectable coupon at checkout.

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

Drop products that are currently out of stock.

## `maxPages` (type: `integer`):

Maximum SERP pages to walk per query in search mode, or per URL in URL mode. 0 = no per-search cap (use maxListings to bound the total).

## `maxListings` (type: `integer`):

Total cap across all queries / URLs. 0 = unlimited (still bounded by maxPages). Ignored in reviews-only mode.

## `fetchDetails` (type: `boolean`):

When ON in search or URL mode, fetch each product's detail page and add ~25 extra fields: full attribute list, merchant info (name, official name, city, score), category tree, web brand, favorite count, max installment, tax %, refundable flag, merchandising group, English category translations, full promotions, winner variant with barcode + stock + tags. Costs roughly +1 fetch per product.

## `fetchReviews` (type: `boolean`):

When ON in search or URL mode, attach the rating breakdown + the first batch of review text to each product record. Costs roughly +1 API call per product.

## `fetchQna` (type: `boolean`):

When ON in search or URL mode, attach the answered Q\&A pairs to each product record. Costs roughly +1 API call per product.

## `maxQnaPerProduct` (type: `integer`):

Cap on Q\&A pairs per product when fetchQna = true.

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

Trendyol requires Apify Residential proxy with country = TR (the prefilled default) — Starter plan and above include Residential. On Datacenter or non-TR exits Trendyol rejects every request and the run returns an upgrade notice instead of products. You can also paste your own TR proxy URLs into the Custom proxies field and untick Use Apify Proxy.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large crawl of products without returning or charging for products already collected there. Use this after an interrupted run, or when continuing a product pull in another run. For recurring daily/weekly monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching products as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED products. Turn on "Emit unchanged" or "Emit expired" only when you also want those products returned (and billed). State is kept separately for each mode/query/URL/filter combination; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the queries/URLs/specials tier/filters — different searches then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return products that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned every tracked query/URL — not when Max products capped it, or when Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "iphone"
  ],
  "specialsCategory": "",
  "sortBy": "BEST_SCORE",
  "urls": [
    "https://www.trendyol.com/sr?q=iphone+15&pi=1",
    "https://www.trendyol.com/cep-telefonu-x-c103498?pi=1",
    "https://www.trendyol.com/sr?tag=kirmizi_kampanya_urunu"
  ],
  "productInputs": [
    "https://www.trendyol.com/apple/yenilenmis-iphone-11-64-gb-beyaz-cep-telefonu-12-ay-garantili-a-kalite-p-356251114"
  ],
  "maxReviewsPerProduct": 200,
  "minRating": "0",
  "freeCargoOnly": false,
  "fastDeliveryOnly": false,
  "officialSellerOnly": false,
  "couponsOnly": false,
  "inStockOnly": true,
  "maxPages": 0,
  "maxListings": 20,
  "fetchDetails": true,
  "fetchReviews": false,
  "fetchQna": false,
  "maxQnaPerProduct": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "TR"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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 = {
    "mode": "search",
    "queries": [
        "iphone"
    ],
    "urls": [
        "https://www.trendyol.com/sr?q=iphone+15&pi=1",
        "https://www.trendyol.com/cep-telefonu-x-c103498?pi=1",
        "https://www.trendyol.com/sr?tag=kirmizi_kampanya_urunu"
    ],
    "productInputs": [
        "https://www.trendyol.com/apple/yenilenmis-iphone-11-64-gb-beyaz-cep-telefonu-12-ay-garantili-a-kalite-p-356251114"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "TR"
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/trendyol-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 = {
    "mode": "search",
    "queries": ["iphone"],
    "urls": [
        "https://www.trendyol.com/sr?q=iphone+15&pi=1",
        "https://www.trendyol.com/cep-telefonu-x-c103498?pi=1",
        "https://www.trendyol.com/sr?tag=kirmizi_kampanya_urunu",
    ],
    "productInputs": ["https://www.trendyol.com/apple/yenilenmis-iphone-11-64-gb-beyaz-cep-telefonu-12-ay-garantili-a-kalite-p-356251114"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "TR",
    },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/trendyol-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 '{
  "mode": "search",
  "queries": [
    "iphone"
  ],
  "urls": [
    "https://www.trendyol.com/sr?q=iphone+15&pi=1",
    "https://www.trendyol.com/cep-telefonu-x-c103498?pi=1",
    "https://www.trendyol.com/sr?tag=kirmizi_kampanya_urunu"
  ],
  "productInputs": [
    "https://www.trendyol.com/apple/yenilenmis-iphone-11-64-gb-beyaz-cep-telefonu-12-ay-garantili-a-kalite-p-356251114"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "TR"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call abotapi/trendyol-scraper --silent --output-dataset

```

## MCP server setup

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