# Blibli Best Sellers Tracker (`zucchini_gopher_m2v/blibli-best-sellers-tracker`) Actor

Memantau daftar "Paling Laris" Blibli per kategori dan melacak produk yang masuk, naik, turun, atau keluar dari daftar antar-run.

- **URL**: https://apify.com/zucchini\_gopher\_m2v/blibli-best-sellers-tracker.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/zucchini_gopher_m2v) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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

## Blibli Best Sellers Tracker

Memantau daftar **"Paling Laris"** [Blibli](https://www.blibli.com) per kategori
dan melaporkan produk mana yang **masuk, naik, turun, tetap, atau keluar** dari
daftar dibanding run sebelumnya.

Dibuat untuk penjual: mengetahui siapa yang menguasai kategori Anda, kapan
pesaing baru menyusup ke daftar, dan kapan produk Anda sendiri tergeser.

### Kenapa actor ini tidak sekadar mengurutkan "terlaris"

Ini bagian terpenting untuk dipahami sebelum memakainya.

Mengurutkan kategori berdasarkan jumlah terjual **tidak** menghasilkan daftar
"Paling Laris" Blibli. Pada kategori Memory Card:

| Peringkat resmi | Terjual |
| --- | --- |
| #1 | 1.899 |
| #2 | 4.178 |
| #3 | 315 |
| #8 | 4.262 |

Produk peringkat 1 terjual jauh lebih sedikit daripada peringkat 8, dan tiga
produk dengan penjualan tertinggi di kategori itu justru tidak berperingkat sama
sekali. Blibli memakai perhitungannya sendiri.

Peringkat resmi hanya tersedia di halaman masing-masing produk, pada
`statistics.bestSelling.rank` — angka yang sama yang memunculkan lencana
*"No. 2 terlaris di Memory Card"*. Actor ini membaca angka itu, bukan menebaknya
dari jumlah terjual.

Konsekuensinya: untuk menyusun daftar sebuah kategori, actor memindai sejumlah
produk terlaris di kategori tersebut lalu membaca peringkat resmi tiap produk.

### Kelengkapan daftar — dan cara actor membuktikannya

Peringkat Blibli berupa deret rapat 1, 2, 3, …, N. Kalau hasil pindai punya
peringkat 1, 2, 4, berarti pemegang peringkat 3 berada di luar jangkauan
pemindaian — bukan berarti peringkat 3 tidak ada.

Actor memeriksa hal ini sendiri dan melaporkannya:

- `leaderboardComplete` — `true` kalau peringkat 1..N rapat tanpa celah
- `leaderboardSize` — jumlah produk dalam daftar
- `candidatesScanned` / `candidatesFailed` — seberapa dalam pemindaian, dan
  berapa yang gagal diambil

Kalau ada celah **dan** ada kandidat yang gagal diambil, log akan menyebutkan
bahwa penyebabnya mungkin jaringan, bukan kedalaman — dua masalah dengan solusi
berbeda.

#### Memilih kedalaman

Dari pengujian:

| Kategori | Kedalaman 100 | Kedalaman 300 |
| --- | --- | --- |
| Memory Card (ME-1000006) | lengkap, 11 produk | lengkap, 11 produk |
| Gaming Laptop (GA-1000002) | **bolong** (rank 15, 16 hilang) | lengkap, 21 produk |
| SSD (SS-1000001) | kosong | kosong |

Default `candidatesPerCategory` adalah **300**. Turunkan untuk hemat, naikkan
kalau `leaderboardComplete` masih `false`.

**Tidak semua kategori punya daftar "Paling Laris".** SSD tidak punya satu pun
produk berperingkat bahkan pada kedalaman 300. Actor melaporkannya apa adanya
alih-alih mengarang daftar dari urutan terjual.

### Pelacakan antar-run

Dengan `trackChanges` aktif (default), actor menyimpan snapshot ke key-value
store bernama dan membandingkannya di run berikutnya. Tiap baris hasil membawa:

| Status | Arti |
| --- | --- |
| `BASELINE` | Run pertama, belum ada pembanding |
| `NEW` | **Masuk** daftar sejak run lalu |
| `UP` / `DOWN` | Naik/turun peringkat (`rankChange`, positif = naik) |
| `SAME` | Peringkat tidak berubah |
| `DROPPED_OUT` | **Keluar** dari daftar — `rank` kosong, `previousRank` terisi |

Produk yang keluar tetap dikeluarkan sebagai baris tersendiri. Bagi penjual,
justru itu kabar yang paling perlu diketahui, dan baris itu akan lenyap tanpa
jejak kalau hanya daftar terbaru yang dilaporkan.

Jadwalkan lewat Apify Scheduler dengan input yang sama; `stateStoreName` yang
sama membuat run-run itu saling menyambung.

### Input

| Field | Keterangan |
| --- | --- |
| `categories` | URL atau kode kategori, mis. `["ME-1000006"]` |
| `discoverCategories` | Telusuri sendiri pohon kategori Blibli |
| `rootCategories` | Titik awal penelusuran; kosong = seluruh 14 kategori utama |
| `categoryLevel` | Kedalaman kategori target (default `3`) |
| `maxCategories` | Pembatas biaya (default `10`) |
| `candidatesPerCategory` | Kedalaman pemindaian (default `300`) |
| `trackChanges` | Bandingkan dengan run sebelumnya (default `true`) |
| `stateStoreName` | Key-value store untuk snapshot |
| `watchMerchantCodes` | Tandai `isWatched=true` untuk kode penjual ini |
| `maxConcurrency` | Permintaan paralel (default `10`) |
| `proxyConfiguration` | Disarankan proxy residensial Indonesia |

#### Mencari kode kategori

Buka kategori di Blibli dan salin URL-nya — actor mengambil kodenya sendiri.
Daftar "Paling Laris" ada di kategori level 3, mis.
`https://www.blibli.com/c3/memory-card/ME-1000006`.

### Contoh keluaran

```json
{
  "rank": 2,
  "status": "DOWN",
  "previousRank": 1,
  "rankChange": -1,
  "productSku": "BLL-70058-00122",
  "name": "SanDisk Ultra microSDXC 64GB C10 UHS-I Card 100MB/s",
  "brand": "SanDisk",
  "salePrice": 259000,
  "listPrice": 299000,
  "discountPercentage": 13,
  "rating": 4.8,
  "reviewCount": 465,
  "stockQuantity": 97,
  "soldCount": 4178,
  "merchantCode": "BLL-70058",
  "merchantName": "Blibli (Laptop - Acc) Flagship Store",
  "isWatched": false,
  "categoryCode": "ME-1000006",
  "categoryName": "Memory Card",
  "leaderboardSize": 11,
  "leaderboardComplete": true,
  "candidatesScanned": 300,
  "candidatesFailed": 0,
  "previousRunAt": "2026-08-30T00:00:00.000Z",
  "runStartedAt": "2026-08-31T04:12:00.000Z"
}
```

Ringkasan per kategori juga disimpan di key-value store run sebagai
`RUN_SUMMARY`, termasuk daftar peringkat yang hilang bila ada.

### Harga

Actor ini ditagih **per kategori yang dipantau**, bukan per baris hasil:

| Item | Tarif |
| --- | --- |
| Memulai run | $0,05 |
| Tiap kategori yang menghasilkan daftar | $1,00 |

Alasannya jujur saja: satu kategori berarti ratusan permintaan halaman produk
tapi hanya belasan baris hasil. Menagih per baris akan membuat actor ini salah
harga secara serius — biaya nyatanya sekitar $0,06 per baris, dua puluh kali
lipat tarif per-hasil yang lazim di Apify Store.

**Kategori tanpa daftar "Paling Laris" tidak ditagih.** Blibli memang punya
kategori seperti itu (SSD salah satunya), dan Anda tidak seharusnya membayar
untuk jawaban kosong — meski memindainya tetap memakan permintaan.

Batas biaya maksimum run yang Anda pasang di Console juga dihormati sejak awal:
kalau anggaran hanya menutup 3 kategori, actor memindai 3 kategori, bukan
memindai 10 lalu gagal menagih.

#### Biaya sumber daya

Satu kategori pada kedalaman 300 memerlukan sekitar 303 permintaan (3 halaman
daftar + 300 halaman produk). Sepuluh kategori berarti sekitar 3.000 permintaan.

`maxCategories` ada khusus supaya penelusuran otomatis tidak diam-diam
membengkak — 14 kategori utama Blibli bercabang menjadi ratusan kategori level 3.

Actor berjalan pada 1 GB memori secara default (puncak pemakaian nyata sekitar
200 MB), jadi biaya compute tetap rendah.

### Catatan teknis

Actor memakai API pencarian internal Blibli dan state JSON yang ditanam di
halaman produk, bukan browser headless. Blibli menolak permintaan yang headernya
tidak konsisten dengan XHR browser sungguhan, jadi profil header dikunci ke satu
identitas Chrome desktop.

#### Soal proxy

Pemblokiran Blibli bertumpu pada header, bukan IP — tapi jenis proxy tetap
berpengaruh besar pada seberapa lengkap daftar yang terkumpul. Pengujian pada
kategori yang sama, kedalaman 300:

| Jalur | Daftar terkumpul | Kandidat gagal | Waktu |
| --- | --- | --- | --- |
| Tanpa proxy (IP Indonesia) | 11 dari 11 | 0 | 12 detik |
| Proxy residensial ID | 11 dari 11 | 1 | 4m 51s |
| Proxy datacenter | 6 dari 11 | banyak | 2m 52s |

Proxy datacenter jelas paling banyak ditolak — hindari. Residensial adalah
default yang disarankan. Tetap perhatikan `leaderboardComplete`: kalau masih
`false` sementara `candidatesFailed` besar, turunkan `maxConcurrency` lalu
jalankan ulang.

Actor sengaja memberi sesi toleransi beberapa kesalahan sebelum membuangnya —
lewat proxy berputar, tiap IP baru harus melewati pemeriksaan awal lagi,
sehingga membuang sesi terlalu cepat justru memperbanyak kegagalan.

### Pengembangan lokal

```bash
npm install
npm test          # tes unit untuk parsing, penyusunan, dan perbandingan daftar
apify run
```

# Actor input Schema

## `categories` (type: `array`):

URL kategori Blibli atau kodenya langsung, mis. https://www.blibli.com/c3/memory-card/ME-1000006 atau ME-1000006. Daftar "Paling Laris" ada di kategori level 3 (sub-sub-kategori).

## `discoverCategories` (type: `boolean`):

Menelusuri sendiri pohon kategori Blibli sampai level target, bukan memakai daftar di atas. Perhatikan "Maksimal kategori" — tiap kategori berarti ratusan permintaan.

## `rootCategories` (type: `array`):

Kode kategori tempat penelusuran dimulai, mis. 53270 (Komputer & Gaming). Kosongkan untuk mulai dari seluruh 14 kategori utama Blibli. Hanya dipakai kalau penelusuran otomatis aktif.

## `categoryLevel` (type: `integer`):

Kedalaman kategori yang dipindai. Level 3 adalah kategori penjualan yang punya daftar "Paling Laris".

## `maxCategories` (type: `integer`):

Pembatas biaya. Tiap kategori memerlukan sekitar "Kandidat per kategori" permintaan halaman produk.

## `candidatesPerCategory` (type: `integer`):

Berapa produk terlaris di kategori yang diperiksa peringkatnya. Peringkat "Paling Laris" tidak sejalan dengan jumlah terjual, jadi produk berperingkat bisa berada cukup dalam. Pengujian menunjukkan 300 memulihkan daftar secara utuh; 100 masih menyisakan lubang.

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

Turunkan kalau Blibli mulai memblokir; naikkan untuk menyelesaikan lebih cepat saat memakai proxy.

## `trackChanges` (type: `boolean`):

Membandingkan hasil dengan run sebelumnya untuk memberi status MASUK / NAIK / TURUN / TETAP / KELUAR pada tiap produk. Matikan kalau Anda hanya ingin potret sesaat.

## `stateStoreName` (type: `string`):

Key-value store bernama tempat snapshot run terakhir disimpan. Run terjadwal dengan nama yang sama akan saling menyambung. Pakai nama berbeda untuk memisahkan pemantauan yang tidak berkaitan.

## `watchMerchantCodes` (type: `array`):

Produk milik kode penjual ini ditandai isWatched=true di hasil, mis. BLL-70058. Berguna untuk menyaring posisi toko Anda sendiri di antara pesaing.

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

Sangat disarankan. Proxy residensial Indonesia memberi daftar yang dilihat pembeli lokal.

## Actor input object example

```json
{
  "categories": [
    "ME-1000006"
  ],
  "discoverCategories": false,
  "rootCategories": [],
  "categoryLevel": 3,
  "maxCategories": 10,
  "candidatesPerCategory": 300,
  "maxConcurrency": 10,
  "trackChanges": true,
  "stateStoreName": "blibli-best-sellers-state",
  "watchMerchantCodes": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ID"
  }
}
```

# Actor output Schema

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

Daftar "Paling Laris" per kategori beserta status pergerakan tiap produk dibanding run sebelumnya.

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

Rekap per kategori: isi daftar, peringkat tertinggi, nomor peringkat yang bolong, jumlah kandidat dipindai, serta berapa produk masuk dan keluar.

# 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 = {
    "categories": [
        "ME-1000006"
    ],
    "rootCategories": [],
    "watchMerchantCodes": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("zucchini_gopher_m2v/blibli-best-sellers-tracker").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 = {
    "categories": ["ME-1000006"],
    "rootCategories": [],
    "watchMerchantCodes": [],
}

# Run the Actor and wait for it to finish
run = client.actor("zucchini_gopher_m2v/blibli-best-sellers-tracker").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 '{
  "categories": [
    "ME-1000006"
  ],
  "rootCategories": [],
  "watchMerchantCodes": []
}' |
apify call zucchini_gopher_m2v/blibli-best-sellers-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zucchini_gopher_m2v/blibli-best-sellers-tracker"
        }
    }
}

```

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/YXN1ex9bJyQGHJapp/builds/W883wCvD31cQSwbtk/openapi.json
