# Latvia Public Procurement (IUB) Scraper (`ayuki/latvia-public-procurement-iub`) Actor

Daily Latvian public procurement notices from IUB open data (CC0): tenders, contracts, awards, CPV, values. GDPR-safe: personal data removed.

- **URL**: https://apify.com/ayuki/latvia-public-procurement-iub.md
- **Developed by:** [LV Data Tools](https://apify.com/ayuki) (community)
- **Categories:** Lead generation, Open source, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

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

## Latvia Public Procurement API | IUB Iepirkumi

Find Latvian public tenders, track contract awards and analyse procurement spending with structured IUB open data. This Actor turns official daily JSON files from the **Procurement Monitoring Bureau (Iepirkumu uzraudzības birojs, IUB)** into an Apify dataset with English field names, buyer details, CPV codes, deadlines, winners and EUR values where available. It includes Latvian national-threshold notices as well as notices that may also appear on TED.

- **Start without configuration:** up to 100 recent notices from the last seven calendar days, with no restrictive filters.
- **Find relevant opportunities:** filter by publication date, CPV, buyer, notice category, procedure type, keyword and minimum value.
- **Use the results:** inspect the Overview or Detail view, download JSON, CSV or Excel, or retrieve the dataset through the Apify API.
- **Direct official source:** daily files on `open.iub.gov.lv`; no source account, browser or proxy required.
- Privacy by design: personal contact names, e-mails and phone numbers are dropped, and winners who are natural persons are withheld.

### IUB iepirkumu API — Latvia public procurement API

Iegūstiet Latvijas publisko iepirkumu paziņojumus, pasūtītājus, CPV kodus, piedāvājumu termiņus un līgumu rezultātus no IUB atvērtajiem datiem. Atlasiet datus pēc datuma, nozares vai pasūtītāja un eksportējiet JSON, CSV vai Excel formātā. Lauku nosaukumi ir angļu valodā; iepirkumu nosaukumi un apraksti paliek avota valodā, parasti latviešu valodā.

IUB provides daily notice files for the eForms data available since **2023-10-25**. The Actor reads the selected dates newest-first, normalizes notices, applies your filters and stores one row per notice. It skips duplicate IDs and, by default, older versions replaced by notices encountered within the selected date window. It stops when `maxItems` is reached.

### Quick start — IUB atvērtie dati

1. Open the Actor input in Apify Console. Keep the defaults and leave date and search filters blank.
2. Click **Start**. The default searches seven calendar days ending today (UTC) and returns up to 100 notices. This small preview is intended to finish in under five minutes with a responsive source; runtime depends on IUB availability and retries.
3. Open the dataset's **Overview** for buyers, values and deadlines, or **Detail** for all fields and winners. Choose **Export** to download the results.

Today's file can be unpublished, and some dates have no notices. The seven-day window includes earlier days so a weekend or a missing current-day file does not restrict the run to an empty day. It does not guarantee results during a source outage. Start broadly, inspect the data, then add filters.

#### JSON input: recent notices with the default settings

The same defaults apply to empty input `{}` through Apify or a local run. For an explicit preview:

```json
{
  "daysBack": 7,
  "maxItems": 100,
  "latestVersionOnly": true,
  "requestDelaySecs": 1,
  "excludeFreeText": false
}
```

#### JSON input: Latvian construction tender monitoring — būvniecības iepirkumi

```json
{
  "daysBack": 30,
  "noticeCategories": ["contract_notice"],
  "cpvCodes": ["45000000"],
  "maxItems": 200
}
```

`45000000` matches construction CPV prefixes in either the main or additional codes. A contract notice is an announcement; it does not by itself mean that bidding is still open. Check `tenderDeadline` and the official documents. With Apify schedules, overlapping windows help catch delayed files; deduplicate repeated runs by `noticeId` in your downstream workflow.

#### JSON input: buyer awards for a fixed period — iepirkumu rezultāti

```json
{
  "dateFrom": "2026-10-01",
  "dateTo": "2026-10-11",
  "noticeCategories": ["award"],
  "buyer": "90000076669",
  "maxItems": 100,
  "excludeFreeText": true
}
```

This historical example selects awards for Latvijas Universitāte. Fixed dates are inclusive, and `dateFrom` overrides `daysBack`. Filtered examples can legitimately return no matches; remove filters or widen the dates to investigate.

#### Input reference

Different filter fields combine: a notice must satisfy all supplied filters. Within category, procedure and CPV lists, any selected value can match. Leave optional filters empty for all notices.

| Input | Default | How to use it |
|---|---|---|
| `daysBack` | `7` | Calendar days including the end date; used only when `dateFrom` is blank. |
| `maxItems` | `100` | Output cap; `0` means all matches in the period. Files are newest-first, with source ordering within each day. |
| `dateFrom` / `dateTo` | Blank | Inclusive publication dates, `YYYY-MM-DD`. End date defaults to today (UTC). Use an end date on or after the start date. |
| `noticeCategories` | `[]` (all) | `planning`, `contract_notice`, `award`, `contract_execution`, `contract_modification`. |
| `cpvCodes` | `[]` (all) | CPV prefixes such as `45000000` (construction), `72000000` (IT) or `7221`; trailing zeros and check-digit suffixes are ignored. |
| `keyword` | Blank | Case-insensitive substring in title or description; use source-language text, e.g. `būvdarbi`. |
| `buyer` | Blank | Case-insensitive part of the buyer name or exact registration number. |
| `procedureTypes` | `[]` (all) | `open`, `restricted`, `neg-w-call`, `neg-wo-call`, `comp-dial`, `innovation`, `oth-single`, `oth-mult`. Selecting types excludes notices with no type. |
| `minValueEur` | Blank (off) | A positive minimum uses contract value, then estimated, then maximum value. Excludes notices without a usable value. `0` disables it. |
| `latestVersionOnly` | `true` | Skip versions superseded by a newer notice encountered within this run's date window. |
| `requestDelaySecs` | `1` | Delay before each sequential daily-file request; minimum `0.5` seconds. |
| `excludeFreeText` | `false` | Set `description` and `winners[].lotName` to `null` for stronger data minimisation. The scrubbed title stays. |

### Latvian tender data — IUB iepirkumu paziņojumi: sample output

The following complete record is taken directly from `sample_output.json`, which contains 100 sample notices. These are historical examples, not a promise of identical results on future runs.

```json
{
  "noticeId": "b3bee47c-97a2-477b-9f1a-2804f01ea61d",
  "procedureId": "03d4169f-0913-453c-a448-47aa46e283d5",
  "procurementReference": "RRS 2026/5",
  "publicationDate": "2026-10-11",
  "noticeCategory": "contract_notice",
  "formType": "competition",
  "noticeType": "pil-planned-contract",
  "legalBasis": "law-9",
  "procedureType": "open",
  "title": "VEĻAS MAZGĀŠANAS UN TĪRĪŠANAS PAKALPOJUMU NODROŠINĀŠANA SIA „SIGULDAS SLIMNĪCA” VAJADZĪBĀM",
  "description": "VEĻAS MAZGĀŠANAS UN TĪRĪŠANAS PAKALPOJUMU NODROŠINĀŠANA SIA „SIGULDAS SLIMNĪCA” VAJADZĪBĀM",
  "contractNature": "services",
  "cpvCode": "98310000-9",
  "additionalCpvCodes": [],
  "buyerName": "SIA “Siguldas slimnīca”",
  "buyerRegNo": "40003124730",
  "buyerCity": "Sigulda",
  "buyerNuts": "LV00A",
  "buyerType": "pub-undert-la",
  "buyerActivity": "health",
  "buyerWebsite": "https://www.siguldasslimnica.lv/lv",
  "estimatedValueEur": null,
  "maximumValueEur": null,
  "contractValueEur": null,
  "lotCount": 1,
  "tenderDeadline": "2026-10-26 11:00",
  "contractConclusionDate": null,
  "winners": [],
  "documentsUrl": "https://www.eis.gov.lv/EKEIS/Supplier/Procurement/183774",
  "replacesNoticeId": null,
  "sourceUrl": "https://open.iub.gov.lv/data/notice/2026/10/11-10-2026.json",
  "license": "CC0 1.0 (IUB open data)"
}
```

Three records from the same sample, shown with selected fields:

| Notice ID | Publication date | Category | Buyer | Contract value (EUR) |
|---|---|---|---|---|
| `b3bee47c-97a2-477b-9f1a-2804f01ea61d` | 2026-10-11 | `contract_notice` | SIA “Siguldas slimnīca” | — |
| `bd213fc2-8fd8-4a7d-948c-dd860f5adc6b` | 2026-10-11 | `award` | Latvijas Universitāte | 147,677.00 |
| `f41a9060-a871-4643-b0c4-46a89794494a` | 2026-10-11 | `contract_execution` | Valsts sabiedrība ar ierobežotu atbildību "Bērnu klīniskā universitātes slimnīca" | 171,305.84 |

The **Overview** view highlights date, category, title, buyer, CPV, estimated and contract values, deadline and document link. The **Detail** view includes all fields, buyer registration and location, procedure codes, `winners`, replacement ID, licence and source link. Both keep one row per notice; `winners` remains a nested array. JSON preserves that structure for integrations.

Null means a field was unavailable or intentionally withheld; `winners: []` means no winners were extracted. Titles and descriptions are not translated. `tenderDeadline` retains the source time when available, without timezone conversion. `sourceUrl` identifies the official daily JSON file, while `documentsUrl` points to tender documents or submission details when supplied.

### Latvian tenders and contract awards — Latvijas iepirkumi un līgumu rezultāti

- **Supplier bid monitoring:** watch CPV sectors and buyers, inspect deadlines and feed selected notices into an Apify integration or your own workflow.
- **Award and competitor tracking:** analyse legal-entity winners, contract values and repeat buyers.
- **Procurement market research:** compare sectors, buyer cities, NUTS regions and publication periods.
- **Public spending transparency:** investigate contract execution, modifications and negotiated procedures using traceable source URLs.

### Cost and pricing FAQ — IUB API izmaksas

**How much does a run cost?** Check the Actor's current **Pricing** tab in Apify Store and the run's usage in Apify Console. Store charges and platform usage depend on the published pricing model and your plan. This README does not quote a fixed price that could become outdated.

**How much do 1,000 notices cost?** If the Pricing tab lists a rate of $P per 1,000 results, that result charge is $P for 1,000 billable results, plus any separately applicable platform charges. If pricing is based on usage or another model, there is no fixed per-1,000 amount. Verify the listed billing unit before estimating a larger run.

**Is IUB open data free?** The source data is CC0 1.0, as explained in the licence section below. That source licence is separate from the cost of running an Actor on Apify.

**Do I need paid proxies or a source subscription?** No. The Actor reads official daily JSON files directly, without a proxy or IUB login.

**How can I keep costs low?** Start with the default seven-day, 100-notice preview. Increase the period and output cap only when needed. Filters limit saved results, but the Actor still downloads complete daily files until the cap is reached or the selected period ends. `maxItems: 0` removes the output cap and can increase usage substantially.

### Data freshness and troubleshooting — IUB datu aktualitāte

**How fresh is the data?** IUB publishes a file per day. Today's file may appear only later in the day. A missing file or an HTML placeholder is treated as zero notices for that date; transient HTTP errors are retried. The Actor does not continuously monitor live tender pages.

**Why did a run return no results?** Check the dates and remove optional filters first. A single day can have no published file, and combinations of CPV, buyer, keyword and minimum value can exclude every notice. Inspect the run log and `RUN_STATS` in the run's key-value store (`daysFetched`, `daysFailed`, `rawNotices`, `pushed`, `runtimeSecs`). Source failures can leave partial or empty output; run completion alone does not prove that every requested day was retrieved.

**Why is a value or deadline empty?** The source may omit it, particularly on planning or national-threshold notices. A minimum-value filter excludes notices without a usable value. A notice row is not a complete contract or lot-level accounting record.

**Is this the same as TED?** Coverage differs: IUB includes Latvian national-threshold procurement notices that may not appear on TED. This Actor reads IUB daily files and does not query TED.

**Can I get all historical notices?** Set explicit publication dates and `maxItems: 0`. The source starts on 2023-10-25. Large periods take longer; split them into smaller date ranges and deduplicate downstream by notice ID.

### Data source and licence

Data: Iepirkumu uzraudzības birojs (Procurement Monitoring Bureau of Latvia), https://open.iub.gov.lv and https://www.iub.gov.lv/lv/atvertie-dati. The same dataset is listed on the Latvian Open Data Portal, licensed **CC0 1.0**: https://data.gov.lv/dati/lv/dataset/publisko-iepirkumu-pazinojumi. The dataset metadata (`publiskie_iepirkumi_metadata.json`) declares the licence **Creative Commons CC0 1.0 (public domain dedication)**. IUB describes the data as freely available to anyone for reuse and processing, downloadable without authorization. This actor is an independent tool and is not affiliated with or endorsed by IUB. Notices can be corrected or republished at the source, so for legal purposes always check the official notice.

### Personal data

The output keeps official public records of organizations only: buyer and winner names, registration numbers, addresses at city level and websites. Safeguards:

- Contact-point names, e-mails and phone numbers are never output.
- Winners flagged at the source as natural persons are output as `"[natural person - withheld]"`, with no registration number.
- **Sole traders and farms** (IK / individuālais komersants, ZS / zemnieku saimniecība, ZvS, IU, and Lithuanian IĮ / įmonė), whose names usually contain a person's name, are output as `"[redacted: sole trader]"`. Registration number, legal form, city and bid value are kept.
- E-mail addresses and Latvian phone numbers are removed from `title`, `description` and `winners[].lotName`.
- Conservative person-name patterns are replaced by `[name removed]`: "Initial.Surname" (e.g. `A.Bērziņa`), "Surname Firstname zemnieku saimniecība" and "individuālais komersants Firstname Surname".
- `excludeFreeText: true` drops `description` and `lotName` entirely.

**Limits (honest):** free-text name detection is pattern-based. It will miss full names written without these patterns (for example "Jānis Bērziņš" alone in a description). It may also over-redact, e.g. street names such as "K. Barona iela". Company names (SIA/AS) that include a founder's initials or surname (e.g. `SIA "E.Tauriņš un Partneri"`) are kept, because they are registered legal-entity names. If you need maximum minimisation, enable `excludeFreeText`.

### Privacy notice

Controller: **Artyom Kutnevskiy (trading as LV Data Tools), contact lvdatatools@gmail.com**. Version 0.3, 2026-10-14.

This Actor republishes information from public procurement notices. Where a notice incidentally contains personal data (for example a sole trader's business name), this notice applies. Notifying each data subject individually would involve disproportionate effort (Art. 14(5)(b) GDPR), so this information is made public here.

- **Controller (for the Actor's processing):** Artyom Kutnevskiy (trading as LV Data Tools), contact lvdatatools@gmail.com
- **Roles:** the publisher (LV Data Tools) is controller for the Actor's own source collection and minimisation, and acts as processor for each user's run output under §5.2 of the Apify Standard Actor Contract, while the user is controller of that output and its reuse.
- **Purpose:** procurement market research and bid monitoring (finding tenders, analysing awards and public spend).
- **Source:** the official open data of Iepirkumu uzraudzības birojs (open.iub.gov.lv; data.gov.lv dataset `publisko-iepirkumu-pazinojumi`, CC0 1.0). The data is already public under Latvian procurement transparency rules.
- **Categories:** organisation names, registration numbers, city, contract values. Personal contact details are not processed into the output. Sole-trader names are redacted.
- **Legal basis:** Art. 6(1)(f) GDPR, legitimate interest (transparency of public spending and fair access to public tenders). See the legitimate-interest assessment kept by the publisher.
- **Retention:** the Actor itself stores nothing beyond the dataset of the user's own run, which the user controls on Apify. The publisher keeps no copy. Each user is an independent controller for their use of the output.
- **Recipients:** the Apify users who run the Actor, and Apify as the platform provider.
- **Your rights:** access, rectification, erasure, restriction and objection (Art. 15–21), and a complaint to a supervisory authority (in Latvia: Datu valsts inspekcija, www.dvi.gov.lv). To object or ask that a record be excluded from future runs, contact Artyom Kutnevskiy (trading as LV Data Tools), contact lvdatatools@gmail.com. Corrections to the underlying notice must be made at the source (IUB / the contracting authority).

### Support

For run errors or input questions, open an issue on the Actor's Apify Store page with the run ID and the filters used. Privacy requests use the controller contact in the notice above.

# Actor input Schema

## `daysBack` (type: `integer`):

Default: 7 calendar days, including the end date. Used only when Date from is blank; the end date is Date to or today (UTC). Keep 7 for a quick first run, or use 30 for broader monitoring.

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

Default: 100 notices for a quick preview. Files are read newest-first and the run stops once the cap is reached; order within a daily file follows the source. Set 0 for all matching notices in the selected period. Narrow filters can require reading every day even with a small cap.

## `dateFrom` (type: `string`):

Optional inclusive publication start date, YYYY-MM-DD. Overrides Days back. IUB daily JSON is available from 2023-10-25; earlier start dates are clamped to that date. Leave blank for recent notices.

## `dateTo` (type: `string`):

Optional inclusive publication end date, YYYY-MM-DD. Leave blank for today (UTC). Use a date on or after Date from. Today’s file may not yet be published; the default seven-day window also checks earlier days.

## `noticeCategories` (type: `array`):

Leave empty to include all notice categories for the first run. Select contract_notice for tender announcements or award for results. Selected categories are alternatives; different filter fields are combined.

## `cpvCodes` (type: `array`):

Optional Common Procurement Vocabulary prefixes: 45000000 for construction, 72000000 for IT, or 7221 for a narrower group. Matches either main or additional CPV; trailing zeros and a check-digit suffix are ignored. Any supplied prefix may match. Leave empty for all sectors.

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

Optional case-insensitive substring in the title or description. Use source-language text, usually Latvian, e.g. būvdarbi. Text is not translated. Leave blank to avoid excluding notices.

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

Optional case-insensitive part of a buyer’s name, e.g. Latvijas Universitāte, or an exact registration number, e.g. 90000076669. Leave blank for all contracting authorities.

## `procedureTypes` (type: `array`):

Optional procedure filter. Selected types are alternatives. Leave empty for all procedures, including notices with no procedure type; selecting a type excludes those notices.

## `minValueEur` (type: `integer`):

Optional minimum value in EUR: uses contract value, falling back to estimated value, then maximum value. A positive threshold excludes notices with no usable value. Leave blank or set 0 to disable the filter.

## `latestVersionOnly` (type: `boolean`):

Default: enabled. Skips duplicate notice IDs and older notices replaced by a newer version encountered in the selected date window. It cannot detect replacements outside that window. Disable to retain older versions with different IDs.

## `requestDelaySecs` (type: `number`):

Default: 1 second before each daily-file request, including retries; minimum 0.5 seconds. Downloads are sequential and need no proxy. Keep the default for polite access; lowering it does not guarantee faster source responses.

## `excludeFreeText` (type: `boolean`):

Default: disabled. Enable to set description and winners\[].lotName to null for stronger data minimisation. The scrubbed title remains. Existing contact-data removal and winner-name redaction apply in both modes.

## Actor input object example

```json
{
  "daysBack": 7,
  "maxItems": 100,
  "noticeCategories": [],
  "cpvCodes": [],
  "procedureTypes": [],
  "latestVersionOnly": true,
  "requestDelaySecs": 1,
  "excludeFreeText": 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 = {
    "daysBack": 7,
    "maxItems": 100,
    "noticeCategories": [],
    "cpvCodes": [],
    "procedureTypes": [],
    "latestVersionOnly": true,
    "requestDelaySecs": 1,
    "excludeFreeText": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("ayuki/latvia-public-procurement-iub").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 = {
    "daysBack": 7,
    "maxItems": 100,
    "noticeCategories": [],
    "cpvCodes": [],
    "procedureTypes": [],
    "latestVersionOnly": True,
    "requestDelaySecs": 1,
    "excludeFreeText": False,
}

# Run the Actor and wait for it to finish
run = client.actor("ayuki/latvia-public-procurement-iub").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 '{
  "daysBack": 7,
  "maxItems": 100,
  "noticeCategories": [],
  "cpvCodes": [],
  "procedureTypes": [],
  "latestVersionOnly": true,
  "requestDelaySecs": 1,
  "excludeFreeText": false
}' |
apify call ayuki/latvia-public-procurement-iub --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ayuki/latvia-public-procurement-iub"
        }
    }
}
```

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/7XQzdWHnchpr6eJtu/builds/g24xKQ6nssSs1Lod8/openapi.json
