# Uruguay Open Data Scraper - CKAN Datos Abiertos (`parseforge/uruguay-open-data-scraper`) Actor

Scrape catalogodatos.gub.uy, Uruguay's national open data portal: 2,702 datasets over the CKAN API with full metadata, resources, live DataStore tables, publishers, themes, tags, formats, licences and link checks.

- **URL**: https://apify.com/parseforge/uruguay-open-data-scraper.md
- **Developed by:** [ParseForge](https://apify.com/parseforge) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.23 / 1,000 datasets

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?

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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

[![ParseForge](https://raw.githubusercontent.com/ParseForge/apify-assets/main/banner.jpg)](https://apify.com/parseforge?fpr=vmoqkp)

### Uruguay Open Data Scraper - CKAN Datos Abiertos API

**Scrape every one of the 2,702 datasets on catalogodatos.gub.uy, Uruguay's national open data portal, in three requests.** Every row carries the full catalogue record: publisher, licence, themes, tags, declared update cadence and each downloadable file with its format, size and direct URL. No login, no API key, no registration. Export to CSV, JSON, Excel, or XML.

The portal's own CKAN API is open but awkward: it caps a page at 1,000, pages its organization list at 25 whatever you ask for, spells one file format 48 different ways, and answers an unknown filter field with zero rows instead of an error. This reads all of it, normalises it, and adds what the API will not tell you on its own: the real column schema behind every queryable table, and whether the download links still work.

| Who uses it | What they scrape Uruguay open data for |
|---|---|
| Data journalists | Which ministries publish what, and which datasets have gone stale |
| Civic tech and NGOs | A complete, refreshable index of Uruguayan public data |
| Researchers and academics | Statistics, health, housing and labour datasets with their real column schemas |
| Data engineers | A machine-readable manifest of 14,373 files to feed an ingestion pipeline |
| Open data auditors | Link rot, missing licences, overdue update cadences, harvest provenance |

### What it does

This Actor reads Uruguay's CKAN catalogue and returns it as flat rows, in ten different shapes chosen by one **Output** setting. Point it at the whole catalogue, at a filtered slice of it, or at a list of datasets you name by URL, slug or UUID. Every dataset row carries:

- 🧾 **Core fields:** title, description, slug, portal URL, publishing organization with its own description and logo, author and maintainer with emails, licence, version, and creation and modification dates.
- 🗂️ **Classification:** the 22 portal themes, the full tag list, and every file format present, deduplicated.
- 📦 **Files nested inline:** each one with format, MIME type, byte size, checksum, direct download URL, portal URL and dates.
- 🧮 **Computed signals:** days since last update, the declared cadence in plain language, an overdue flag, total bytes, and whether the dataset has queryable DataStore tables.
- 🔎 **Provenance:** whether the record was harvested from another portal, and which one.

Results export to CSV, JSON, Excel, or XML, or stream from the API.

### What you can do with Uruguay open data

**🗺️ Build a complete index of the catalogue.**

One run with no filters returns all 2,702 datasets in three requests. Schedule it and diff the `updatedAt` column to see exactly what the state published or changed this week.

**🔬 Find the data before you download it.**

Turn on the column schema block and the Actor reads each DataStore table's real column names, PostgreSQL types and exact row count without downloading a byte. Across just 25 popular datasets that surfaced 101 live tables holding 6.5 million rows, including a vote breakdown with 519,750 rows and 8 typed columns.

**🔗 Audit link rot and staleness.**

The portal harvests six external sites and never re-verifies what it copied. Switch on the link check and every file URL is fetched and reported with its HTTP status. Sampling 90 URLs across the full age range of the catalogue, 8 were not retrievable.

**📇 Map who publishes what.**

The Contacts output deduplicates the people and units named on the datasets into a directory with emails, roles, dataset counts and the themes they cover. 316 distinct contacts across the whole catalogue.

### Why choose this scraper

| | What you get |
|---|---|
| **Ten outputs, one Actor** | Datasets, files, DataStore tables, contacts, organizations, themes, tags, formats, licences and harvest sources. |
| **Real column schemas** | Column names, PostgreSQL types and exact row counts read from the portal DataStore, with no download. |
| **Link checking** | Every file URL fetched and reported with status, content type, size, redirect and latency. |
| **Filters measured, not guessed** | Every filter in the schema was tested against the unfiltered total of 2,702, and only verified values are offered. |
| **Format names that work** | One canonical `CSV` matches all nine spellings the publishers actually typed, and finds 2,550 datasets instead of 2,543. |
| **Four export formats** | CSV, JSON, Excel and XML, from the dashboard or the API. |

### How it compares

The generic CKAN scrapers on the Store point at any portal and return the raw package record, which is a reasonable thing to want and cheaper per row. This one is built for this catalogue specifically, so it knows the things a generic reader cannot: that `update_frequency` is a Uruguay-only field holding a number of days, that the organization list silently pages at 25, that `include_tracking` breaks the search endpoint, and which four of the six harvest sources are dead test entries. It also does work the others do not attempt at all, reading DataStore schemas and checking whether the files are still there. If you only need raw CKAN packages from any portal, the generic ones are the better buy.

| Feature | ParseForge | straightforward\_hydra | datapilot | doggo |
|---|---|---|---|---|
| Raw CKAN dataset record | Yes | Yes | Yes | Yes |
| DataStore column schema and row counts | Yes | No | No | No |
| Sample data rows from the live table | Yes | No | No | No |
| File link checking | Yes | No | No | No |
| Verified Uruguay filters and enums | Yes, 68 publishers, 22 themes | Generic | Generic | Generic |
| Separate outputs beyond datasets | 10 | 1 | 1 | 1 |
| Billable events | 19 | 2 | 2 | 2 |

### What a dataset looks like

Every dataset returns as one JSON row with its files nested. Here is a real record from a verified run. Three things are shortened for space and nothing else is changed: the description is truncated, the publisher's own long description is dropped, and only the first of its four files is shown, with that file's portal URL and position fields left out.

```json
{
  "datasetId": "accd0e24-76be-4101-904b-81bb7d41ee88",
  "name": "inumet-observaciones-meteorologicas-temperatura-del-aire-en-el-uruguay",
  "title": "Observaciones meteorológicas - Temperatura del aire en el Uruguay",
  "url": "https://catalogodatos.gub.uy/dataset/inumet-observaciones-meteorologicas-temperatura-del-aire-en-el-uruguay",
  "apiUrl": "https://catalogodatos.gub.uy/api/3/action/package_show?id=inumet-observaciones-meteorologicas-temperatura-del-aire-en-el-uruguay",
  "description": "El siguiente conjunto presenta la información sobre las observaciones meteorológicas llevadas a cabo por estaciones meteorológicas automáticas del Ins …",
  "organizationName": "inumet",
  "organizationTitle": "INUMET",
  "organizationUrl": "https://catalogodatos.gub.uy/organization/inumet",
  "author": "INUMET",
  "authorEmail": "contacto@inumet.gub.uy",
  "maintainer": "Área de Informática",
  "maintainerEmail": "informatica.direccion@inumet.gub.uy",
  "licenseId": "odc-uy",
  "licenseTitle": "Licencia de DAG de Uruguay",
  "isOpenLicence": "Yes",
  "sourceUrl": "Not Disclosed",
  "version": "1.0",
  "categories": ["medio-ambiente"],
  "categoryTitles": ["Medio Ambiente"],
  "tags": ["Aire", "Cambio climático", "Medio ambiente", "Meteorología", "Temperatura"],
  "tagCount": 5,
  "resourceCount": 4,
  "formats": ["CSV", "JSON", "XLSX", "XML"],
  "totalSizeBytes": 63031037,
  "hasDatastore": "Yes",
  "datastoreTableCount": 2,
  "createdAt": "2024-10-22T17:59:12.802088",
  "updatedAt": "2026-08-27T04:15:14.268125",
  "daysSinceUpdate": 0,
  "updateFrequencyDays": 1,
  "updateFrequencyLabel": "Daily (Diaria)",
  "updateOverdue": "No",
  "harvested": "No",
  "harvestSourceTitle": "Not Disclosed",
  "resources": [
    {
      "resourceId": "2435e1f5-24c7-4991-8eb7-7708b556b32f",
      "name": "Metadatos de temperatura del aire",
      "format": "JSON",
      "mimeType": "application/json",
      "downloadUrl": "https://catalogodatos.gub.uy/dataset/accd0e24-76be-4101-904b-81bb7d41ee88/resource/2435e1f5-24c7-4991-8eb7-7708b556b32f/download/metadatos_inumet_temperatura_del_aire.json",
      "sizeBytes": 1319,
      "checksum": "Not Disclosed",
      "queryableApi": "No",
      "datastoreApiUrl": "N/A",
      "createdAt": "2025-08-30T04:17:03.548584",
      "lastModifiedAt": "2026-08-27T04:07:51.942993"
    }
  ],
  "scrapedAt": "2026-08-27T16:21:23.929Z"
}
```

Fields the portal leaves blank come back as `Not Disclosed`, and questions that do not apply to a row come back as `N/A`, so an empty CSV cell always means the same thing. `sourceUrl` is empty here because this publisher did not fill it in.

### Configure the run

Pick an **Output** first: it decides what a row is and which event you pay. Then either name the datasets you want in **Dataset URLs or slugs**, or leave that empty and narrow the whole catalogue with filters, which combine with AND while multiple values inside one filter combine with OR. Leave everything empty and you get all 2,702 datasets. Optional blocks are all off by default and each is billed only when it actually returned something. The Input tab lists every parameter.

Pull three named datasets, given as a portal URL, a bare slug and a UUID:

```json
{ "dataset": "datasets", "startUrls": ["https://catalogodatos.gub.uy/dataset/agesic-guia-de-tramites", "montevideo-audiovisual", "accd0e24-76be-4101-904b-81bb7d41ee88"], "maxItems": 10 }
```

Health and environment datasets from three ministries, only ones with live queryable tables, with their column schemas read:

```json
{ "dataset": "datasets", "categories": ["salud", "medio-ambiente"], "organizations": ["msp", "ambiente", "inumet"], "onlyWithDatastore": true, "includeDatastoreSchema": true, "maxItems": 200 }
```

Every CSV file in the catalogue, checked to see whether it still downloads:

```json
{ "dataset": "resources", "formats": ["CSV"], "checkResourceLinks": true, "onlyLiveResources": true, "maxItems": 5000 }
```

### Pricing

Pay-per-event: **$0.007 per dataset**, dropping to $0.00623 at higher volume, plus a $0.02 run-start fee and $0.004 per catalogue page scanned. A page holds up to 1,000 datasets, so the whole catalogue is three pages. You pay only for rows written to your dataset.

| Datasets collected | Approximate cost |
|---|---|
| 100 | $0.72 |
| 1,000 | $7.02 |
| All 2,702 | $18.95 |

Other outputs bill their own rate: files at $0.005, DataStore tables at $0.008, contacts at $0.006, directory rows from $0.003. All 14,373 files in the catalogue cost about $71.90. Optional blocks are extra and only charged when they return: link checks at $0.006, column schemas at $0.006, sample rows at $0.008, view counts at $0.004. At higher monthly volume every rate drops by up to 11%. New Apify accounts start with $5 in free credit.

### Free users

Free-plan runs return up to 10 rows as a preview. [Upgrade your Apify plan](https://console.apify.com/sign-up?fpr=vmoqkp) to collect up to 1,000,000 rows per run.

### Run it

1. [Create a free Apify account with $5 in credit](https://console.apify.com/sign-up?fpr=vmoqkp).
2. Open the [Uruguay Open Data Scraper](https://apify.com/parseforge/uruguay-open-data-scraper?fpr=vmoqkp).
3. Pick an **Output**, add any filters and optional blocks, set **Max Items**, and click **Start**.
4. Export the results as CSV, Excel, JSON, or XML from the **Dataset** tab.

Run it programmatically through the [Apify API](https://docs.apify.com/api/v2) or the [ApifyClient](https://docs.apify.com/api/client/js) for JavaScript and Python.

### Use with AI agents (MCP)

Give an AI agent live access to Uruguay's open data catalogue through the Model Context Protocol. Add the Actor to Claude, Cursor, or any MCP client:

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=parseforge/uruguay-open-data-scraper"
```

Then prompt it in plain language:

- *"List every health dataset the Uruguayan government publishes and say which ones are overdue for an update."*
- *"Find Uruguayan open datasets that have a queryable table with a date column, and show me the column names."*
- *"Which Uruguayan ministries publish the most datasets, and what formats do they use?"*

Copy this into ChatGPT, Claude, or Cursor to start:

```
Use the Apify Actor "parseforge/uruguay-open-data-scraper" to read Uruguay's national open data catalogue at catalogodatos.gub.uy. Input: { "dataset": "<datasets|resources|datastore-tables|contacts|organizations|categories|tags|formats|licenses|harvest-sources>", "searchQuery": "<text>", "organizations": ["<slug>"], "categories": ["<theme>"], "maxItems": <n> }. It returns title, description, organization, licence, themes, tags, update cadence and every file with its format, size and download URL. Call it with the ApifyClient and my APIFY_TOKEN.
```

### Troubleshooting

**Why am I getting no results?**

Check your filters first. If you used **Filter query**, note that this portal answers an unknown Solr field name with zero rows rather than an error, so a typo looks like an empty catalogue. Tag values must match the portal's own spelling exactly, accents and capitals included: run the Tags output to see them.

**Why fewer rows than I asked for?**

**Only datasets with queryable tables** and **Exclude formats** are applied after the search, so they remove rows the index already returned. The run over-fetches to compensate, but it cannot invent datasets that do not match. Free-plan runs also stop at 10.

**Why is a field empty?**

It is not empty, it says `Not Disclosed` or `N/A`. The first means the publisher left that field blank, which is common for `sourceUrl`, `version` and `checksum`. The second means the question does not apply, for example a DataStore API URL on a file that has no table.

**Why is the run slow?**

The catalogue sweep itself is fast: 14,373 file rows in three requests and 43 seconds. The optional blocks are what cost time, because each one is a separate request per file. Turning on link checking, schemas, previews and visualizations together means four extra requests per file. Turn on only what you need, or lower **Max Items**.

**A field stopped filling.**

The portal changed its CKAN response shape or an endpoint moved behind its edge gateway. Email us with your run ID so we can update the parser.

### FAQ

| Question | Answer |
|---|---|
| Do I need an API key or an account on the portal? | No. The CKAN API is fully anonymous and needs no key, cookie or proxy. |
| How is this different from calling the CKAN API myself? | It handles the traps: the 1,000-row page cap, the organization list that pages at 25, 48 raw spellings for 30 formats, and filters that fail silently. It also adds DataStore schemas and link checks, which CKAN does not expose in the search response. |
| How many datasets are there? | 2,702 datasets and 14,373 files, from 68 publishing organizations, measured 2026-08-27. |
| What is a DataStore table? | A file the portal has loaded into its own database, so it can be queried and filtered live. 101 of 400 files in a sample run had one. The Actor returns their column names, types and exact row counts. |
| Can I get the actual data, not just the metadata? | Yes, for DataStore-backed files: switch on sample rows and you get the records themselves, verbatim, up to 100 per table. For everything else the row carries a direct download URL. |
| Are the download links reliable? | Not always. Of 90 file URLs sampled across the catalogue's full age range, 8 did not answer. Switch on link checking to find out which. |
| Is the catalogue in Spanish? | Yes. Titles, descriptions and tags are Spanish. Theme names are returned in both Spanish and English. |
| Can I filter by date? | Yes, on both the metadata creation and modification dates, as `YYYY-MM-DD`. |
| Can I scrape specific datasets rather than search? | Yes. Put their portal URLs, slugs or UUIDs in **Dataset URLs or slugs**, mixed freely. It works with every Output, so the same list can give you their files or their DataStore tables. |
| How fast is it? | 335 rows a second on the file output, and the whole 2,702-dataset catalogue in three requests. Optional blocks add a request per file and slow it down proportionally. |
| Is this an official Uruguayan government product? | No. It is unofficial and reads only public data from the portal's public API. |

### Related actors

- [GovData Germany Scraper](https://apify.com/parseforge/govdata-germany-scraper?fpr=vmoqkp): Germany's national CKAN portal with DCAT-AP.de metadata.
- [Chile Open Data Scraper](https://apify.com/parseforge/chile-datos-gob-cl-scraper?fpr=vmoqkp): datos.gob.cl datasets, publishers and resources.
- [Argentina Open Data Scraper](https://apify.com/parseforge/argentina-datos-gob-ar-scraper?fpr=vmoqkp): datos.gob.ar catalogue records and files.
- [Colombia Open Data Scraper](https://apify.com/parseforge/colombia-datos-gov-co-scraper?fpr=vmoqkp): datos.gov.co datasets and their metadata.
- [EU Open Data Portal Scraper](https://apify.com/parseforge/euopendata-datasets-scraper?fpr=vmoqkp): data.europa.eu datasets across every member state.

Browse the full [ParseForge collection](https://apify.com/parseforge?fpr=vmoqkp) for more scrapers.

🆘 **Need help?** Email parseforge@protonmail.com with your run ID, your input, and what you expected.

⚠️ **Disclaimer.** This Actor is unofficial and is not affiliated with, endorsed by, or sponsored by AGESIC or the government of Uruguay. It collects only publicly available data from the portal's public API. You are responsible for using the data in compliance with the portal's terms and applicable laws, including GDPR, CCPA, and PIPL. Contact fields come from the datasets' own public metadata; do not use them to identify, profile, or target individuals.

# Actor input Schema

## `dataset` (type: `string`):

What each row should be. Datasets is the full catalogue record with every file nested inside it. Resources gives one row per downloadable file. DataStore tables lists only the resources the portal will answer live queries about, with their real column names, types and row counts. Contacts deduplicates the people and units named on the datasets scanned. The remaining six are directories of the catalogue itself.

## `startUrls` (type: `array`):

Target specific datasets instead of searching. Accepts portal URLs (https://catalogodatos.gub.uy/dataset/agesic-guia-de-tramites), bare slugs (agesic-guia-de-tramites) or dataset UUIDs, mixed freely. Leave empty to search the whole catalogue. Combines with the filters below.

## `searchQuery` (type: `string`):

Free text searched across title, description, tags and publisher, exactly as the portal's own search box does. Spanish works best: the catalogue is in Spanish. Leave empty to take everything. Example: agua potable

## `titleContains` (type: `string`):

Narrow to datasets whose title matches this text. Measured: title:vivienda returns 110 of 2,702.

## `descriptionContains` (type: `string`):

Narrow to datasets whose description matches this text. Measured: notes:"agua potable" returns 50 of 2,702.

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

Free users: limited to 10 items (preview). Paid users: up to 1,000,000. This is the hard ceiling on rows written and therefore on cost.

## `organizations` (type: `array`):

Filter to one or more of the 73 publishing bodies. Multiple values are ORed. Counts are the datasets each held on 2026-08-27.

## `categories` (type: `array`):

The 22 themes the portal groups datasets under. Multiple values are ORed. Counts measured 2026-08-27.

## `tags` (type: `array`):

Keywords from the catalogue vocabulary, matched exactly as the portal stores them, accents and capitals included. 1,487 tags exist, which is too many for a dropdown, so run the Tags output first to see the real spellings. Multiple values are ORed. Example: Salud

## `formats` (type: `array`):

Keep only datasets carrying at least one file in these formats. Each canonical name expands to every raw spelling the publishers actually typed, so CSV also catches .csv, CSV ZIP and CSV, XML, JSON: 2,550 datasets instead of the 2,543 an exact match finds.

## `excludeFormats` (type: `array`):

Drop any dataset that carries a file in one of these formats. Applied after the search, on the full row, so it costs nothing extra. Case insensitive. Example: PDF

## `licenses` (type: `array`):

Filter by the licence declared on the dataset. 2,649 of 2,702 carry the Uruguayan open government data licence, so this mostly matters when you want the handful that do not.

## `updateFrequencies` (type: `array`):

The publisher's declared refresh interval, which this portal stores as a number of days. Multiple values are ORed. Counts measured 2026-08-27.

## `authorContains` (type: `string`):

Match the free-text author field on the dataset. Example: INE

## `maintainerContains` (type: `string`):

Match the free-text maintainer field on the dataset. Example: AGESIC

## `minResources` (type: `integer`):

Drop datasets with fewer than this many downloadable files. Measured: 125 datasets carry 5 or more.

## `modifiedAfter` (type: `string`):

Only datasets whose metadata changed on or after this date. YYYY-MM-DD. Measured: 323 datasets changed since 2026-01-01.

## `modifiedBefore` (type: `string`):

Only datasets whose metadata last changed on or before this date. YYYY-MM-DD.

## `createdAfter` (type: `string`):

Only datasets first published on or after this date. YYYY-MM-DD. Measured: 54 datasets were created during 2025.

## `createdBefore` (type: `string`):

Only datasets first published on or before this date. YYYY-MM-DD.

## `onlyOpenLicence` (type: `boolean`):

Keep only datasets the portal marks as openly licensed. 2,676 of 2,702 qualify, so this exists to exclude the 26 that do not rather than to narrow a search.

## `onlyWithDatastore` (type: `boolean`):

Keep only datasets holding at least one resource loaded into the portal's DataStore, which means it can be queried live and filtered by column without downloading the file. No Solr field exposes this, so it is applied on the full row after the search and costs nothing extra.

## `sortBy` (type: `string`):

Result order. Only the ten orders below were kept: an unknown sort field does not error on this portal, it silently falls back to relevance, so a typo would look like it worked.

## `filterQuery` (type: `string`):

A raw Solr fq clause ANDed onto everything above, for filters this schema does not expose. Careful: an unknown field name returns zero rows on this portal instead of an error. Example: num\_resources:\[10 TO \*]

## `checkResourceLinks` (type: `boolean`):

Optional, billed per file checked. Fetches every resource URL and reports HTTP status, content type, byte size, redirect target and latency. Worth it because the catalogue harvests six external portals and never re-verifies what it copied: of 90 URLs sampled on 2026-08-27, 8 were not retrievable. Applies to the Datasets and Resources outputs.

## `onlyLiveResources` (type: `boolean`):

Needs the link check above. Skips datasets where every checked file failed, and individual dead files on the Resources output. Rows dropped this way are not written and not billed as rows.

## `includeDatastoreSchema` (type: `boolean`):

Optional, billed per table read. For every resource loaded into the portal's DataStore, returns its actual column names, PostgreSQL types, exact row count and table size, without downloading the file. Measured: one INUMET series reports 384,637 rows and 3 typed columns where the catalogue metadata says only CSV. Applies to the Datasets and Resources outputs.

## `includeDatastorePreview` (type: `boolean`):

Optional, billed per table previewed. Returns the first rows of each DataStore table straight from the portal's query API, so you can see the data itself rather than its description. Works on the Datasets, Resources and DataStore tables outputs.

## `datastorePreviewRows` (type: `integer`):

How many rows the preview above returns per table, 1 to 100. One request either way, so a bigger sample does not cost more.

## `includeViewStats` (type: `boolean`):

Optional, billed per dataset. Adds the portal's own view counters, total and recent, which is the only public signal of what Uruguayans actually use. Costs one extra request per dataset because the counters ride on package\_show and cannot be read from the search index.

## `includeResourceViews` (type: `boolean`):

Optional, billed per resource. Lists the previews the portal has configured for each file: data explorer, map, chart, PDF or web page viewer. Applies to the Datasets and Resources outputs.

## `includeHarvestProvenance` (type: `boolean`):

Optional, billed per harvested dataset. Resolves where a copied dataset really came from: the upstream portal URL, its harvester type, its refresh frequency and whether it is still active. Only fires on datasets that were actually harvested.

## `includeOrganizationProfile` (type: `boolean`):

Optional, billed per organization profiled, and only on the Organizations output. One extra query per publisher returning what it actually publishes: its top themes, formats, tags and licences with counts.

## `includeRawExtras` (type: `boolean`):

Adds the untouched CKAN extras array to each dataset row, for the harvest identifiers and anything the portal adds later. Free, no extra request.

## `maxPages` (type: `integer`):

Each page bills one catalogue page event. A page holds up to 1,000 datasets, so 3 pages covers the entire catalogue; smaller runs use smaller pages and never fetch more than they need.

## `directoryLimit` (type: `integer`):

How many rows the Tags and Formats directories return. The tag vocabulary has 1,487 entries and its long tail is mostly one-off keywords.

## `concurrency` (type: `integer`):

Parallel requests, 1 to 10. Measured: 8 concurrent searches all returned HTTP 200 in 1.8 seconds with no throttling. The portal's robots.txt asks for a 10 second crawl delay on its HTML pages, so this stays modest by default out of courtesy to a public service.

## `timeoutSecs` (type: `integer`):

Soft wall-clock budget. The run stops issuing requests and flushes what it has. The platform's own run timeout still applies and whichever is nearer wins.

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

Off by default and not needed: the CKAN API answers anonymous requests with no proxy, no cookie and no User-Agent. Turn it on only if you are sweeping the whole catalogue repeatedly on a schedule.

## Actor input object example

```json
{
  "dataset": "datasets",
  "maxItems": 10,
  "onlyOpenLicence": false,
  "onlyWithDatastore": false,
  "sortBy": "modified-desc",
  "checkResourceLinks": false,
  "onlyLiveResources": false,
  "includeDatastoreSchema": false,
  "includeDatastorePreview": false,
  "datastorePreviewRows": 5,
  "includeViewStats": false,
  "includeResourceViews": false,
  "includeHarvestProvenance": false,
  "includeOrganizationProfile": false,
  "includeRawExtras": false,
  "maxPages": 20,
  "directoryLimit": 500,
  "concurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `csv` (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 = {
    "dataset": "datasets",
    "maxItems": 10,
    "sortBy": "modified-desc"
};

// Run the Actor and wait for it to finish
const run = await client.actor("parseforge/uruguay-open-data-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 = {
    "dataset": "datasets",
    "maxItems": 10,
    "sortBy": "modified-desc",
}

# Run the Actor and wait for it to finish
run = client.actor("parseforge/uruguay-open-data-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 '{
  "dataset": "datasets",
  "maxItems": 10,
  "sortBy": "modified-desc"
}' |
apify call parseforge/uruguay-open-data-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parseforge/uruguay-open-data-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/pRJBt5WTpbLnSn7fG/builds/BEd9GLxKcBcbZKNdf/openapi.json
