France BOAMP Public Tenders Scraper
Pricing
$3.00 / 1,000 notice returneds
France BOAMP Public Tenders Scraper
French public procurement tenders from the official BOAMP open-data API (DILA/Opendatasoft): buyer, deadline, CPV codes, department, contact email.
Pricing
$3.00 / 1,000 notice returneds
Rating
0.0
(0)
Developer
Jason
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Pulls French public procurement notices from BOAMP (Bulletin officiel des annonces de marchés publics), the French government's official tender bulletin, through its open-data API on the DILA / Opendatasoft portal. No API key, no account, no browser automation. You get one flat JSON record per notice with the buyer, the publication date, the response deadline, the market type (works / supplies / services), the notice type, the department code(s), the region (derived from the department), the city, the CPV-style descriptor codes and labels, and the buyer's contact name and e-mail where the notice publishes them - filtered by publication-date window, keyword, market type, department, region, buyer name and response deadline. On 10 September 2026 the dataset held 1,704,443 notices going back to a publication date of 2 March 2015, and BOAMP publishes roughly 400 notices per business day (399 on 9 September 2026).
What you get
Every record contains:
| Field | Description |
|---|---|
id | BOAMP notice id (idweb), for example 26-87284 |
source | boamp, constant |
url | The public notice page, e.g. https://www.boamp.fr/pages/avis/?q=idweb:26-87284 (the API's own url_avis) |
title | The subject (objet), trimmed to 200 characters on a word boundary |
buyerName | The contracting authority (nomacheteur), e.g. FRANCE TRAVAIL - IdF |
publicationDate | Date the notice was published (dateparution), YYYY-MM-DD |
deadline | Response deadline (datelimitereponse) as an ISO timestamp with timezone, or null when the notice has none (award and result notices) |
marketType | Array of market types: TRAVAUX (works), FOURNITURES (supplies), SERVICES. Empty when the notice carries none (some corrigenda/results) |
natureType | Notice type in French, e.g. Avis de marché, Rectificatif, Résultat de marché, Modification |
noticeState | The notice's state (etat), e.g. INITIAL |
procedureType | The procurement procedure label (procedure_libelle), e.g. Procédure Adaptée, or null |
department | Array of French department codes (code_departement), e.g. ["93","75","77","92","94","95"] |
region | Region name derived from the department code(s), e.g. Île-de-France; multiple regions are joined with ; (see Limits and freshness) |
city | The buyer's city, read from the notice body (donnees); null when the notice omits it |
cpvCodes | Array of BOAMP descriptor codes (descripteur_code), the CPV-style subject codes, e.g. ["274"] |
cpvLabels | The matching descriptor labels (descripteur_libelle), e.g. ["Prestations de services"] |
contactName | The buyer's published contact person or service, read from the notice body; null when none is published |
contactEmail | The buyer's published contact e-mail, read from the notice body; null when none is published or the value is not a well-formed address |
description | The full subject (objet), untrimmed |
fetchedAt | ISO timestamp of the run that produced the record |
city, contactName and contactEmail are read out of each notice's source form (donnees), whose shape differs by notice family - the national MAPA and FNS forms keep them under organisme, and the EU eForms (JOUE) notices reference the buyer by an organisation id that the Actor resolves to that organisation's own address and contact, never the publishing platform's. The dataset has two views: Overview (dates, buyer, market type, department, region, city, CPV, link) and Buyer contacts (buyer, contact name, e-mail, city, region, deadline, link).
Input
| Input | Type | Default | Description |
|---|---|---|---|
daysBack | integer | 3 | Look-back window in days on the publication date, ending today. Ignored when dateFrom/dateTo are set. Max 3,660. |
dateFrom | string | - | Start of the publication-date window, YYYY-MM-DD, inclusive. Overrides daysBack. |
dateTo | string | today | End of the publication-date window, YYYY-MM-DD, inclusive. |
keywords | string[] | none | Terms matched against the subject and the buyer name with BOAMP's full-text search, which matches whole words (so eau does not match bureau). Terms are ORed. |
marketTypes | string[] | all | Any of Travaux, Fournitures, Services. Notices with no market type are excluded when this is set. |
departments | string[] | all | French department codes, e.g. 75, 13, 2A, 971, 973. A notice is kept when any of its departments matches. |
regions | string[] | all | Region names, matched as a case-insensitive substring of the derived region, e.g. Bretagne, Occitanie, Île-de-France. Terms are ORed. |
buyers | string[] | any | Buyer-name terms matched against nomacheteur with the full-text search, e.g. mairie, metropole. Terms are ORed. |
deadlineAfter | string | - | Keep only notices whose response deadline is on or after this date, YYYY-MM-DD. Notices with no deadline are excluded when this is set. |
maxItems | integer | 500 | Stop after this many notices. You are charged per notice, so this is also the cost cap. Newest publication date first, so a value below the window's volume drops the oldest notices in the window. |
The default of 500 is a little above one business day's volume (about 400), so a daily run with the defaults captures a full day with headroom. Keyword, market-type, department, buyer and deadline filters are applied by the BOAMP API; the region filter is applied locally to the derived region.
Example - open works and supplies tenders in Île-de-France published in the last week, with a deadline still to come:
{ "daysBack": 7, "marketTypes": ["Travaux", "Fournitures"], "regions": ["Île-de-France"], "deadlineAfter": "2026-09-20", "maxItems": 500 }
Example - a daily watch on every IT-related notice, run on a schedule:
{ "daysBack": 2, "keywords": ["informatique", "logiciel", "cloud"], "maxItems": 200 }
Example - every notice from a set of departments over a quarter:
{ "dateFrom": "2026-06-01", "dateTo": "2026-09-01", "departments": ["75", "92", "93", "94"], "maxItems": 5000 }
Bad input fails fast: an unknown market type, a malformed department code or a malformed date stops the run with the validation message as its status, before any request is made.
Output example
A real record from a live run on 10 September 2026 ({"daysBack": 2, "maxItems": 5}), unedited:
{"id": "26-87284","source": "boamp","url": "https://www.boamp.fr/pages/avis/?q=idweb:26-87284","title": "PRESTATION DE SERVICE SOCIALE AU BENEFICE DES AGENTS DE FRANCE TRAVAIL ILE DE FRANCE PUBLIC ET PRIVE","buyerName": "FRANCE TRAVAIL - IdF","publicationDate": "2026-09-09","deadline": "2026-10-13T16:00:00+00:00","marketType": ["SERVICES"],"natureType": "Avis de marché","noticeState": "INITIAL","procedureType": "Procédure Adaptée","department": ["93", "75", "77", "92", "94", "95"],"region": "Île-de-France","city": "MONTREUIL","cpvCodes": ["274"],"cpvLabels": ["Prestations de services"],"contactName": "Nacéra Djelti","contactEmail": "nacera.djelti@francetravail.fr","description": "PRESTATION DE SERVICE SOCIALE AU BENEFICE DES AGENTS DE FRANCE TRAVAIL ILE DE FRANCE PUBLIC ET PRIVE","fetchedAt": "2026-09-10T00:15:09.032Z"}
An EU-threshold notice (family JOUE, published as eForms) looks the same: for example 26-86644, buyer MAIRIE DE GISORS, region Normandie, city Gisors, contactEmail direction.generale@mairie-gisors.fr resolved from the buyer's own organisation block rather than the publishing platform's.
Every run also writes a SUMMARY record to the key-value store with the resolved date window, the filters used, how many records the local region filter dropped, the number of pages read, and the windowExhausted completeness flag (see Limits and freshness).
Pricing
Pay per result: US$0.003 per notice delivered (US$3 per 1,000 notices). You are charged only for records pushed to the dataset; a run that returns nothing costs nothing. Runs on the Apify free plan are limited by the platform's free-tier usage allowance.
Data source and licence
- Endpoint.
GET https://boamp-datadila.opendatasoft.com/api/explore/v2.1/catalog/datasets/boamp/records, the Opendatasoft Explore v2.1 API for DILA's BOAMP dataset. Public, no authentication. Dataset page: https://boamp-datadila.opendatasoft.com/explore/dataset/boamp/ (read 10 September 2026). - Licence. BOAMP open data is published under the Licence Ouverte / Open Licence 2.0 (Etalab), https://www.etalab.gouv.fr/licence-ouverte-open-licence/ (read 10 September 2026). It permits reuse for any purpose, including commercial reuse, provided the source and the date of the last update are acknowledged. Attribute as "Source: DILA / BOAMP, Licence Ouverte 2.0" and link to the notice page.
- Personal data.
contactNameandcontactEmailare the contact each contracting authority publishes on its own notice so that suppliers can ask questions and submit bids - sometimes a named officer (Nacéra Djelti), often a service or a shared mailbox (marchespublics@…). BOAMP publishes them lawfully as part of the official bulletin. Using them for anything other than responding to the tender - marketing in particular - is the buyer's responsibility under the applicable regime (the GDPR and the French loi Informatique et Libertés for contacts in France). Some notices also name individuals in the subject text.
Limits and freshness
- Volumes, measured 10 September 2026 with this Actor's own date filter: notices with a publication date in the last 1 full day (9 September) - 399; last 3 days - 697; last 7 days - 1,683; last 30 days - 7,704. That is roughly 400 per business day. A single keyword narrows it sharply:
informatiqueover the last 30 days returned 104; department75over the last 7 days, 163. The whole dataset was 1,704,443 notices back to a publication date of 2 March 2015. - Size
maxItemsto the window, and checkwindowExhausted.maxItemscounts records delivered and the stream is newest-first on publication date, so a value below the window's volume drops the oldest notices in it - but never silently. The run stops when the cap is filled and warnsmaxItems (N) was reached before the window was exhausted, and theSUMMARYrecord carrieslimitReached: truewithwindowExhausted: false.windowExhausted: trueis the guarantee that you hold the complete window: it is set only when the run read every matching notice and delivered every record it kept. - The 10,000-row offset ceiling is handled for you. The Explore API refuses
offset + limit > 10000(verified 10 September 2026). A window with more matches than that - about 25 days at the current rate, or fewer with looser filters - is walked in date sub-windows: when the offset ceiling is reached the Actor re-anchors the upper date bound on the oldest publication date seen and continues, de-duplicating the re-read boundary date byidweb. So an arbitrarily deep window is delivered complete and in order; only a single day holding more than ~9,900 matching notices (never observed - the busiest day seen was 399) would be unreachable, and the run warns if that ever happens. - Speed, measured 10 September 2026. A complete 3-day window of 697 notices (7 pages of 100) delivered in 11.3 s; a capped run of 300 notices (3 pages) in 6.1 s - roughly 60 notices a second, paging included. A full 30-day window of about 7,700 notices takes on the order of two to three minutes.
- Rate limits. The Actor requests one 100-row page at a time and retries
429and5xxresponses with exponential back-off, honouringRetry-After(via the sharedfetchWithRetry). No documented hard quota was hit in testing. - Missing values are the notice's, not the Actor's.
deadlineisnullfor award and result notices, which have no response date;marketTypeis empty on some corrigenda and results;contactNameis absent on the FNS simplified form, which carries no correspondant;cityandcontactEmailare present on most notices but not all. These staynull/empty rather than being guessed.contactEmailis returned only when the published value is a well-formed address. - Freshness. Notices appear on business days; the newest publication date on 10 September 2026 was 9 September, with nothing yet published for the 10th at run time. Run an overlapping window (
daysBack: 2daily) rather than one that exactly abuts the previous run. A notice is corrected in place with aRectificatif/Modificationnotice carrying its ownidweb, so re-run with an overlap to catch changes.
Use cases
- Bid pipeline for a supplier or contractor: a scheduled daily run over your departments or regions and market type, with the
deadline,cpvCodesand the buyer's contact e-mail already on the record, so a bid/no-bid call takes minutes. - Lead generation for firms that sell to the public sector: filter by
keywordsandbuyers, and usebuyerName,city,contactNameandcontactEmailto reach the contracting authority behind each notice. - Public-procurement research and dashboards: pull a full quarter or year by publication date and analyse spend intentions by region, department, CPV code, market type or buyer across France's 1.7-million-notice archive back to 2015.
Support
Open an issue on the Actor's page on Apify Store. Issues are answered within 14 days, as the Store terms require. Bug reports that name the run id and the input used are fixed fastest.