# El Salvador Procurement Scraper (COMPRASAL) (`publicmoney/comprasal-el-salvador-scraper`) Actor

Extract El Salvador public procurement from COMPRASAL: open processes with stage schedules and deadlines, and award records with supplier, amount, shareholders and beneficial owner.

- **URL**: https://apify.com/publicmoney/comprasal-el-salvador-scraper.md
- **Developed by:** [Public Money](https://apify.com/publicmoney) (Apify)
- **Categories:** Business
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## 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.
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?

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

This Actor reads El Salvador's public procurement from **COMPRASAL**, the national system run by DINAC: **processes open for offers**, with institution, modality, status and the full stage schedule (offer deadline, opening, evaluation, award), and **award records**, with supplier, award amount and date, and the supplier's shareholders and beneficial owner as COMPRASAL publishes them.

### What it does

- **Open processes**: 509 open when this was verified, each with every stage's start and end; optionally the internal code, publication date, planned contract date and awarded amount.
- **Award records**: 133,563, newest registered first: process, institution, award date, supplier legal and trade name, amount in USD, shareholders, beneficial owner.
- **Filters**: keyword in the process name, institution; in awards mode also institution id and modality id, searched by COMPRASAL.

### Use cases

| You need to | How this Actor does it |
| --- | --- |
| Find open Salvadoran tenders | Open mode, read `offerDeadline` |
| See who wins government contracts | Awards mode, group by `supplierName` |
| Due diligence on a supplier | Awards mode, `shareholders` and `beneficialOwner` |
| Track one institution | `institutionId` (awards) or `institution` (open) |

### Input

| Field | Type | Default | What it controls |
| --- | --- | --- | --- |
| `mode` | string | `open` | `open` or `awards` |
| `keyword` | string | empty | Process name |
| `institution` | string | empty | Institution name |
| `institutionId` | integer | empty | Institution id (awards) |
| `modalityId` | integer | empty | Modality id (awards) |
| `fetchDetails` | boolean | `true` | Read each open process |
| `maxItems` | integer | `500` | Caps how many records are returned, and so the cost |

```json
{
    "mode": "awards",
    "keyword": "suministro"
}
```

### Output (open process)

```json
{
    "processCode": "704-2026-P0016",
    "processName": "Suministro de agendas y calendarios",
    "institution": "Fondo Salvadoreño para Estudios de Preinversión (FOSEP)",
    "modality": "Comparación de precios",
    "status": "Activo",
    "stage": "En ejecución",
    "offerDeadline": "2026-10-06T05:00:00.000Z",
    "internalCode": "CP-16-2026",
    "publishedAt": "2026-09-29T13:37:15.000Z"
}
```

### Output (award record)

```json
{
    "processCode": "300-2026-P0168",
    "processName": "SUMINISTRO DE MEDICAMENTOS EQUIPOS E INSUMOS MÉDICOS PARA EL PROCESO ELECTORAL 2026 2027",
    "institution": "Tribunal Supremo Electoral (TSE)",
    "awardDate": "2026-09-25",
    "supplierName": "Laboratorios Suizos, S.A. de C.V.",
    "supplierTradeName": "Laboratorios Suizos",
    "awardAmount": 1970
}
```

### Coverage and limits

- Award records come newest registered first; COMPRASAL does not order them by award date, so there is no award-date filter.
- Shareholders and beneficial owners are returned as COMPRASAL publishes them, names and nationality only.
- Texts are in Spanish, as published.

### Pricing

Pay per event: one `tender-scraper` event per record written to the dataset. The optional schema.org block is charged once per run.

# Actor input Schema

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

Processes open for offers (509 when verified) or award records with supplier and amount (133,563, newest first).

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

Matched in the process name; in awards mode searched by COMPRASAL ('suministro' 43,133 awards).

## `institution` (type: `string`):

Matched in the institution name, e.g. 'Ministerio de Salud'.

## `institutionId` (type: `integer`):

COMPRASAL institution id, searched by COMPRASAL, e.g. 6163 (110 awards).

## `modalityId` (type: `integer`):

Contracting modality id: 11 Licitación competitiva; 12 Comparación de precios; 16 Servicios de Consultoría selección basada en precio fijo; 17 Servicios de Consultoria selección basada en calificacion de consultores; 18 Compra en línea; 14 Servicios de consultoria selección basada en calidad y costo; 15 Servicios de consultoría selección basada en la calidad; 20 Servicios de consultoría de consultor individual; 21 Servicios de consultoría selección al menor costo; 22 Convenios; 23 Subasta Inversa; 13 Contratación directa; 19 Servicios de consultoría de fuente única; 24 Subasta en plataformas privadas; 25 Proyectos de utilidad pública; 26 Adquisiciones de servicios en el exterior; 27 Catálogo Electrónico.

## `fetchDetails` (type: `boolean`):

Open mode: adds internal code, publication date, start and planned contract dates, awarded amount and every stage.

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

Caps how many records are written to the dataset, and so caps the cost. Set to 0 for everything matched.

## `schemaOrg` (type: `boolean`):

Appends a `schemaOrg` object to every record, mapping it to schema.org (Demand). Charged once per run, not per record.

## Actor input object example

```json
{
  "mode": "open",
  "fetchDetails": true,
  "maxItems": 500,
  "schemaOrg": false
}
```

# Actor output Schema

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

Open processes or award records matched by the run, one item per record, in the default dataset.

# 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 = {
    "maxItems": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicmoney/comprasal-el-salvador-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 = { "maxItems": 500 }

# Run the Actor and wait for it to finish
run = client.actor("publicmoney/comprasal-el-salvador-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 '{
  "maxItems": 500
}' |
apify call publicmoney/comprasal-el-salvador-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,publicmoney/comprasal-el-salvador-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/MgtrCEM7jqOGwuigC/builds/PC0l9SPtCwTu1bvSf/openapi.json
