# Chile Mercado Público Tenders Scraper (`automatic/chile-mercado-publico-tenders-scraper`) Actor

Scrape Chilean public tenders from Mercado Publico (ChileCompra): title, buyer with RUT and region, UNSPSC codes, procedure, status, deadline in Chile time, amount, items, awards and suppliers, documents and notice link. Track new, amended and closed tenders between runs.

- **URL**: https://apify.com/automatic/chile-mercado-publico-tenders-scraper.md
- **Developed by:** [Philip Kirkbride](https://apify.com/automatic) (community)
- **Categories:** Lead generation
- **Features:** 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 tenders

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

## Chile Mercado Público Tenders Scraper

Chilean public procurement, straight from Mercado Público. Each row is one procurement (one OCID) with what the buyer published: the tender title and description, the buyer with its RUT and region, the UNSPSC categories, the procedure, the status, the bid deadline in Chile time, the estimated amount and currency, the item list, and the official notice link.

Where the buyer has published awards, the row also carries the award records, the winning suppliers and the award documents. Run it for a month, narrow it by keyword, buyer, region or status, or turn on Changes mode to receive only new, amended and closed tenders on later runs.

Built for Chilean suppliers, bid teams, consultancies and analysts following public procurement, and for anyone feeding Mercado Público into a spreadsheet, database or alert.

Use it to find tenders you can still bid on, to watch one buyer or one product category, to follow a tender until it is awarded, or to keep a daily feed of what changed. Awards and winning suppliers are included whenever the buyer has published them.

**Cost.** $0.001 per delivered tender plus a $0.005 run start, so the Console sample of 50 open tenders costs about $0.055, and 100 tenders about $0.105. Changes mode also charges $0.000025 for each tender it checks. See [Price](#price).

### Quick start

The 50 open tenders published this month:

```json
{"maxItems": 50}
```

Cameras, open processes, published in November 2026:

```json
{
  "year": 2026,
  "month": 11,
  "keyword": "cámaras",
  "status": "open",
  "maxItems": 100,
  "includeItems": true
}
```

A daily monitor of one buyer that keeps running across month changes: leave year and month empty, and schedule it.

```json
{
  "buyer": "Municipalidad de Los Ángeles",
  "status": "all",
  "mode": "changes",
  "stateKey": "los-angeles",
  "maxItems": 200
}
```

The Console opens with the current month's open tenders, 50 rows: about $0.055 and a few minutes, depending on how many of the month's open tenders the run has to check.

### Input

| Field | Type | Default | What it does |
|---|---|---:|---|
| `year` | integer | current year | Year of the monthly tender list. In Changes mode, set it only together with `month`. |
| `month` | integer | current month | Month (1-12) of the monthly tender list. In Changes mode, leave year and month empty to follow the latest months. |
| `keyword` | string | `""` | Words that must all appear in the tender title, description, buyer name or category names. Spanish accents are optional. |
| `buyer` | string | `""` | Buyer name, RUT or Mercado Público unit code, for example `Municipalidad de Máfil`, `692005007` or `4543`. |
| `region` | string | `""` | Chilean region as the buyer publishes it, for example `Biobío` or `Metropolitana`. Accents are optional. |
| `status` | string | `open` | `open` (not yet closed), `closed` (closed, void or awarded), `awarded` (only awarded), or `all`. |
| `mode` | string | `full` | `full` returns every matching tender. `changes` returns only new, amended and closed tenders against the saved history. |
| `stateKey` | string | `""` | A name for the saved change history. Leave empty to name it from the filters (and the month, when you set one). |
| `maxItems` | integer | `50` | Most rows to return, up to 5,000. In Changes mode this is the most changes to return. |
| `includeItems` | boolean | `false` | Adds every published item with its quantity, unit and UNSPSC code. The item count and codes are always included. |

All fields are optional and can be combined. An empty input returns the 50 open tenders published in the current month.

### Change tracking

Changes mode is the part that makes a recurring run useful.

- **The first run is the starting point.** It delivers every matching tender as `new` and says so in the run status.
- **Later runs deliver only what moved.** A tender is `new` when it was not delivered before, `amended` when any published value changed, and `closed` when it stops being something you follow.
- **A closed row says why.** `closedReason` is `closedBySource` when Mercado Público closed, voided, awarded, revoked or suspended it, `leftFilters` when it no longer matches your filters (for example an open-tenders search after the tender closed), and `unpublished` when Mercado Público no longer publishes it. An unpublished row carries the last values seen. A tender that later matches again comes back as `amended`.
- **Every change row names the change.** `changedFields` lists the fields that moved. `previousValues` holds the earlier value of short fields such as the title, status, dates, amount and buyer name. A change to long fields such as the description, documents or awards is named in `changedFields` without the earlier text.
- **The source's own version marks are kept.** `sourcePublishedDate`, `releaseIds`, `releaseDates`, `releaseTags`, `awardReleaseIds`, `awardReleaseTags` and `statusDetails` show the buyer's own publication history.
- **Leave the month empty for a daily monitor.** The run then follows the current month, last month's late additions, and every tender it already delivered until that tender is awarded, void or revoked, for up to three months after the month it was published. The same history carries on from one month to the next.
- **Or fix a month.** With year and month set, the run follows only that month's tenders, however long you keep running it.
- **A run that stops early stays safe.** Only tenders that were actually delivered are marked as seen. When the time limit or `maxItems` stops a run before every tender was checked, the status says how many were checked and how many are left, and the next run checks those first. A run never says "no changes" unless it checked everything.
- **A failed read is not a change.** When an award record cannot be read, an already-delivered tender keeps its earlier values and is checked again next time.
- **One history per search.** Two different searches must not share a history. Give each its own `stateKey`, or leave it empty and the filters name it for you. A history that is missing a part, or was saved for other filters, stops the run with a clear message instead of starting over and charging every tender again.

The history is saved in your own Apify account. You do not need to configure or open anything.

### What it returns

Every row has:

- **Identity:** `ocid`, `tenderId`, `noticeUrl`, `sourceUrl`, `source`, `scrapedAt`.
- **What is being bought:** `title`, `description`, `descriptionExcerpt`, `itemsCount`, `items`.
- **Buyer:** `buyerName`, `buyerLegalName`, `buyerRut`, `buyerId`, `buyerCode`, `buyerRegion`, `buyerAddress`, `buyerContactName`.
- **Categories:** `unspscCodes` and `categories` (code, scheme and the source's own category text).
- **Procedure and status:** `procurementMethod`, `procurementMethodDetails`, `status`, `statusDetails`.
- **Dates:** `publishedAt`, `sourcePublishedDate`, `tenderStartAt`, `tenderStartChile`, `tenderEndAt`, `tenderEndChile`.
- **Money:** `estimatedAmount` and `currency`.
- **Awards:** `awardsCount`, `awards`, `suppliers`, `documents`, `awardReleaseIds`, `awardReleaseDates`, `awardReleaseTags`, `awardError`.
- **Publication history:** `releaseIds`, `releaseDates`, `releaseTags`.
- **Changes mode:** `changeType`, `changedFields`, `previousValues`, `closedReason`.

Dates come in two forms. `publishedAt`, `tenderStartAt` and `tenderEndAt` keep the source's UTC stamp. The matching `tenderStartChile` and `tenderEndChile` give the same moment in Chile civil time with its offset, for example `2026-11-23T13:00:00-03:00` in November or `-04:00` in July.

### Output example

```json
{
  "ocid": "ocds-70d2nz-3623-39-LP26",
  "tenderId": "3623-39-LP26",
  "title": "ADQUISICIÓN DE CAMION ALJIBE COMUNA DE MÁFIL",
  "description": "Adquirir un nuevo camión aljibe de acuerdo a las especificaciones, garantías y asistencia técnicas que se indican en adelante; puestas y aprobadas en la municipalidad. Según antecedentes adjuntos.",
  "descriptionExcerpt": "Adquirir un nuevo camión aljibe de acuerdo a las especificaciones, garantías y asistencia técnicas que se indican en adelante; puestas y aprobadas en la municipalidad. Según antecedentes adjuntos.",
  "buyerName": "I MUNICIPALIDAD DE MAFIL | I MUNICIPALIDAD DE MAFIL",
  "buyerLegalName": "I MUNICIPALIDAD DE MAFIL",
  "buyerRut": "692005007",
  "buyerId": "CL-MP-4543",
  "buyerCode": "4543",
  "buyerRegion": "Región de Los Ríos",
  "buyerAddress": "San Martin 263",
  "buyerContactName": "ESTEBAN EMILIO GUTIERREZ CABRERA",
  "unspscCodes": ["25101611"],
  "categories": [
    {"code": "25101611", "scheme": "UNSPSC",
     "name": "Vehículos y equipamiento en general / Vehículos motorizados / Vehículos para transporte de carga / Camiones de transporte"}
  ],
  "procurementMethod": "open",
  "procurementMethodDetails": "Licitación Pública Mayor 1000 UTM (LP)",
  "status": "active",
  "statusDetails": "5-Publicada",
  "publishedAt": "2026-11-03T12:00:03Z",
  "sourcePublishedDate": "2026-11-03T12:33:52Z",
  "tenderStartAt": "2026-11-03T12:00:03Z",
  "tenderStartChile": "2026-11-03T09:00:03-03:00",
  "tenderEndAt": "2026-11-23T16:00:00Z",
  "tenderEndChile": "2026-11-23T13:00:00-03:00",
  "estimatedAmount": 197678391.0,
  "currency": "CLP",
  "itemsCount": 1,
  "items": [
    {"id": "43773394",
     "description": "Vehículos y equipamiento en general / Vehículos motorizados / Vehículos para transporte de carga / Camiones de transporte",
     "quantity": 1.0, "unit": "Unidad", "unspscCode": "25101611", "unspscScheme": "UNSPSC"}
  ],
  "awardsCount": 1,
  "awards": [
    {"id": "9728908", "title": "ADQUISICIÓN DE CAMION ALJIBE COMUNA DE MÁFIL",
     "description": "Adquirir un nuevo camión aljibe ...", "status": "cancelled",
     "statusDetails": "15-Revocada", "date": null, "amount": null, "currency": null}
  ],
  "suppliers": null,
  "documents": null,
  "releaseIds": ["06766526-3623-39-LP26", "0aa988d2-3623-39-LP26"],
  "releaseDates": ["2026-11-03T12:00:03Z", "2026-11-03T12:00:03Z"],
  "releaseTags": ["tender", "tenderUpdate"],
  "awardReleaseIds": ["b1f406c2-9728908"],
  "awardReleaseDates": [null],
  "awardReleaseTags": ["award"],
  "awardError": null,
  "noticeUrl": "https://www.mercadopublico.cl/Procurement/Modules/RFB/DetailsAcquisition.aspx?idlicitacion=3623-39-LP26",
  "source": "mercadopublico.cl",
  "scrapedAt": "2026-11-04T18:19:05-03:00",
  "changeType": null,
  "changedFields": null,
  "previousValues": null,
  "closedReason": null
}
```

### Empty fields and why

- `estimatedAmount` and `currency` are empty when the buyer did not publish an amount. The scraper never estimates one.
- `awards`, `suppliers` and `documents` appear only when the buyer's award records publish them. A tender that has not been awarded yet has no award rows. An award can also be revoked; its `status` and `statusDetails` say so, and the tender itself can stay open.
- `items` is empty unless `includeItems` is on. The item count and UNSPSC codes are always there.
- `buyerAddress`, `buyerContactName`, `description` and other buyer-published values are empty only when the source leaves them blank.
- A tender whose page cannot be read keeps its place in the status line as unavailable detail; the run does not turn a failed read into an empty month.

### Limits

- Up to 5,000 tenders per run.
- Full mode returns at most `maxItems` tenders, counting only rows that match the filters.
- Changes mode checks every tender it follows and returns at most `maxItems` changes. A busy month holds about 10,000 tenders, more than one run can check in the default hour; a run that stops at the time limit keeps what it delivered, and the next run continues with the tenders not yet checked.
- Large months take longer because every tender is checked individually. The default one-hour timeout is a ceiling, not a target.
- Keyword, buyer, region and status narrow the tenders inside the chosen month; they do not change which month is read.

### Published information

**Fuente: Dirección ChileCompra.** Data from Mercado Público, under ChileCompra's [API terms of use](https://www.chilecompra.cl/api/).

Everything Mercado Público shows publicly is returned as published, in Spanish, including buyer names, RUTs, addresses, contact names, descriptions and award suppliers. Nothing is masked, shortened, translated or rewritten. The listing text and the tender description keep the source's wording; only runs of whitespace are collapsed.

### FAQ

**How do I get only new tenders each day?** Use `"mode": "changes"` with a `stateKey`, leave year and month empty, and schedule the run. The first run is the starting point; later runs deliver only changes, including across the start of a new month.

**How much does a run cost?** Full mode: $0.001 per delivered tender plus a $0.005 run start, so 50 tenders cost $0.055 and 100 cost $0.105. Changes mode adds $0.000025 per tender checked, changed or not (about $0.035 for 1,400 tenders and $0.25 for 10,000). Nothing is charged for a tender whose detail page could not be read.

**Why do I see a tender again?** It was amended or closed since the last run, or the history name changed. Keep the same `stateKey` to continue the same history.

**Why is there no award for a tender I know was awarded?** Awards appear when the buyer publishes the award records, sometimes weeks after the tender. In Changes mode the award arrives as an `amended` row when it is published.

**What happens when nothing matches?** The run succeeds with an empty dataset and a plain status message such as "No Mercado Público tenders match these filters".

**Does it include closed tenders?** Yes, with `"status": "all"` or `"status": "closed"`. The default is open tenders only.

**Can I monitor several searches separately?** Yes. Give each search its own `stateKey` so their histories never mix.

**Where does the official notice link go?** To the procurement's page on Mercado Público, where the buyer's documents and the process history are published.

**Which regions and categories can I filter on?** `region` matches the buyer's region as Mercado Público publishes it, for example `Biobío` (accents optional), and `keyword` also searches the published UNSPSC category names, so `cámaras`, `aseo` or `alimentos` find tenders by what is being bought.

### Price

Full mode: **$0.001 per delivered tender** plus a **$0.005 run start**. The run-start event is charged per GB of memory; the default 512 MB run is one start. The run start is charged even when a run saves no results.

Changes mode: each run re-reads the followed window and also charges **Tender checked (changes mode)**, **$0.000025 per successful tender read**, changed or not. Failed detail reads are not charged. This includes the first-run starting point. A delivered change also costs the normal $0.001 per tender; an unchanged tender has no delivered-tender charge. Filters do not shrink the read: keyword, buyer, region and status are applied after the detail is fetched.

The window grows through the month, so a late-month run costs more than an early one: about **1,400 tenders early in the month = $0.035 in checks plus the start**; about **10,000 late in the month = $0.25 in checks plus the start**, before any delivered changes. If the run's maximum charge stops the checks, the run succeeds with a status saying how many it checked and how many are left for the next run.

For bulk downloads, schedule runs between **22:00 and 07:00 Chile time**, following ChileCompra's recommendation. See the Pricing tab for current prices.

### Support

For questions or issues, contact us from the Actor page.

# Actor input Schema

## `year` (type: `integer`):

Calendar year of the monthly tender list. Leave empty for the current year. In changes mode, set it only together with the month.

## `month` (type: `integer`):

Calendar month (1-12) of the monthly tender list. Leave empty for the current month. In changes mode, leave year and month empty to follow the latest months across month changes.

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

Words to look for in the tender title, description, buyer name or category names. Every word must appear. Spanish accents are optional. Leave empty for all tenders.

## `buyer` (type: `string`):

Buyer name, RUT or unit code, for example Municipalidad de Mafil or 691701018. Leave empty for all buyers.

## `region` (type: `string`):

Chilean region as the buyer publishes it, for example Biobío or Metropolitana. Leave empty for all regions.

## `status` (type: `string`):

Open follows tenders the source still lists as open. Closed covers closed, void and awarded processes; Awarded returns only awarded ones; All includes everything.

## `mode` (type: `string`):

Full list returns every matching tender. Only changes returns just new, amended or closed tenders against the saved history.

## `stateKey` (type: `string`):

A name for the saved change history, so separate searches keep separate histories. Leave empty to derive it from the filters.

## `maxItems` (type: `integer`):

Most rows to return, up to 5,000. In changes mode this is the most changes to return.

## `includeItems` (type: `boolean`):

Adds every published item with its quantity, unit and UNSPSC code. Item count and codes are always included.

## Actor input object example

```json
{
  "keyword": "",
  "buyer": "",
  "region": "",
  "status": "open",
  "mode": "full",
  "stateKey": "",
  "maxItems": 50,
  "includeItems": 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 = {
    "keyword": "",
    "buyer": "",
    "region": "",
    "status": "open",
    "mode": "full",
    "stateKey": "",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("automatic/chile-mercado-publico-tenders-scraper").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 = {
    "keyword": "",
    "buyer": "",
    "region": "",
    "status": "open",
    "mode": "full",
    "stateKey": "",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("automatic/chile-mercado-publico-tenders-scraper").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 '{
  "keyword": "",
  "buyer": "",
  "region": "",
  "status": "open",
  "mode": "full",
  "stateKey": "",
  "maxItems": 50
}' |
apify call automatic/chile-mercado-publico-tenders-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automatic/chile-mercado-publico-tenders-scraper"
        }
    }
}
```

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/Og1kJJcJHLU1SzDsf/builds/YNQ5W2hzhTAfLonNh/openapi.json
