Poland e-Zamówienia Tenders Scraper (BZP Public Procurement) avatar

Poland e-Zamówienia Tenders Scraper (BZP Public Procurement)

Pricing

from $1.50 / 1,000 tender notices

Go to Apify Store
Poland e-Zamówienia Tenders Scraper (BZP Public Procurement)

Poland e-Zamówienia Tenders Scraper (BZP Public Procurement)

High-performance hybrid scraper for Polish public procurement (BZP) via official e-Zamówienia REST APIs. Features server-side Elasticsearch keyword search (SearchTenders) and temporal sliding-window bulk extraction. 128 MB RAM execution, 0 headless browser overhead.

Pricing

from $1.50 / 1,000 tender notices

Rating

0.0

(0)

Developer

Galhali

Galhali

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

🇵🇱 Poland e-Zamówienia Tenders Scraper (BZP Public Procurement API)

Apify Actor Version Pricing Model Memory Footprint Architecture TypeScript

Extract, monitor, and automate official Polish public procurement notices (Biuletyn Zamówień Publicznych - BZP) directly from the official e-Zamówienia platform (ezamowienia.gov.pl).

Built for B2B lead generation agencies, government contractors, bid intelligence platforms, and workflow automation engineers (n8n, Make.com, AI/MCP agents).


⚡ Why Use This Scraper?

Public tenders in Poland represent billions of euros in annual government spending across IT, construction, medical, engineering, and consulting sectors. However, tracking opportunities through official government portals is traditionally frustrating:

  • Manual search portals lack automated webhook alerts or structured data exports.
  • Commercial tender aggregation portals charge $150 – $500/month for slow, delayed updates.
  • Traditional web scrapers using headless browsers (Puppeteer/Playwright) are notoriously slow, prone to memory leaks, crash frequently, and break whenever the website DOM updates.

The Architectural Advantage: Hybrid Dual-Track REST Engine (v0.2.0)

This Actor does not render web pages in headless Chrome. Instead, it features an intelligent dual-track hybrid acquisition engine interfacing directly with the official, authoritative e-Zamówienia backend REST APIs:

  1. Track 1: Server-Side Full-Text Search (SearchTenders):

    • Activated whenever searchQuery is provided.
    • Queries the official e-Zamówienia Elasticsearch read-models engine (/mp-readmodels/api/Search/SearchTenders).
    • Binds keywords server-side to procurement dossiers, returning relevant active and historical tenders.
    • Enforces strict descending chronological sort (SortingColumnName=InitiationDate&SortingDirection=DESC).
    • Supports native pagination via PageNumber and reads x-pagination metadata headers.
  2. Track 2: Forward Temporal Sliding-Window Stream (/mo-board/api/v1/notice):

    • Activated when extracting general procurement notices (no searchQuery).
    • Dynamically advances the temporal cursor (PublicationDateFrom = lastItem.publicationDate) down to microsecond precision.
    • Implements in-memory boundary deduplication (Set<string>) and stall detectors (+1ms fallback) to bypass the upstream single-page limit.
    • Enables uninterrupted streaming of 1,000+ distinct notices across multi-week or multi-month ranges.
Metric / FeatureTraditional Headless ScraperPoland e-Zamówienia Scraper v0.2.0
Extraction MethodHeadless Chrome (Puppeteer / Playwright)Hybrid Official REST APIs (Search + Stream)
Search EngineBrittle DOM element searchingOfficial Elasticsearch index (SearchTenders)
Bulk PaginationManual clicks / brittle paginationDynamic Temporal Sliding Window (1,000+ items)
RAM Footprint1,024 MB – 2,048 MB128 MB (Ultra-lightweight Alpine container)
Execution Speed5 – 15 tenders / minuteUp to 1,500+ tenders / minute
DOM Breakage RiskHigh (Breaks on CSS / HTML updates)Zero (Backed by official API schemas)
Rate Limit ResilienceProne to aggressive IP bansAdaptive pacing + automatic WAF cool-down & proxy rotate
Compute CostHigh ($0.25+ in compute units per run)Negligible (~$0.0001 per run in compute)
Pricing ModelHigh monthly rental or heavy CUPay-Per-Event ($0.0015 per saved tender)

