# Trendyol Price & Stock Monitor (`eaukkesh/trendyol-price-monitor`) Actor

Watch Trendyol products and get told when something actually changes: a price moves, stock
flips, the seller on the listing changes, or a new product appears in a category you follow.

- **URL**: https://apify.com/eaukkesh/trendyol-price-monitor.md
- **Developed by:** [Ahmet Boyraz](https://apify.com/eaukkesh) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 product checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

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 Price & Stock Monitor

Watch Trendyol products and get told when something actually changes: a price moves, stock
flips, the seller on the listing changes, or a new product appears in a category you follow.

Give it product URLs, or point it at a category or brand listing and let it follow the top
products there. Every run compares against the previous one, so you receive change events
rather than a fresh dump you have to diff yourself.

### What it is good for

- **Competitor price tracking.** Follow the products you compete with and see the moment one
  of them drops its price.
- **Losing the listing.** `seller` tells you which merchant Trendyol currently shows for a
  product. When that changes, you find out.
- **Minimum price policy checks.** Brands and distributors can watch who sells below the
  price they set, with basket and membership discounts reported separately from the shelf
  price so you can judge each case.
- **Category watch.** Follow a category or brand listing and get told when a new product
  enters it, along with each product's position.

### Getting started

Set a `monitorId` and give it something to watch. Keep the same `monitorId` on later runs so
it can compare against what it saw before.

```json
{
  "monitorId": "my-competitors",
  "productUrls": [
    "https://www.trendyol.com/tp-link/tapo-c210-akilli-wi-fi-guvenlik-kamerasi-p-356747505"
  ],
  "categoryUrls": ["https://www.trendyol.com/tp-link-x-b108165"],
  "productsPerCategory": 24,
  "onlyChanges": true,
  "minimumPriceChangePercent": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "TR"
  }
}
```

**A Turkish proxy is required.** Trendyol sends visitors from other countries to its country
selector instead of the product page, so without a Turkish exit IP no page can be read at
all. Use the proxy settings above. If a run reports every product as `blocked`, this is why,
and the run message will say so.

`productUrls` is a fixed set: exactly those products, every run. `categoryUrls` follows a
listing instead, taking the top `productsPerCategory` products from its first page, so the
monitored set moves with the listing. You can use either or both.

The first run has nothing to compare against, so it records a baseline for each product. With
`onlyChanges` on, that means the first run's dataset may be empty. That is expected: it is
building the reference point for every run after it.

### Example output

```json
{
  "productTitle": "Tp-Link Tapo C210 Akıllı Wi-Fi Güvenlik Kamerası 360 Derece Takip",
  "productUrl": "https://www.trendyol.com/tp-link/tapo-c210-...-p-356747505",
  "productId": "356747505",
  "currentPrice": 1599,
  "previousPrice": 1749,
  "priceChangePercent": -8.58,
  "listPrice": 1619,
  "conditionalPrice": null,
  "currency": "TRY",
  "availability": "in_stock",
  "seller": "Vizyon Bilgisayar",
  "previousSeller": "Vizyon Bilgisayar",
  "otherSellerCount": 5,
  "selectedVariant": null,
  "rank": 3,
  "previousRank": 5,
  "categoryUrl": "https://www.trendyol.com/tp-link-x-b108165",
  "observationCount": 12,
  "observedMinPrice": 1599,
  "observedMaxPrice": 1899,
  "changes": ["price_decreased", "lowest_observed"],
  "checkedAt": "2026-09-12T18:12:04.505Z"
}
```

### Reading the output

**Three prices, and the difference matters.** `currentPrice` is what an ordinary visitor sees
on the page. `conditionalPrice` is a lower price that only applies under a condition, such as
a basket promotion or a Trendyol Plus membership price, with the promotion names in
`conditions`. `listPrice` is the struck-through reference price, and only appears when it is
genuinely above the current price.

This is worth understanding before you compare numbers with the site. One product displayed
2.599 TL on the shelf while offering 2.469,05 TL in the basket to Plus members. Both numbers
are real, and they are reported in separate fields rather than mixed into one. Roughly one in
six products carries such a conditional price, so tools that publish a single "price" often
show the conditional one without saying so.

**Change labels.** `baseline` on the first observation. Then `price_increased`,
`price_decreased`, `stock_changed`, `seller_changed`, and `listing_added` when a product
enters a monitored listing. These are the events; `onlyChanges` keeps only rows that carry
one of them.

`lowest_observed` and `highest_observed` are notes, not events. They mean the price is the
lowest or highest **this monitor has recorded**, not an all-time low, and they never make a
row appear on their own.

**Seller.** `seller` is the merchant Trendyol shows for the offer the page renders to an
anonymous visitor, and `otherSellerCount` is how many other merchants are listed for that
product. A logged-in shopper or a different region can be shown a different offer, so read
`seller_changed` as "the displayed merchant changed".

**Variants.** Clothing, shoes and watches are sold as variant groups. There, price and stock
describe the variant the page had selected, named in `selectedVariant`, and `isVariantGroup`
is true. Different colourways are separate products with their own URLs and prices; add them
individually if you want to follow them.

**Position.** With `categoryUrls`, `rank` is the product's place on the listing page and
`previousRank` is where it was last run. Position moves constantly, so it is reported but
never raised as a change event.

**Per-run records.** `SUMMARY` describes the run: how many products were requested, read and
emitted, and a breakdown of failures. `ERRORS` lists each failed URL with a reason of
`blocked`, `timeout`, `extraction`, `network` or `other`. `LISTING_CHANGES` lists the products
that entered and left each monitored listing.

A product that cannot be read never overwrites its previous observation and is never reported
as out of stock. If every product fails, the run fails loudly and tells you whether it looks
like the exit IP or the page shape.

### Scheduling and alerts

Save your input as a Task, then give the Task a Schedule, daily or hourly as you prefer.

To be notified, add an `ACTOR.RUN.SUCCEEDED` webhook pointing at Make, n8n or your own
endpoint, fetch the run's dataset, and alert only when a row carries a change label. A
successful run is not itself a change; with `onlyChanges` on, an empty dataset means nothing
moved. This Actor does not send messages itself.

Avoid overlapping runs on the same `monitorId`. A run claims its monitor while working and a
second run will stop with a clear message rather than interleave writes.

### Pricing

Two events are charged, and they follow the work rather than the output.

- **`product-checked`** — once for each product read successfully. This is charged even when
  `onlyChanges` keeps the observation out of the dataset, because reading a product costs the
  same whether or not its price moved.
- **`change-detected`** — once more when that observation carries a real event. One charge per
  observation, not one per label.

Nothing is charged for a product that could not be read: a blocked page or a changed page
shape is not billable. You can cap a run with the maximum cost per run setting, and when the
cap is reached the run stops taking on new work instead of continuing.

Apify platform usage and proxy traffic are billed by the platform as usual, on top of events.

For sizing: twenty-four products take about a minute at the default concurrency of 2, so
the 600 second default timeout leaves room for a few hundred. Memory above 1024 MB is
wasted unless `browserFallback` is on, which needs 4096 MB for Chromium.

### Limits

- Trendyol only. Prices are read in TRY; a page in another currency is refused rather than
  converted.
- Up to 200 products per monitor: 100 direct URLs, plus up to 5 listings at up to 60 products
  each. Only the first page of a listing is read.
- History starts when you start. There is no data from before your first run, and each product
  keeps its most recent `historyLength` observations, 50 by default.
- `minimumPriceChangePercent` compares against the previous successful observation, not a
  cumulative move over weeks.
- Shipping cost, coupon stacking, cart totals, location-specific offers and matching the same
  product across marketplaces are not covered.
- Stock is read from what the page publishes. Out-of-stock pages are handled but have been
  seen far less often in testing than in-stock ones, so treat stock alerts as newer ground
  than price alerts.
- Search URLs are not accepted, because Trendyol's robots.txt disallows them.

### Notes

The Actor reads only public product and listing pages. No login is required and no account
credentials are used. It runs with limited permissions and needs access to nothing in your
account beyond the storages it creates for your monitors.

Development notes, verification results and measured costs are in
[`docs/STATUS.md`](docs/STATUS.md) and [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md).

# Actor input Schema

## `monitorId` (type: `string`):

Names this monitor's history. Keep the same ID across scheduled runs so each run can compare against the previous one. Lowercase letters, digits and hyphens.

## `productUrls` (type: `array`):

Up to 100 HTTPS product URLs. Merchant and variant parameters are preserved. Give these, categoryUrls, or both.

## `categoryUrls` (type: `array`):

Up to 5 listing pages. Each run reads the first page and monitors the top products it shows, so the set follows the listing rather than staying fixed. Search URLs are not accepted.

## `productsPerCategory` (type: `integer`):

How many top products to take from each listing page. Total across products and listings may not exceed 200. Twenty-four products take about a minute at the default concurrency.

## `onlyChanges` (type: `boolean`):

Suppress baseline and unchanged observations; first run may return no rows.

## `minimumPriceChangePercent` (type: `integer`):

Compared to the immediately preceding successful observation.

## `maxConcurrency` (type: `integer`):

Maximum concurrent requests.

## `browserFallback` (type: `boolean`):

Retry a failed product in Chromium. Off by default: the HTTP path handled every product in testing, and Chromium needs the run's memory raised to 4 GB. Turn it on only if you see repeated extraction failures, and raise memory with it.

## `testMode` (type: `boolean`):

Use an isolated test store and do not update historical state.

## `historyLength` (type: `integer`):

How many past observations to keep per URL. Used for the observed minimum and maximum only; it does not change alerting.

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

Required on the Apify platform. Trendyol sends visitors from other countries to its country selector instead of the product page, so a Turkish exit IP is needed. Residential proxies in Turkey are known to work.

## Actor input object example

```json
{
  "monitorId": "my-monitor",
  "categoryUrls": [
    "https://www.trendyol.com/tp-link-x-b108165"
  ],
  "productsPerCategory": 12,
  "onlyChanges": false,
  "minimumPriceChangePercent": 0,
  "maxConcurrency": 2,
  "browserFallback": false,
  "testMode": false,
  "historyLength": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "TR"
  }
}
```

# Actor output Schema

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

No description

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

No description

## `errors` (type: `string`):

No description

## `listingChanges` (type: `string`):

No description

## `listingDiagnostics` (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 = {
    "monitorId": "my-monitor",
    "categoryUrls": [
        "https://www.trendyol.com/tp-link-x-b108165"
    ],
    "productsPerCategory": 12,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "TR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("eaukkesh/trendyol-price-monitor").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 = {
    "monitorId": "my-monitor",
    "categoryUrls": ["https://www.trendyol.com/tp-link-x-b108165"],
    "productsPerCategory": 12,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "TR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("eaukkesh/trendyol-price-monitor").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 '{
  "monitorId": "my-monitor",
  "categoryUrls": [
    "https://www.trendyol.com/tp-link-x-b108165"
  ],
  "productsPerCategory": 12,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "TR"
  }
}' |
apify call eaukkesh/trendyol-price-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eaukkesh/trendyol-price-monitor"
        }
    }
}
```

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/dKcgSAyedyoyPmQsj/builds/JejChFYsFFCncEdtc/openapi.json
