Poland e-Zamówienia Tenders Scraper (BZP Public Procurement)
Pricing
from $1.50 / 1,000 tender notices
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
Maintained by CommunityActor 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)
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:
-
Track 1: Server-Side Full-Text Search (
SearchTenders):- Activated whenever
searchQueryis 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
PageNumberand readsx-paginationmetadata headers.
- Activated whenever
-
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.
- Activated when extracting general procurement notices (no
| Metric / Feature | Traditional Headless Scraper | Poland e-Zamówienia Scraper v0.2.0 |
|---|---|---|
| Extraction Method | Headless Chrome (Puppeteer / Playwright) | Hybrid Official REST APIs (Search + Stream) |
| Search Engine | Brittle DOM element searching | Official Elasticsearch index (SearchTenders) |
| Bulk Pagination | Manual clicks / brittle pagination | Dynamic Temporal Sliding Window (1,000+ items) |
| RAM Footprint | 1,024 MB – 2,048 MB | 128 MB (Ultra-lightweight Alpine container) |
| Execution Speed | 5 – 15 tenders / minute | Up to 1,500+ tenders / minute |
| DOM Breakage Risk | High (Breaks on CSS / HTML updates) | Zero (Backed by official API schemas) |
| Rate Limit Resilience | Prone to aggressive IP bans | Adaptive pacing + automatic WAF cool-down & proxy rotate |
| Compute Cost | High ($0.25+ in compute units per run) | Negligible (~$0.0001 per run in compute) |
| Pricing Model | High monthly rental or heavy CU | Pay-Per-Event ($0.0015 per saved tender) |
🎯 High-Value Use Cases
- Automated B2B Lead Generation for Contractors:
Filter tenders by your exact industry CPV code (e.g.
72000000-5for IT software & cloud services) and get instant alerts the minute a municipal or national government body posts an RFP. - Competitor Intelligence & Award Tracking:
Track
TenderResultNotice(Wynik postępowania) to find out which competitors won government contracts, their final bid pricing, and contract terms. - 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.
- 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
- Input Parameters Guide
- Sample Input Configurations
- Output Dataset Structure
- Workflow Automation & Integration Guides
- Azure WAF & Rate Limiting Engine
- Transparent Pricing (Pay-Per-Event)
- Polish & EU B2B Invoicing (VAT-EU Reverse Charge)
- Statutory Attribution & Legal Notice
- FAQ
✨ 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 whensearchQueryis 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
detailUrllinking directly to the interactive government dossier onezamowienia.gov.pl. - Apify Proxy Support: Fully compatible with Apify Datacenter proxies for ultra-high throughput.
⚙️ Input Parameters Guide
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
searchQuery | String | No | None | Keyword query triggering server-side full-text search (SearchTenders) on tender title and purchaser. Omit for bulk BZP streaming. |
noticeType | String | Yes | "ContractNotice" | Type of procurement notice in the official Polish bulletin (BZP). See Notice Types. |
orderType | String | No | "All" | Category of procurement. Strict PascalCase: "All", "Services", "Delivery", "Works". |
cpvCode | String | No | None | Common Procurement Vocabulary code prefix (e.g. 72000000-5, 45000000-7, 33000000-0). |
publicationDateFrom | String | No | Now - 7 days | Start date in ISO format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ). Defaults to rolling 7 days ago. |
publicationDateTo | String | No | Current time | End date in ISO format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ). Defaults to current moment. |
maxItems | Integer | No | 100 | Maximum number of tender notices to push to the Apify dataset (Range: 1 to 50,000). |
pacingDelayMs | Integer | No | 3500 | Inter-page request delay in milliseconds (min 2000, recommended 3500) to respect Azure WAF limits. |
proxyConfiguration | Object | No | None | Standard 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
publicationDateFromandpublicationDateToempty, 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 Name | Type | Description |
|---|---|---|
objectId | String | Unique UUID identifier of the notice in e-Zamówienia. |
bzpNumber | String | Official Public Procurement Bulletin number (e.g. 2026/BZP 00497408). |
noticeNumber | String | Full notice identifier with version suffix (e.g. 2026/BZP 00497408/01). |
noticeType | String | Notice type (ContractNotice, TenderResultNotice, etc.). |
orderType | String | Procurement category (Services, Delivery, Works). |
clientType | String | Official institutional classification code of the buyer. |
tenderType | String | Procurement procedure type code. |
isTenderAmountBelowEU | Boolean | true if tender value is below European Union thresholds. |
organizationName | String | Official name of the government institution or municipal entity. |
organizationCity | String | City where the purchasing organization is registered. |
organizationProvince | String | Voivodeship code (e.g. PL14 for Mazowieckie, PL21 for Małopolskie). |
organizationCountry | String | Country code (PL). |
organizationNationalId | String | Tax ID (NIP or REGON) of the purchasing body. |
tenderTitle | String | Full official title and subject of the tender (orderObject). |
tenderDescriptionSnippet | String | Cleaned, plain-text summary snippet (HTML tags stripped). |
cpvCode | String | CPV codes with official descriptions. |
publicationDate | String | ISO 8601 UTC timestamp of official notice publication. |
submissionDeadline | String / null | Bid submission deadline timestamp (crucial for RFP alerts). |
procedureResult | String / null | Outcome status (populated for TenderResultNotice). |
tenderId | String | Public OCDS dossier identifier. |
detailUrl | String | Direct clickable URL to view the live dossier on ezamowienia.gov.pl. |
htmlBody | String / null | Complete raw HTML body containing legal notice clauses. |
scrapedAt | String | ISO 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:
- 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>). - Set the JSON Body in the Apify node:
{"noticeType": "ContractNotice","orderType": "Services","cpvCode": "72000000-5","maxItems": 50}
- Connect an If or Filter node checking
{{ $json.submissionDeadline }} != null. - 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.
- Trigger: Add the Apify module -> Select "Watch Dataset Items" or "Run an Actor and Get Dataset".
- Actor Selection: Choose
ezamowienia-tenders-scraper. - Actor Input: Specify your target category (e.g.
orderType: "Works",cpvCode: "45000000-7"). - Action: Add the Airtable module -> "Create a Record":
Tender Title➔tenderTitleBZP Number➔bzpNumberPurchasing Authority➔organizationNameCity➔organizationCityDeadline➔submissionDeadlineDossier Link➔detailUrl
- Deduplication: Use Airtable's primary key on
objectIdto 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 ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run_input = {"noticeType": "ContractNotice","orderType": "Services","cpvCode": "72000000-5","maxItems": 50,"pacingDelayMs": 3500}# Run the Actor and wait for completionrun = client.actor("your-username/ezamowienia-tenders-scraper").call(run_input=run_input)# Fetch dataset itemsfor 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:
- Intelligent Pacing: By default, an inter-page delay of
3500 ms(pacingDelayMs) ensures request rates remain safely under the Azure WAF threshold. - 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.
- 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:
| Volume | Scraped Notices | Actor Cost | Typical Commercial Portal Cost |
|---|---|---|---|
| Free Tier / Trial | ~3,330 tenders | $0.00 (Covered by Apify's $5 free monthly credit) | $199.00 / month |
| Small Contractor | 1,000 tenders / month | $1.50 / month | $249.00 / month |
| Enterprise Agency | 20,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
PLNIP 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.
⚖️ Statutory Attribution & Legal Notice (Polish Open Data Act)
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:
-
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.
-
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.
-
Data Modification Disclosure: Original administrative notices are retrieved via the public BZP WebService, filtered, parsed, and converted into structured JSON records for analytical processing.
-
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.
-
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.