🎯 High-Value Use Cases

  1. Automated B2B Lead Generation for Contractors: Filter tenders by your exact industry CPV code (e.g. 72000000-5 for IT software & cloud services) and get instant alerts the minute a municipal or national government body posts an RFP.
  2. Competitor Intelligence & Award Tracking: Track TenderResultNotice (Wynik postępowania) to find out which competitors won government contracts, their final bid pricing, and contract terms.
  3. Subcontractor & Supplier Outreach: Identify large public infrastructure or construction projects right after contract award to pitch your equipment, staffing, or material supply services to the winning prime contractors.
  4. AI Market Intelligence & Copilots: Feed structured tender data into LLMs, Vector DBs, or Model Context Protocol (MCP) servers so AI agents can answer questions like: "What cloud migration tenders were published in Mazowieckie this week?"

📋 Table of Contents


✨ Key Features

  • 23 Rich Fields per Notice / Dossier: Extracts BZP bulletin numbers, tender IDs, purchasing organization, city, province, tax ID (NIP/REGON), CPV codes, submission deadlines, full HTML notice body (for notices), and direct clickable links to public dossiers.
  • Server-Side Full-Text Search (SearchTenders): Instantly search Poland's entire procurement archive with Elasticsearch indexing when searchQuery is provided, sorted descending by initiation date.
  • Temporal Sliding-Window Bulk Extraction: Continuously stream 1,000+ distinct notices via dynamic forward microsecond cursor sliding, overcoming the upstream API's single-page cap.
  • Dynamic Date Scheduling: Automatically calculates a rolling 7-day window when dates are omitted—schedule it once in Apify and let it run daily without updating input parameters.
  • Smart Pacing & WAF Handling: Complies with Azure Application Gateway WAF thresholds with configurable delay (default 3,500 ms) and automatic cool-down retry logic on HTTP 403/429.
  • Direct Dossier URL Generation: Every notice and search result includes a computed detailUrl linking directly to the interactive government dossier on ezamowienia.gov.pl.
  • Apify Proxy Support: Fully compatible with Apify Datacenter proxies for ultra-high throughput.

⚙️ Input Parameters Guide

ParameterTypeRequiredDefaultDescription
searchQueryStringNoNoneKeyword query triggering server-side full-text search (SearchTenders) on tender title and purchaser. Omit for bulk BZP streaming.
noticeTypeStringYes"ContractNotice"Type of procurement notice in the official Polish bulletin (BZP). See Notice Types.
orderTypeStringNo"All"Category of procurement. Strict PascalCase: "All", "Services", "Delivery", "Works".
cpvCodeStringNoNoneCommon Procurement Vocabulary code prefix (e.g. 72000000-5, 45000000-7, 33000000-0).
publicationDateFromStringNoNow - 7 daysStart date in ISO format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ). Defaults to rolling 7 days ago.
publicationDateToStringNoCurrent timeEnd date in ISO format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ). Defaults to current moment.
maxItemsIntegerNo100Maximum number of tender notices to push to the Apify dataset (Range: 1 to 50,000).
pacingDelayMsIntegerNo3500Inter-page request delay in milliseconds (min 2000, recommended 3500) to respect Azure WAF limits.
proxyConfigurationObjectNoNoneStandard Apify Proxy configuration. Datacenter proxies are fully supported.

🕒 Dynamic 7-Day Fallback Window (Zero-Maintenance Scheduling)

One of the biggest pain points with API-based scrapers is that the upstream government API strictly rejects requests missing publication dates (returning HTTP 400 Bad Request). If you had to manually change publicationDateFrom and publicationDateTo every single day, automated scheduling would be impossible.

This Actor solves this completely:

  • If you leave publicationDateFrom and publicationDateTo empty, the scraper dynamically calculates:
    • publicationDateFrom = NOW() - 7 days (in ISO 8601 UTC)
    • publicationDateTo = NOW() (in ISO 8601 UTC)
  • Result: You can set up a daily or weekly cron schedule in Apify Console or n8n without ever having to touch the input dates!

