# Bob Shop Product & Competitor Monitor (`thescrapelab/bobshop-product-competitor-monitor`) Actor

Scrape public Bob Shop products and auctions for prices, bids, sellers, stock and shipping. Monitor competitor listing changes across runs.

- **URL**: https://apify.com/thescrapelab/bobshop-product-competitor-monitor.md
- **Developed by:** [Inus Grobler](https://apify.com/thescrapelab) (community)
- **Categories:** E-commerce
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product listings

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?

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

## Bob Shop Product & Competitor Monitor

Track public Bob Shop listings from a product keyword, search page, seller page, or exact product URL. Each run returns one row per listing, including fixed prices or auction bids, seller, condition, availability, quantity, and shipping price when shown. Repeat a run with the same targets to see which listings are new or changed.

Use it to compare sellers for a product search, watch an auction bid, or follow prices and stock on a set of listings. This is an independent monitoring tool and is not affiliated with Bob Shop.

### Input

In Apify Console, enter a keyword or a public Bob Shop search, seller, or product URL under **What to monitor**, then select **Start**. Results appear in the default dataset; the Output tab links to the products and the run summary.

Only the targets are required. This input returns up to five products with details:

```json
{
  "targets": ["iphones"]
}
```

| Input | Default | What it does |
| --- | --- | --- |
| `targets` — What to monitor | Example: `["iphones"]` | One to 20 keywords or public Bob Shop URLs. For example, `iphones` or `https://www.bobshop.co.za/search/coins`. |
| `maxListings` — Number of products | `5` | Maximum unique products across all targets, from 1 to 1,000. Availability and search results can produce fewer rows. |
| `includeDetails` — Include product details | `true` | Adds seller descriptions, shipping rates, and product-page quantities when available. Keep it on for stock monitoring; turn it off for faster listing-only runs. |

### Output

The Products table shows each listing's title, price or current bid, listing type, seller, quantity, starting shipping rate, change, and product link. Export the dataset as JSON, CSV, or Excel.

| Fields | Meaning |
| --- | --- |
| `listingId`, `url`, `title` | The product's identifier, public URL, and title. Each listing appears once per run. |
| `listingType`, `priceOrBid`, `price`, `currentBid` | `FIXED_PRICE` rows use `price`; `ENGLISH_AUCTION` rows use `currentBid`. `priceOrBid` provides the relevant value for either type. Currency is returned in `currency`, normally `ZAR`. |
| `sellerName`, `stockQuantity`, `shippingPrice`, `description` | Public seller and product details. Missing values are `null`; descriptions are limited to 1,000 characters. |
| `changeType`, `changedFields`, `previousValues` | `NEW` on first observation, `UPDATED` when a tracked value changes, or `UNCHANGED`. Updates identify the fields and their previous values. |
| `firstSeenAt`, `observedAt`, `sourceTargets` | First observation, current run observation time, and the targets that found this listing. Times use UTC. |

Tracked changes cover fixed price, auction bid, auction buy-now price, availability status, verified stock quantity, and starting shipping rate. Other fields, such as titles and descriptions, are collected but do not trigger `UPDATED`.

With product details off, quantity comes from search cards and may lag the product page. These quantities are displayed but do not trigger stock-change alerts. A stock baseline is established when the product page supplies a quantity; subsequent verified changes are reported as `UPDATED`. If details are turned off, a detail request fails, or a product page has no quantity, the last verified quantity is retained for the next successful comparison. A change reported after a gap happened since the last verified observation; its exact time is not known.

`shippingPrice` is the starting shipping rate shown in the page's structured offer. Checkout charges can vary by destination.

Comparison history is separated by the target set. Changing a target creates a new baseline. Missing search results are not treated as removals. The Actor reads public Bob Shop HTML pages and embedded page data; it does not call Bob Shop APIs, log in, or download images. Bob Shop pages and values can change, and a partial run is identified in Run status.

The run summary includes the number of products and detail pages collected. If a request or time limit stops detail collection, the search-page listings already found are still returned and the summary reports `PARTIAL`. A customer spending cap can also limit the number of listings; the summary then shows `MAX_TOTAL_CHARGE_USD` as the limit reason. A platform run can finish with Succeeded status while its summary is `PARTIAL`, so check the summary when completeness matters. A run that collects no listings fails with an explanation.

The Actor follows pagination and sets a request limit automatically. Large runs with product details can take several minutes; a 1,000-product detail run took about 10 minutes in testing. Listing-only runs use far fewer requests.

Example listing row:

```json
{
  "listingId": "591438859",
  "url": "https://www.bobshop.co.za/apple-iphone-xs-pristine-pre-owned/p/591438859",
  "title": "Apple iPhone XS - Pristine Pre-Owned",
  "listingType": "FIXED_PRICE",
  "priceOrBid": 4230,
  "price": 4230,
  "currentBid": null,
  "currency": "ZAR",
  "sellerName": "Mobitronics",
  "changeType": "NEW",
  "changedFields": [],
  "observedAt": "2026-09-28T19:41:11.400Z"
}
```

### Cost and limits

The price is **$1 per 1,000 returned products** (`$0.001` per row), including `UNCHANGED` rows on repeat runs, plus a `$0.00005` Actor start event at the default 512 MB memory setting. Platform usage is included. Five returned products cost approximately `$0.00505` in Actor events.

Set a maximum run charge in Apify to control spending. The minimum accepted spending cap is `$0.05`; actual event charges depend on the products returned and the start event. The Actor reduces collection to fit the cap before fetching listings. The maximum is 1,000 products per run.

When you provide several targets, the listing limit is shared among them in input order so an early search cannot consume every slot. Set `maxListings` to at least the number of targets if you want a chance of seeing a listing from each one.

### Troubleshooting

- If there are no rows, check the keyword or URL directly on Bob Shop. The Actor accepts public search, seller, and product pages only.
- If Run status says `PARTIAL`, inspect its error codes or `limitReason`. The rows already returned are usable, but some targets or product details may have been missed, or a spending cap reduced collection.
- For stock monitoring, keep **Include product details** on. Search-card quantities can lag product pages and do not trigger stock-change alerts.
- A listing missing from a later search is not reported as removed. Search ranking and availability can change between runs.

For help, report an issue through this Actor's Issues tab in Apify Console. Include the run ID, the affected public product URL, and the field you expected to see.

### Python example

This example uses the current [Apify API client for Python 3.x](https://docs.apify.com/api/client/python/docs/introduction/quick-start).

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("thescrapelab/bobshop-product-competitor-monitor").call(run_input={
    "targets": ["iphones"],
})
if run is None:
    raise RuntimeError("The Actor did not finish within the client's wait time")

record = client.key_value_store(run.default_key_value_store_id).get_record("OUTPUT")
if record is not None:
    print("Run summary:", record["value"])
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["title"], item.get("priceOrBid"), item["changeType"], item["url"])
```

# Actor input Schema

## `targets` (type: `array`):

Add a keyword or a Bob Shop search, seller, or product URL on each line.

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

Maximum products across all targets. Large runs can take several minutes.

## `includeDetails` (type: `boolean`):

Add seller descriptions, shipping rates, and verified stock-change alerts. Turn off for faster runs.

## Actor input object example

```json
{
  "targets": [
    "iphones"
  ],
  "maxListings": 5,
  "includeDetails": true
}
```

# Actor output Schema

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

No description

## `runSummary` (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 = {
    "targets": [
        "iphones"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thescrapelab/bobshop-product-competitor-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 = { "targets": ["iphones"] }

# Run the Actor and wait for it to finish
run = client.actor("thescrapelab/bobshop-product-competitor-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 '{
  "targets": [
    "iphones"
  ]
}' |
apify call thescrapelab/bobshop-product-competitor-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thescrapelab/bobshop-product-competitor-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/mZQk08GO329dAwkNc/builds/QBsQvbHEyq6qONEIF/openapi.json
