# Listing Watch — Job Alert Monitor for Computrabajo (`mfapitools/listing-watch`) Actor

Wraps computrabajo-jobs-scraper with scheduled runs and stateful diffing to deliver only NEW job listings since your last check. Turns a one-shot scraper into a subscription. Pay per check + per new listing found.

- **URL**: https://apify.com/mfapitools/listing-watch.md
- **Developed by:** [Mariano Ferreras](https://apify.com/mfapitools) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listing 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/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Listing Watch — Job Alert Monitor for Computrabajo

> **Turn a one-shot scraper into a subscription.** `listing-watch` schedules `computrabajo-jobs-scraper`, diffs every run against a stored history of job URLs, and delivers **only the listings that are new since your last check**. You pay a small per-check fee plus a per-new-listing fee — the premium is for the alert, not for re-reading data you already have.

---

### What it does

**listing-watch** is a wrapper actor: it runs `computrabajo-jobs-scraper` on your behalf with your search parameters, compares the results against a stateful key-value store of previously seen job URLs, and outputs a compact `WatchResult` containing only the **new** listings. Nothing is re-processed and nothing duplicate reaches your dataset.

It works by:
1. Running `computrabajo-jobs-scraper` with your keyword, country, and optional location/date filters
2. Comparing the returned job URLs against a stored list from your last run (URL is the stable dedup key)
3. Pushing a single `WatchResult` record with the new listings only
4. Updating its stored state so the *next* run picks up only what's fresh from there

Run it on an Apify Schedule (daily, hourly, whatever cadence fits) and you get a continuous, deduplicated feed of new Computrabajo postings — a **job alert** service built entirely from an existing one-shot scraper plus a diff layer.

---

### Use cases

- **Job alert automation** — schedule a daily Computrabajo search for your ideal role and get a compact feed of only new postings, ready to pipe into Slack, email, or your ATS.
- **New job listings monitor** — track new posting volume by role, location, and country across LatAm without writing your own dedup logic.
- **Competitor hiring monitoring** — watch what roles a specific employer or industry is hiring for, and get notified the moment a new one goes up.
- **HR tech / recruiting pipelines** — feed a continuously deduplicated stream of new LatAm job listings into a matching engine, analytics dashboard, or candidate-alert system.
- **Labor market trend tracking** — measure new-posting velocity by keyword and geography over time, run after run, without manual bookkeeping.

---

### Input example

```json
{
  "keyword": "desarrollador python",
  "country": "ar",
  "location": "buenos aires",
  "sinceDate": "2026-07-01",
  "maxNewItems": 20
}
````

| Field | Type | Default | Description |
|---|---|---|---|
| `targetActor` | enum | `computrabajo-jobs-scraper` | Which actor to watch. More sources coming in v2. |
| `keyword` | string | `"desarrollador"` | Job search keyword to monitor |
| `country` | string | `"ar"` | Computrabajo country code (`ar`, `mx`, `co`, `pe`, `cl`, etc.) |
| `location` | string | *(none)* | Optional city/province filter |
| `sinceDate` | string | *(none)* | ISO date `YYYY-MM-DD`. Only monitor jobs posted on or after this date. |
| `maxNewItems` | integer | `20` | Maximum new listings to return per run (1–200) |
| `detectRemoved` | boolean | `false` | v2 feature — currently a no-op |

Each unique combination of `keyword` + `country` + `location` is one independent "watch" with its own stored history — reuse the same input on a schedule to keep it going.

***

### Output example

```json
[
  {
    "watchId": "9849d0d277328a70d1391d105a029ab101c8691646a705a0f7c6709351879832",
    "targetActor": "computrabajo-jobs-scraper",
    "keyword": "desarrollador python",
    "country": "ar",
    "newCount": 3,
    "totalChecked": 60,
    "lastRunAt": "2026-07-22T12:00:00.000Z",
    "checkedAt": "2026-07-23T12:00:00.000Z",
    "previousListingCount": 55,
    "newListings": [
      {
        "url": "https://ar.computrabajo.com/ofertas-de-trabajo/oferta-de-trabajo-de-senior-backend-python-developer-remoto-para-residentes-en-argentina-en-monserrat-F2A4E9D19A683AFB61373E686DCF3405",
        "title": "Senior Backend Python Developer",
        "company": "Kaizen Recursos Humanos",
        "location": "Monserrat, Capital Federal",
        "salary": { "raw": "A convenir", "min": null, "max": null, "currency": null },
        "contractType": "Contrato por tiempo indeterminado",
        "workMode": "remote",
        "postedDate": "2026-07-23",
        "description": "En KaizenRH buscamos Senior Backend Python Developer...",
        "source": "computrabajo",
        "country": "ar"
      }
    ]
  }
]
```

Each dataset item is a `WatchResult` containing:

- **Watch metadata** — `watchId`, `targetActor`, `keyword`, `country`, `checkedAt`, `lastRunAt`
- **Counts** — `newCount`, `totalChecked`, `previousListingCount`
- **New listings** — `newListings[]` — array of `Job` objects (same schema as `computrabajo-jobs-scraper`: title, company, location, salary, contract type, work mode, posted date, description, URL)

The very first run of a watch has no history to compare against, so all returned listings count as "new" — that's your baseline. Every run after that reports only what actually changed.

***

### Pricing

This actor uses **pay-per-event** pricing — no rental, no subscription, no charge for duplicate listings.

| Event | Price | What triggers it |
|---|---|---|
| Actor start | $0.001 | One-time per run (covers orchestration compute) |
| `listing-checked` | $1.00 / 1,000 ($0.001/ea) | Charged once per watch run — the cost of running the check itself |
| `listing-new` | $5.00 / 1,000 ($0.005/ea) | Charged per genuinely new listing discovered. The premium over raw scraping pays for the dedup + alerting value, not the data |

**Important — this actor internally runs `computrabajo-jobs-scraper` on your behalf.** That sub-run is billed to you separately, at `computrabajo-jobs-scraper`'s own published rates (currently ~$0.001 start + $0.0015 per job scraped). You'll see it as its own line item in your Apify usage. `listing-watch`'s fees above are only for the orchestration and alerting layer on top.

**Real-world cost examples** (measured on live platform validation runs, `keyword: "desarrollador"`, `country: "ar"`):

| Scenario | Jobs checked | New listings | `listing-watch` fees | `computrabajo` pass-through | Total |
|---|---|---|---|---|---|
| First run (seed watch) — measured | 15 | 5 | $0.027 | $0.024 | ~$0.05 |
| Second run, nothing new — measured | 15 | 0 | $0.002 | $0.024 | ~$0.03 |
| Larger watch (100 checked, 10 new) | 100 | 10 | $0.052 | $0.151 | ~$0.20 |

Most of the steady-state cost is the underlying Computrabajo scrape (unavoidable — the only way to know what's new is to re-check what's there). `listing-watch`'s own fee stays low when nothing changes and scales only with genuinely new results.

***

### Use with AI agents (MCP)

This actor is available as a tool for AI assistants via the Apify MCP server. Agents can subscribe to a **job search alert** or **new listings monitor** directly — no Apify console needed, just a function call.

#### MCP setup

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://mcp.apify.com?tools=mfapitools/listing-watch",
        "--header",
        "Authorization: Bearer <YOUR_API_TOKEN>"
      ]
    }
  }
}
```

#### Example agent prompts

- "Check if there are any new Python developer jobs on Computrabajo Argentina since last week"
- "Set up a watch for remote React jobs in Mexico and tell me only about new postings"
- "Has anything new been posted for 'contador' roles in Buenos Aires?"

The actor returns structured JSON with the fields shown above. Agentic workflows can run this on a schedule (via the Apify Scheduler) and only need to look at `newListings` on each check — no manual dedup logic required on the agent side.

***

### Limitations

- **v1 — Computrabajo only.** More sources (Trustpilot, licitaciones-feed, others) are candidates for v2; `targetActor` is an enum of one value today.
- **Detect removed listings is v2.** The `detectRemoved` input field currently has no effect.
- **No webhook/email notifications in v1.** The actor writes to its dataset each run; connect it to Slack, email, or a ticketing system via Apify webhooks or the dataset API.
- **Single keyword per watch.** One watch = one keyword + country + location. For multiple keywords, create multiple schedules with different inputs.
- **State stored in a named key-value store** (`listing-watch-state`), one key per watch (hash of `targetActor` + `keyword` + `country` + `location`). URLs are capped at 1,000 per watch, newest-preserved, to bound storage growth — job postings older than the most recent 1,000 for a given search won't be tracked for dedup.
- **Computrabajo's own charges are billed to you separately** — see Pricing above. This actor does not mark up or hide that cost; it's a transparent pass-through from the underlying scrape.
- **Cross-actor invocation.** This actor calls `computrabajo-jobs-scraper` (`ywW0ObCeHcOu3RdpJ`) internally via `Actor.call()`, with an automatic fallback to the Apify REST API if `Actor.call()` is unavailable.
- **Compliance inherits from the wrapped actor.** All the same public-data-only guarantees of `computrabajo-jobs-scraper` apply — this actor adds no new scraping surface of its own.

***

### Changelog

See [CHANGELOG.md](./CHANGELOG.md).

# Actor input Schema

## `targetActor` (type: `string`):

Which actor to watch. Currently only 'computrabajo-jobs-scraper' is supported.

## `keyword` (type: `string`):

Job search keyword to monitor, e.g. 'desarrollador python', 'contador', 'ventas'.

## `country` (type: `string`):

Computrabajo country code (ar, mx, co, pe, cl, etc.)

## `location` (type: `string`):

Optional city/province filter, e.g. 'buenos aires', 'cordoba'.

## `sinceDate` (type: `string`):

ISO date YYYY-MM-DD. Only monitor jobs posted on or after this date.

## `maxNewItems` (type: `integer`):

Maximum new listings to return per run. The source actor fetches 3x this many for dedup margin.

## `detectRemoved` (type: `boolean`):

Also report listings that were in previous results but are now gone. This is a v2 feature and currently does nothing.

## Actor input object example

```json
{
  "targetActor": "computrabajo-jobs-scraper",
  "keyword": "desarrollador",
  "country": "ar",
  "maxNewItems": 20,
  "detectRemoved": false
}
```

# Actor output Schema

## `results` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("mfapitools/listing-watch").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("mfapitools/listing-watch").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call mfapitools/listing-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=mfapitools/listing-watch",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Listing Watch — Job Alert Monitor for Computrabajo",
        "description": "Wraps computrabajo-jobs-scraper with scheduled runs and stateful diffing to deliver only NEW job listings since your last check. Turns a one-shot scraper into a subscription. Pay per check + per new listing found.",
        "version": "0.1",
        "x-build-id": "WdmmFhqvBedUqPztF"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/mfapitools~listing-watch/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-mfapitools-listing-watch",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/mfapitools~listing-watch/runs": {
            "post": {
                "operationId": "runs-sync-mfapitools-listing-watch",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/mfapitools~listing-watch/run-sync": {
            "post": {
                "operationId": "run-sync-mfapitools-listing-watch",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "keyword"
                ],
                "properties": {
                    "targetActor": {
                        "title": "Target actor to watch",
                        "enum": [
                            "computrabajo-jobs-scraper"
                        ],
                        "type": "string",
                        "description": "Which actor to watch. Currently only 'computrabajo-jobs-scraper' is supported.",
                        "default": "computrabajo-jobs-scraper"
                    },
                    "keyword": {
                        "title": "Search keyword",
                        "type": "string",
                        "description": "Job search keyword to monitor, e.g. 'desarrollador python', 'contador', 'ventas'.",
                        "default": "desarrollador"
                    },
                    "country": {
                        "title": "Country",
                        "type": "string",
                        "description": "Computrabajo country code (ar, mx, co, pe, cl, etc.)",
                        "default": "ar"
                    },
                    "location": {
                        "title": "Location (optional)",
                        "type": "string",
                        "description": "Optional city/province filter, e.g. 'buenos aires', 'cordoba'."
                    },
                    "sinceDate": {
                        "title": "Since date (optional)",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                        "type": "string",
                        "description": "ISO date YYYY-MM-DD. Only monitor jobs posted on or after this date."
                    },
                    "maxNewItems": {
                        "title": "Max new listings",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Maximum new listings to return per run. The source actor fetches 3x this many for dedup margin.",
                        "default": 20
                    },
                    "detectRemoved": {
                        "title": "Detect removed listings (v2)",
                        "type": "boolean",
                        "description": "Also report listings that were in previous results but are now gone. This is a v2 feature and currently does nothing.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