🏷️ Notice Types & Order Categories

Notice Types (noticeType):

  • ContractNotice (Ogłoszenie o zamówieniu): New tenders open for bidding. Most popular for lead generation.
  • TenderResultNotice (Wynik postępowania): Completed tenders with awarded contractor, price, and decision. Ideal for competitor tracking.
  • NoticeUpdateNotice (Zmiana ogłoszenia): Clarifications, deadline extensions, and specification updates.
  • AgreementUpdateNotice (Zmiana umowy): Modifications and annexes to active public contracts.
  • ConcessionNotice (Ogłoszenie o koncesji): Concessions for construction works or public services.

Order Types (orderType):

  • All: All procurement categories.
  • Services (Usługi): IT, consulting, cleaning, transportation, legal, software development.
  • Delivery (Dostawy): Hardware, medical supplies, vehicles, fuel, equipment.
  • Works (Roboty budowlane): General construction, road building, renovations, infrastructure.

💡 Technical Note on BZP vs TED:
This scraper queries the domestic Polish bulletin (Biuletyn Zamówień Publicznych - BZP), which covers all national public tenders up to EU financial thresholds (e.g. < €140,000 for government supplies/services, < €5,538,000 for construction works). This represents over 85% of all public tenders in Poland.


💡 Sample Input Configurations

Example 1: Daily Lead Gen for IT Companies (Automated Schedule)

Find all new IT service and software tenders published in the last 7 days without hardcoded dates:

{
"noticeType": "ContractNotice",
"orderType": "Services",
"cpvCode": "72000000-5",
"maxItems": 100
}

Example 2: Medical & Hospital Equipment Deliveries

Find tenders for medical supplies with keyword search:

{
"noticeType": "ContractNotice",
"orderType": "Delivery",
"cpvCode": "33000000-0",
"searchQuery": "szpital",
"maxItems": 50
}

Example 3: Construction Award Monitoring (Competitor Tracking)

Track road and building construction contracts awarded during October 2026:

{
"noticeType": "TenderResultNotice",
"orderType": "Works",
"cpvCode": "45000000-7",
"publicationDateFrom": "2026-10-01",
"publicationDateTo": "2026-10-26",
"maxItems": 200
}

📊 Output Dataset Structure

Each scraped tender item pushed to your Apify dataset is normalized into a clean, developer-friendly JSON object:

Field NameTypeDescription
objectIdStringUnique UUID identifier of the notice in e-Zamówienia.
bzpNumberStringOfficial Public Procurement Bulletin number (e.g. 2026/BZP 00497408).
noticeNumberStringFull notice identifier with version suffix (e.g. 2026/BZP 00497408/01).
noticeTypeStringNotice type (ContractNotice, TenderResultNotice, etc.).
orderTypeStringProcurement category (Services, Delivery, Works).
clientTypeStringOfficial institutional classification code of the buyer.
tenderTypeStringProcurement procedure type code.
isTenderAmountBelowEUBooleantrue if tender value is below European Union thresholds.
organizationNameStringOfficial name of the government institution or municipal entity.
organizationCityStringCity where the purchasing organization is registered.
organizationProvinceStringVoivodeship code (e.g. PL14 for Mazowieckie, PL21 for Małopolskie).
organizationCountryStringCountry code (PL).
organizationNationalIdStringTax ID (NIP or REGON) of the purchasing body.
tenderTitleStringFull official title and subject of the tender (orderObject).
tenderDescriptionSnippetStringCleaned, plain-text summary snippet (HTML tags stripped).
cpvCodeStringCPV codes with official descriptions.
publicationDateStringISO 8601 UTC timestamp of official notice publication.
submissionDeadlineString / nullBid submission deadline timestamp (crucial for RFP alerts).
procedureResultString / nullOutcome status (populated for TenderResultNotice).
tenderIdStringPublic OCDS dossier identifier.
detailUrlStringDirect clickable URL to view the live dossier on ezamowienia.gov.pl.
htmlBodyString / nullComplete raw HTML body containing legal notice clauses.
scrapedAtStringISO 8601 timestamp when this record was extracted by the Actor.

