Belgium e-Procurement Tenders Scraper: BOSA Notices
Pricing
Pay per event
Belgium e-Procurement Tenders Scraper: BOSA Notices
Pricing
Pay per event
Rating
0.0
(0)
Developer
Francesco Correnti
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Features
Share
Monitor Belgian public procurement: Benelux and EU bid teams, consultants and suppliers track new overheidsopdrachten / marchés publics on BOSA e-Procurement (publicprocurement.be) by keyword, CPV, NUTS region, buyer, notice type or date, as clean rows.
Live sample, pulled 2026-11-06 (noticeTypes: ["16","17"], publishedFrom: 2026-11-01), 12 rows in sample.json:
| noticeId | title | buyer | KBO/BCE no. | mainCpv | published | noticeUrl |
|---|---|---|---|---|---|---|
| 46fa7ef2-35cd-4749-8bf5-947022aecc77 | Cahier Spécial des Charges n°57/53/4/26/083 - Ligne 43 : Riv | Infrabel Projects South | 0869763267 | 45220000 | 2026-11-06 | https://www.publicprocurement.be/publication-workspaces/46fa7ef2-35cd-4749-8bf5-947022aecc77/general |
| 62361823-708a-40ff-93ba-519ab050b2cf | Zuidijzerpolder: Onderhoudswerken aan onbevaarbare waterlope | ZUIDIJZERPOLDER | 0851235970 | 45240000 | 2026-11-06 | https://www.publicprocurement.be/publication-workspaces/62361823-708a-40ff-93ba-519ab050b2cf/general |
| 7291a5d2-15ff-48ee-a598-4b73b8ccca8b | 57/53/4/26/145 L166 : Gedinne -Bertrix Commune de Bertrix En | Infrabel Projects South | 0869763267 | 45000000 | 2026-11-06 | https://www.publicprocurement.be/publication-workspaces/7291a5d2-15ff-48ee-a598-4b73b8ccca8b/general |
| 2bc73dfb-4ddd-4b39-a50c-3a8bbbe1d35c | Achat d'un camion d'occasion équipé d'une plate-forme élévat | Stadt Sankt Vith | 0207078568 | 34137000 | 2026-11-05 | https://www.publicprocurement.be/publication-workspaces/2bc73dfb-4ddd-4b39-a50c-3a8bbbe1d35c/general |
| b1859abc-4fc0-4904-aa8a-f8ba389be4fb | Slibruiming van de Aa te Vorselaar en Lille | Vlaamse Milieumaatschappij | 0887290276 | 45246000 | 2026-11-05 | https://www.publicprocurement.be/publication-workspaces/b1859abc-4fc0-4904-aa8a-f8ba389be4fb/general |
Text is kept as served (NL/FR/DE/EN). title is the first available in the order EN > NL > FR > DE, language says which; titles has every language version. Empty values (null) are not published by the buyer.
Input
| field | example | meaning |
|---|---|---|
keywords | "informatique" | free-text search |
cpv | ["72000000"] | list of 8-digit CPV codes |
noticeTypes | ["16","17"] | BOSA notice subtype codes (16/17 contract notices, 20 modification, E1-E6 eForms); empty = all |
location | "BE10" | Belgian NUTS code (BE10 Brussels, BE2 Flanders, BE3 Wallonia, BE332 Liège) |
buyer | "Infrabel" | buyer name contains (filtered client-side) |
publishedFrom / publishedTo | "2026-10-01" | publication date range, YYYY-MM-DD |
deadlineFrom | "2026-11-10" | tender deadline on or after (server-side; notices without deadline drop out) |
includeDetails | true | default true; one extra request per notice for KBO/BCE number, value, documents link |
maxItems | 50 | default 50, max 1000 |
Newest first.
Output
| field | meaning |
|---|---|
noticeId | BOSA publication workspace id (UUID, unique) |
referenceNumber | buyer's file reference |
title, titles, language, languages | title (EN>NL>FR>DE), all title versions {lang: text}, chosen language, publication languages |
description | as served; e-mail addresses stripped |
buyerName, buyerOrgNumber | buyer and Belgian KBO/BCE company number (10 digits; needs includeDetails) |
noticeType, procedureType, nature, status | e.g. 16, OPEN, WORKS/SUPPLIES/SERVICES, ACTIVE |
cpvCodes (array), mainCpv | 8-digit CPV |
nutsCodes | NUTS codes |
estimatedValue, currency | only when the notice states a value (needs includeDetails); mostly null |
publicationDate, deadline | date / local timestamp |
noticeUrl, documentsUrl | publicprocurement.be page, tender documents link (needs includeDetails) |
scrapedAt | ISO timestamp |
Pricing
Pay per event: $0.005 per start (actor-start) + $0.002 per notice (notice). Example: 1000 notices = $0.005 + 1000 x $0.002 = $2.005. The run stops cleanly at your spending cap; nothing is pushed beyond maxItems.
Source and limits
Step 0 findings (2026-11-06): publicprocurement.be is a Vue SPA calling its own JSON APIs (no registration, no captcha). Plain calls without a token get 403; the SPA first takes an anonymous visitor token, which the actor does the same way:
GET https://www.publicprocurement.be/env.config.jspublishes the public frontend client id/secret.POST https://www.publicprocurement.be/auth/realms/supplier/protocol/openid-connect/token(grant_type=client_credentials, Basic auth with that public client) -> 200, 1 h visitor token. No account or private key involved.POST https://www.publicprocurement.be/api/sea/search/publications-> 200. Body{terms, cpvCodes, nutsCodes, noticeSubtypes, publicationDateFrom/To, tenderSubmissionDeadlineFrom/To, page, pageSize<=100}, needsAuthorization: Bearer+BelGov-Trace-Id.GET https://www.publicprocurement.be/api/dos/publication-workspaces/{noticeId}-> 200 (eForms XML: KBO/BCE number, documents URL, deadline).
Limits: unofficial API that can change; the visitor-token route relies on the site's public client, so it may be closed without notice; buyer filter applies after the search; the source rarely states estimated values; max 1000 items per run. No proxy.
Business data only
Buyer organisation, notice, CPV, value, dates and URLs. Contact persons, personal e-mails and phones are not read or output.
Run / test
python3 check.py (offline against fixtures/belgium.json, real BOSA responses; asserts query mapping, maxItems, PPE charge counts, no personal data). python3 check.py --live makes 1 real search request, needs 5+ notices (last result: live.log, 2026-11-06). Run: put input in storage/key_value_stores/default/INPUT.json, node src/main.js.
Publishing
publish.py --noruns (needs APIFY_TOKEN) creates/updates the actor without test runs. Not run: #469's publish.py was not run either, so this one is ready, not published.