# OpenCart Product Catalog Change Monitor & Diff (`clintsa/opencart-product-catalog-change-monitor`) Actor

Track new, updated and removed products across public OpenCart storefronts with field-level change details.

- **URL**: https://apify.com/clintsa/opencart-product-catalog-change-monitor.md
- **Developed by:** [Andy Besos](https://apify.com/clintsa) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 opencart product changes

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

OpenCart Product Catalog Change Monitor & Diff compares public OpenCart product catalogs over time and reports new, changed, unchanged and removed products with field-level diffs. Enter a public OpenCart storefront URL to discover products, or paste a product URL for one focused lookup. The output is a structured Apify Dataset that can be exported as JSON, CSV or Excel.

No OpenCart admin account or OpenCart API key is required. The Actor reads pages already visible to shoppers through direct HTTP. An Apify proxy is optional for shops that block the default network route.

### Why use this catalog change feed?

- Use oldValues, newValues and changedFields to see exactly which product details changed between scheduled observations.
- Use a stable product ID or review fingerprint so scheduled runs can compare records.
- Get a run summary with requested, successful, failed and incomplete targets, plus exported record counts.
- Run several OpenCart targets in one job. If one target fails, other targets can still succeed.
- Send the dataset to Apify schedules, webhooks or your own API client.

The Actor retries temporary network errors and logs failures per target. It does not invent exact stock counts when a shop only displays “In Stock.” A shop with customized themes may expose fewer fields than the default OpenCart layout.

### Pricing

Pay per event: $0.001 per run plus $0.0005 per exported product event. The example totals below are Actor event charges for 256 MB runs:

| Exported records | Actor event charge |
| ---: | ---: |
| 1 | $0.00150 |
| 100 | $0.051 |
| 1,000 | $0.501 |
| 10,000 | $5.001 |

The exact formula is $0.001 + (exported records × $0.0005). Apify platform storage or data transfer charges can be separate. A target that returns no matching records still incurs the run start event; choose a known product for your first test.

### How to use this Actor

Paste a homepage such as https://opencart.ridly.io/ to discover product links through OpenCart categories and pagination. A direct product URL such as https://opencart.ridly.io/index.php?route=product/product\&product\_id=40 is faster and ideal for a focused check. Hostnames without a scheme are accepted and normalized to HTTPS.

Quick start with the prefilled public product:

```json
{
  "targets": [
    "https://opencart.ridly.io/index.php?route=product/product&product_id=40"
  ],
  "maxItemsPerTarget": 1
}
```

For a store-wide scan, set the export cap to zero and raise page limits if your shop is large:

```json
{
  "targets": [
    "https://opencart.ridly.io/"
  ],
  "maxItemsPerTarget": 0,
  "maxListingPages": 0,
  "maxProductPages": 0
}
```

The prefill requests one product and exports one record. For a storefront scan, maxItemsPerTarget limits the Dataset output, while snapshots compare every record fetched within the listing and product page limits.

### Monitor new, updated and removed products

Use the same monitorId and target URLs on repeated scheduled runs. The first run labels records “new”; later runs label them “updated,” “unchanged,” or “removed.” changedFields lists fields that changed. For product changes, oldValues and newValues show the before and after values; the price and stock Actor also emits eventType values such as price\_drop and sold\_out.

```json
{
  "targets": [
    "https://opencart.ridly.io/index.php?route=product/product&product_id=40"
  ],
  "monitorId": "my-opencart-watch",
  "maxItemsPerTarget": 0,
  "onlyChangesSince": "2026-09-01T00:00:00.000Z"
}
```

Omit onlyChangesSince to include unchanged rows. A removed event is emitted only when a complete crawl confirms the record disappeared. If a listing, product or review page limit truncates the crawl, the Actor keeps prior records and reports the target as incomplete in SUMMARY to avoid false removal alerts.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/Clintsa~opencart-product-catalog-change-monitor/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"targets":["https://opencart.ridly.io/index.php?route=product/product&product_id=40"],"maxItemsPerTarget":1}'
```

For larger shops, start the run asynchronously and read its Dataset when it finishes.

### Input options

| Field | Type | Purpose |
| --- | --- | --- |
| targets | URL list | One or more OpenCart shop homepages, category pages or product pages. |
| maxItemsPerTarget | integer | Export cap per target; 0 exports all scanned records. The prefill is 1. |
| maxListingPages | integer | Maximum category and pagination pages per storefront; 0 removes the cap. |
| maxProductPages | integer | Maximum product detail pages per storefront; 0 removes the cap. |
| monitorId | string | Persistent name for snapshots across scheduled runs. |
| onlyChangesSince | ISO timestamp | Emit only changes detected since the given time. |
| requestDelayMillis | integer | Optional pause between requests. |
| useApifyProxy | boolean | Optional Apify Proxy fallback for blocked storefronts. |
| proxyConfiguration | object | Proxy settings when the fallback is enabled. |

### Output

Selected fields from an illustrative product event after a repeat run (unchanged records appear when onlyChangesSince is omitted):

```json
{
  "target": "https://opencart.ridly.io/index.php?route=product/product&product_id=40",
  "itemId": "40",
  "productId": "40",
  "name": "iPhone",
  "price": 123.2,
  "regularPrice": 123.2,
  "availability": "in_stock",
  "inStock": true,
  "productUrl": "https://opencart.ridly.io/index.php?route=product/product&language=en-gb&product_id=40",
  "sourceUrl": "https://opencart.ridly.io/index.php?route=product/product&product_id=40",
  "scrapedAt": "2026-09-30T12:05:00.000Z",
  "changeType": "unchanged",
  "eventType": "unchanged",
  "changedFields": [],
  "oldValues": {},
  "newValues": {},
  "changeDetectedAt": "2026-09-30T12:00:00.000Z",
  "firstSeenAt": "2026-09-30T12:00:00.000Z",
  "lastSeenAt": "2026-09-30T12:05:00.000Z"
}
```

Every run also writes a SUMMARY record in its default key-value store. It includes scan counts, change counts, completion time and whether Apify Proxy was used.

### Use cases

- This change feed is meant for assortment alerts, product content QA and scheduled comparison of competing shops.
- Create a repeatable feed from several OpenCart shops without logging in to their administration panels.
- Compare public product information between two scheduled observations.
- Export a small focused sample for a spreadsheet or an automated downstream job.

### FAQ

#### Does this need an OpenCart API key?

No. It requests public storefront and product pages. An Apify account is needed to run the Actor itself.

#### Can it scan a whole OpenCart shop?

Yes, when public category and product links are discoverable. Set page limits to zero for complete coverage and use a modest request delay on large shops.

#### Why can a result have no exact inventory count?

Most OpenCart storefronts publish only an availability label. The Actor leaves inventoryLevel empty unless a public count is available.

#### What happens when a shop blocks requests?

The target is logged as failed. You can enable Apify Proxy as a network fallback and retry. A shop's own policies still apply.

#### How are removals decided?

A record must have appeared in a prior snapshot and be absent from a complete later scan using the same monitorId and target scope.

### Limitations and responsible use

Only public storefront content is returned. Store themes, extensions, language settings, cookie requirements and site defenses vary, so a customized shop may need adaptation. Prices are displayed shopper prices; tax, shipping and variant-specific totals may differ. Review dates are preserved as displayed, without inventing a timezone. Follow each shop's robots.txt, terms and applicable law, and avoid excessive request rates.

### Support

Use the Issues tab on this Actor's Store page. Include the run ID, the target URL and the fields you expected so a failing theme or route can be reproduced.

# Actor input Schema

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

Public OpenCart storefront URLs or individual product URLs. Paste full HTTP(S) links or a hostname; product links produce a cheap one-product run.

## `maxItemsPerTarget` (type: `integer`):

Maximum exported records per target. Set 0 to export all. Crawling and monitoring still compare every fetched record; the prefill exports one.

## `maxListingPages` (type: `integer`):

Limit category and pagination pages fetched for a storefront. Set 0 for all pages. Removal events are suppressed when this limit truncates a crawl.

## `maxProductPages` (type: `integer`):

Limit product detail requests after discovery. Set 0 for every discovered product. A truncated scan will not emit removed events.

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

Persistent snapshot namespace. Keep this value stable for scheduled runs over the same target scope; use another value for an independent monitor.

## `onlyChangesSince` (type: `string`):

Optional ISO 8601 timestamp. When set, emit only new, updated and removed records detected since this time. Omit to include unchanged records.

## `requestDelayMillis` (type: `integer`):

Pause between listing or product requests to reduce load on the store. Leave at zero for the small prefill.

## `useApifyProxy` (type: `boolean`):

Optional network fallback for stores that restrict data-center IPs. Public demo sources normally work without it.

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

Optional proxy options used only when Use Apify Proxy is enabled.

## Actor input object example

```json
{
  "targets": [
    "https://opencart.ridly.io/index.php?route=product/product&product_id=40"
  ],
  "maxItemsPerTarget": 1,
  "maxListingPages": 20,
  "maxProductPages": 100,
  "monitorId": "default",
  "requestDelayMillis": 0,
  "useApifyProxy": false
}
```

# Actor output Schema

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

No description

## `summary` (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": [
        "https://opencart.ridly.io/index.php?route=product/product&product_id=40"
    ],
    "maxItemsPerTarget": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("clintsa/opencart-product-catalog-change-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": ["https://opencart.ridly.io/index.php?route=product/product&product_id=40"],
    "maxItemsPerTarget": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("clintsa/opencart-product-catalog-change-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": [
    "https://opencart.ridly.io/index.php?route=product/product&product_id=40"
  ],
  "maxItemsPerTarget": 1
}' |
apify call clintsa/opencart-product-catalog-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,clintsa/opencart-product-catalog-change-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/49KALVibQsLsYNvrq/builds/TxR8HVLbl840LbjX0/openapi.json