📄 Real-World Output Item Sample

{
"objectId": "08df2f30-9b81-90f9-701a-d0000164a818",
"bzpNumber": "2026/BZP 00497408",
"noticeNumber": "2026/BZP 00497408/01",
"noticeType": "ContractNotice",
"orderType": "Services",
"clientType": "1.1.13",
"tenderType": "1.1.2",
"isTenderAmountBelowEU": true,
"organizationName": "Uniwersytet Warszawski",
"organizationCity": "Warszawa",
"organizationProvince": "PL14",
"organizationCountry": "PL",
"organizationNationalId": "5250011266",
"tenderTitle": "Realizacja międzynarodowego ilościowego badania sondażowego metodą CAWI (Computer-Assisted Web Interview) w 12 krajach partnerskich",
"tenderDescriptionSnippet": "Ogłoszenie nr 2026/BZP 00497408 z dnia 2026-10-21. Przedmiotem zamówienia jest usługa realizacji ilościowego badania sondażowego metodą CAWI...",
"cpvCode": "79315000-5 (Usługi badań społecznych), 79311200-9 (Usługi przeprowadzania badań ankietowych)",
"publicationDate": "2026-10-21T05:03:12.366Z",
"submissionDeadline": "2026-10-29T09:00:00Z",
"procedureResult": null,
"tenderId": "ocds-148610-71fcc7b3-19e6-439f-85f0-9f7cb6ee8d2d",
"detailUrl": "https://ezamowienia.gov.pl/mp-client/search/list/ocds-148610-71fcc7b3-19e6-439f-85f0-9f7cb6ee8d2d",
"htmlBody": "<html><head><meta charset=\"UTF-8\">...</head><body><div class=\"notice-content\">...</div></body></html>",
"scrapedAt": "2026-10-26T15:04:39.966Z"
}

🔄 Workflow Automation & Integration Guides

1. n8n Automation Recipe

Automatically run the scraper every morning at 08:00 CET and dispatch new tender notifications directly to a Slack / Discord channel or your company CRM.

[Cron Trigger (08:00 Daily)]
│
▼
[Apify Node: Run Actor "ezamowienia-tenders-scraper"]
│
▼
[Item Lists / Split In Batches]
│
▼
[Filter: Deadline > Today]
│
▼
[Slack / Telegram: "🚨 New Polish Public Tender: {{ $json.tenderTitle }}"]

Step-by-Step n8n Configuration:

  1. In n8n, add an Apify node (or HTTP Request node calling https://api.apify.com/v2/acts/<your-username>~ezamowienia-tenders-scraper/runs?token=<APIFY_TOKEN>).
  2. Set the JSON Body in the Apify node:
    {
    "noticeType": "ContractNotice",
    "orderType": "Services",
    "cpvCode": "72000000-5",
    "maxItems": 50
    }
  3. Connect an If or Filter node checking {{ $json.submissionDeadline }} != null.
  4. Connect a Slack node with Block Kit layout:
    *New Polish IT Tender Announced!*
    • *Title*: {{ $json.tenderTitle }}
    • *Buyer*: {{ $json.organizationName }} ({{ $json.organizationCity }})
    • *Deadline*: {{ $json.submissionDeadline }}
    • *Official Dossier*: <{{ $json.detailUrl }}|View Tender on e-Zamówienia>

2. Make.com (Integromat) Setup

Set up a zero-code pipeline to synchronize public tenders directly into Google Sheets, Airtable, or HubSpot.

  1. Trigger: Add the Apify module -> Select "Watch Dataset Items" or "Run an Actor and Get Dataset".
  2. Actor Selection: Choose ezamowienia-tenders-scraper.
  3. Actor Input: Specify your target category (e.g. orderType: "Works", cpvCode: "45000000-7").
  4. Action: Add the Airtable module -> "Create a Record":
    • Tender Title ➔ tenderTitle
    • BZP Number ➔ bzpNumber
    • Purchasing Authority ➔ organizationName
    • City ➔ organizationCity
    • Deadline ➔ submissionDeadline
    • Dossier Link ➔ detailUrl
  5. Deduplication: Use Airtable's primary key on objectId to prevent duplicate records on recurring runs.

3. AI Agents & Model Context Protocol (MCP)

Connect this Actor directly to Claude Desktop, Cursor, or autonomous LangChain / AutoGPT agents using the official Apify MCP Server.

Claude Desktop MCP Configuration (claude_desktop_config.json):

{
"mcpServers": {
"apify": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-apify"],
"env": {
"APIFY_TOKEN": "your_apify_api_token_here"
}
}
}
}

Real-World Agent Prompt Examples:

  • "Check for new IT tenders announced in Poland today related to cloud migration and summarize the budget, buyer, and submission deadline."
  • "Find all medical equipment tenders published in Mazowieckie in the last 72 hours and rank them by urgency of the deadline."
  • "Who won the recent road construction tenders in Warsaw according to e-Zamówienia award notices?"

4. Python & Node.js Quickstarts

Python (apify-client):

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run_input = {
"noticeType": "ContractNotice",
"orderType": "Services",
"cpvCode": "72000000-5",
"maxItems": 50,
"pacingDelayMs": 3500
}
# Run the Actor and wait for completion
run = client.actor("your-username/ezamowienia-tenders-scraper").call(run_input=run_input)
# Fetch dataset items
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"[{item['bzpNumber']}] {item['tenderTitle']} | Buyer: {item['organizationName']}")
print(f"URL: {item['detailUrl']}\n")

Node.js (apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const input = {
noticeType: 'ContractNotice',
orderType: 'Services',
cpvCode: '72000000-5',
maxItems: 50,
};
const run = await client.actor('your-username/ezamowienia-tenders-scraper').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
console.log(`Tender: ${item.tenderTitle}`);
console.log(`Link: ${item.detailUrl}`);
});

🛡️ Azure WAF & Rate Limiting Engine

The Polish government e-Zamówienia portal is protected by Microsoft Azure Application Gateway Web Application Firewall (WAF). Overaggressive or concurrent scraping triggers HTTP 403 / 429 rate limits (~30 requests per minute per IP).

This Actor includes built-in protection:

  1. Intelligent Pacing: By default, an inter-page delay of 3500 ms (pacingDelayMs) ensures request rates remain safely under the Azure WAF threshold.
  2. Automated Cool-Down: If a temporary rate limit (403/429) is detected, the Actor automatically detects the WAF signature, pauses execution for 45–50 seconds to let the firewall cool down, and retries seamlessly with exponential backoff.
  3. Zero Browser Overhead: Standard HTTP requests prevent TCP connection flooding, ensuring continuous, stable data harvesting.

💰 Transparent Pricing (Pay-Per-Event)

This Actor uses Apify's modern Pay-Per-Event (PPE) pricing model. You never pay for idle time, startup latency, or empty queries. You only pay for the actual tender records delivered to your dataset:

$$\mathbf{$0.0015\text{ USD per scraped tender notice}}\quad(\mathbf{$1.50\text{ per 1,000 tenders}})$$

Cost Comparison:

VolumeScraped NoticesActor CostTypical Commercial Portal Cost
Free Tier / Trial~3,330 tenders$0.00 (Covered by Apify's $5 free monthly credit)$199.00 / month
Small Contractor1,000 tenders / month$1.50 / month$249.00 / month
Enterprise Agency20,000 tenders / month$30.00 / month$899.00 / month
  • No monthly platform fee: Pay only for what you extract.
  • Ultra-low compute cost: Running in a 128 MB RAM container, compute unit (CU) costs are practically non-existent (< $0.001 per run).

🧾 Polish & EU B2B Invoicing (VAT-EU Reverse Charge)

For businesses operating in Poland and the European Union, subscription and Pay-Per-Event usage charges are invoiced directly by Apify Technologies s.r.o. (established in Prague, Czech Republic, EU VAT ID: CZ04788290).

  • Reverse Charge Mechanism (Odwrotne obciążenie / WNT): When providing an active EU VAT number (e.g. Polish PL NIP registered for intra-community transactions in VIES), invoices are issued with 0% VAT pursuant to Article 196 of Council Directive 2006/112/EC.
  • Tax Deductibility: All invoice line items (Compute Units, PPE dataset events) constitute 100% tax-deductible operational business expenses (koszty uzyskania przychodów - KUP).
  • Automated Monthly Invoicing: Apify provides compliant PDF invoices and monthly breakdown summaries in the account billing portal for effortless accounting.

Public procurement notices published in the official Polish Public Procurement Bulletin (Biuletyn Zamówień Publicznych - BZP) on the e-Zamówienia portal (ezamowienia.gov.pl) constitute public sector information (informacja sektora publicznego).

Pursuant to Article 15 of the Polish Act of 11 August 2021 on Open Data and the Re-Use of Public Sector Information (Ustawa o otwartych danych i ponownym wykorzystywaniu informacji sektora publicznego, Dz.U. z 2021 r. poz. 1641, t.j. Dz.U. z 2023 r. poz. 1524), transposing Directive (EU) 2019/1024:

  1. Source of Public Sector Information: This Actor retrieves public procurement notices published in the official Public Procurement Bulletin (Biuletyn Zamówień Publicznych - BZP) maintained by the Public Procurement Office of the Republic of Poland (Urząd Zamówień Publicznych - UZP) via ezamowienia.gov.pl.

  2. Legal Basis for Re-Use: Public sector information is re-used pursuant to the Polish Act of 11 August 2021 on Open Data and the Re-Use of Public Sector Information (Dz.U. z 2021 r. poz. 1641, t.j. Dz.U. z 2023 r. poz. 1524), transposing Directive (EU) 2019/1024 of the European Parliament and of the Council.

  3. Data Modification Disclosure: Original administrative notices are retrieved via the public BZP WebService, filtered, parsed, and converted into structured JSON records for analytical processing.

  4. Disclaimer of Warranties & Liability: Data is provided "AS IS" without warranties of completeness, currency, or fitness for a particular procurement bid. Neither the author nor Urząd Zamówień Publicznych shall be held liable for any commercial, contractual, or legal decisions made based on this automated data feed. Bidders must consult official tender documentation on ezamowienia.gov.pl before submitting formal bids.

  5. No Official Government Affiliation: This Actor is an independent commercial software tool and is not endorsed by, sponsored by, or affiliated with Urząd Zamówień Publicznych or any Polish governmental body.


❓ Frequently Asked Questions

Q: How does this scraper differ from TED (Tenders Electronic Daily)?

A: TED only covers high-value tenders exceeding EU thresholds (> €140k for supplies/services, > €5.5M for works). The Polish Biuletyn Zamówień Publicznych (BZP) on e-Zamówienia contains all public tenders from Polish schools, municipalities, police departments, universities, and regional agencies that never appear on TED.

Q: Does it break when the e-Zamówienia website changes its layout?

A: No. This Actor connects directly to the official government REST API backend. It does not scrape HTML DOM or CSS selectors, making it virtually immune to website redesigns.

Q: Can I run this scraper without specifying dates?

A: Yes! When date parameters are omitted, the Actor dynamically sets the search window to the last 7 rolling days. This makes it ideal for automated daily schedules on Apify, n8n, or Make.

Q: What if I need notices older than 7 days?

A: Simply set publicationDateFrom and publicationDateTo to your desired dates (e.g. 2026-01-01 to 2026-06-30).

Q: Do I need proxies?

A: For standard daily scraping (up to a few thousand notices per day), direct connections work seamlessly thanks to the built-in pacing engine. For heavy enterprise scraping (50,000+ notices in minutes), enabling Apify Datacenter proxies is recommended.


🤝 Support & Custom Solutions

Need custom integrations, automated tender enrichment with Polish REGON/KRS databases, or specialized tender alerting?
Feel free to open an issue or reach out via the Apify Actor console.