# Germany Public Tenders Scraper: Ausschreibungen to Excel (`tenderfeed/germany-public-tenders`) Actor

German public tenders (Ausschreibungen) and contract awards from oeffentlichevergabe.de, the official federal notice service: EU-wide and national below-threshold notices. Filter by keyword, CPV, state, value, deadline. GDPR-safe.

- **URL**: https://apify.com/tenderfeed/germany-public-tenders.md
- **Developed by:** [TenderFeed](https://apify.com/tenderfeed) (community)
- **Categories:** Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

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

## Germany Public Tenders (Ausschreibungen) Scraper by TenderFeed

Search **German public tenders (öffentliche Ausschreibungen) and contract awards** from **oeffentlichevergabe.de**, the official federal notice service (Bekanntmachungsservice / Datenservice Öffentlicher Einkauf). You get **EU-wide notices and national below-threshold notices (VOB/A, UVgO, VOL/A)** that never reach TED. Filter by **keyword, CPV code, federal state (NUTS), stage, contract type, buyer, value and deadline**. Clean JSON, CSV or Excel with English field names.

Built by **TenderFeed** ([apify.com/tenderfeed](https://apify.com/tenderfeed)) on the official daily open-data export (OCDS + eForms, CC0 licence). No API key, no login, no scraping of private portals. About **1,000 notices per working day** (measured: 1,183 on 2026-10-28, 1,078 on 2026-10-30).

### Why this Actor

- **Below-threshold coverage**: on 2026-10-30, 253 of 683 calls for tenders were national (Unterschwellen) notices that TED does not carry.
- **Real deadlines**: the submission deadline is read from the eForms XML (the OCDS export alone has none): 596 of 683 calls for tenders on 2026-10-30 had one.
- **Built for bid managers**: federal state, legal basis (EU directive or VOB/A / UVgO / VOL/A), lots, e-procurement platform link (DTVP, Vergabe24, subreport, evergabe-online, DB Bieterportal...).
- **Award notices with winners** (`stages: ["award"]`) for competitor and pricing analysis.
- **"Only new" monitoring** for daily alerts, and pay only for new rows.

### Input example

```json
{
  "keywords": ["Software", "Rechenzentrum"],
  "stages": ["tender"],
  "contractTypes": ["services", "goods"],
  "regions": ["DE2", "Berlin"],
  "cpvCodes": ["72", "48"],
  "publishedFrom": "7 days",
  "onlyOpen": true,
  "maxResults": 0
}
```

- `stages`: `tender` (calls for tenders, default), `award` (results with winners), `planning` (prior information).
- `regions`: NUTS prefixes of the buyer or place of performance, e.g. `DE1` Baden-Württemberg, `DE2` Bayern, `DE3` Berlin, `DE7` Hessen, `DEA` Nordrhein-Westfalen, `DED` Sachsen, or finer (`DE212` München). State names like `"Bayern"` or `"NRW"` also work.
- `onlyEuWide`: keep only notices under the EU directives (above EU thresholds).
- Keywords match word starts in title, description and lot titles. Most notices are in German, so German terms work best (`Reinigung`, `Bauleistungen`, `Beratung`).
- The official export covers completed days, so the newest data is from yesterday.

### Output example

Real row from a live run (notice published 2026-10-30), national VOB/A works tender:

```json
{
  "source": "de-oeffentlichevergabe",
  "sourceId": "25988484",
  "ocid": "ocds-mnwr74-25988484",
  "url": "https://oeffentlichevergabe.de/ui/de/search/details?noticeId=25988484",
  "title": "HHI Berlin Berlin - Dachsanierung über EG 73-50405-3220-5 Dachabdichtungsarbeiten PR1321703 -3220-B",
  "description": "Siehe PDF-Datei.\n\n73-50405-3220-5 Dachabdichtungsarbeiten",
  "noticeType": "cn-standard",
  "status": "active",
  "procedureType": null,
  "contractType": "works",
  "buyerName": "Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. Vergabenummer B12 - SG 7 Vergabestelle Bau Hansastr. 27c, 80686 München, Deutschl",
  "buyerCountry": "DE",
  "buyerCity": null,
  "buyerContactName": null,
  "buyerContactEmail": null,
  "buyerContactPhone": null,
  "cpvCodes": [
    "45261410"
  ],
  "otherClassificationCodes": [],
  "placeOfPerformance": "10587 Fraunhofer IPK, Dachsanierung über EG, Pascalstraße 8-9",
  "publishedAt": "2026-10-30T19:00:02Z",
  "deadlineAt": "2026-11-27T10:00:00+01:00",
  "estimatedValue": null,
  "currency": null,
  "documentsUrl": null,
  "submissionUrl": null,
  "awardedValue": null,
  "awardees": [],
  "stage": "tender",
  "buyerState": null,
  "buyerNuts": null,
  "buyerWebsite": null,
  "legalBasis": "VOB/A national (works, below EU threshold)",
  "euWide": false,
  "numberOfLots": 1,
  "numberOfTenderers": null,
  "language": null
}
```

Fields shared by all TenderFeed Actors: `source, sourceId, ocid, url, title, description, noticeType, status, procedureType, contractType, buyerName, buyerCountry, buyerCity, cpvCodes, placeOfPerformance, publishedAt, deadlineAt, estimatedValue, currency, documentsUrl, submissionUrl, awardedValue, awardees`. Germany extras: `stage, buyerState, buyerNuts, buyerWebsite, legalBasis, euWide, numberOfLots, numberOfTenderers, language`.

### Buyer contacts and GDPR (`includeBuyerContacts`)

Notices often name a contact person with email and phone. By default (`includeBuyerContacts: false`) these are removed and you get **organisation-level data only** (buyer name, city, state, notice and platform links). Set it to `true` only if you have a lawful basis under the GDPR. In a live test (683 calls for tenders, 2026-10-30) contacts-on returned an email on 351 rows and a contact name on 155; contacts-off returned none.

### Daily alerts ("only new" monitoring mode)

Turn on `onlyNew`, give the search a `monitoringId` (e.g. `"de-it-bayern"`) and schedule the Actor daily. Each run returns, and charges for, only notices you have not received before.

### Notes and limits

- `estimatedValue` is filled only when the buyer publishes it (45 of 683 calls for tenders on 2026-10-30). Award notices often carry the contract value.
- Some national notices have a short description ("Siehe PDF-Datei"); open `url` or `documentsUrl` for the full documents on the buyer's e-procurement platform.
- Above-threshold German tenders are also on TED; use this Actor if you want one feed for both EU-wide and national German notices.

### More TenderFeed sources

Same output schema across all sources, so you can merge results in one sheet or CRM:

- [EU TED tenders](https://apify.com/tenderfeed/ted-eu-tenders)
- [SAM.gov federal contract opportunities](https://apify.com/tenderfeed/sam-gov-opportunities)
- [Grants.gov US federal grants](https://apify.com/tenderfeed/grants-gov-us)
- [USAspending federal contract awards](https://apify.com/tenderfeed/usaspending-contract-awards)
- [UK Find a Tender + Contracts Finder](https://apify.com/tenderfeed/uk-tenders)
- [France BOAMP appels d'offres](https://apify.com/tenderfeed/france-boamp-tenders)
- [Switzerland SIMAP tenders](https://apify.com/tenderfeed/switzerland-simap-tenders)
- [World Bank procurement notices & awards](https://apify.com/tenderfeed/world-bank-procurement)
- [Poland BZP e-Zamówienia tenders](https://apify.com/tenderfeed/poland-bzp-tenders)
- [Ukraine Prozorro tenders](https://apify.com/tenderfeed/ukraine-prozorro-tenders)
- [AusTender Australian government contracts](https://apify.com/tenderfeed/australia-austender-contracts)
- [EU Funding & Tenders Portal grants and calls](https://apify.com/tenderfeed/eu-funding-tenders-portal)
- [CanadaBuys tenders and awards](https://apify.com/tenderfeed/canada-canadabuys-tenders)
- [NYC City Record bids & awards](https://apify.com/tenderfeed/nyc-city-record-procurement)
- [Brazil PNCP licitações](https://apify.com/tenderfeed/brazil-pncp-tenders)
- [Colombia SECOP II licitaciones](https://apify.com/tenderfeed/colombia-secop-tenders)
- [Netherlands TenderNed aanbestedingen](https://apify.com/tenderfeed/netherlands-tenderned-tenders)

### Sample output (real run)

One row from a run on 6 November 2026 (core columns only; every row also has description, status, procedureType, documentsUrl and more). Contact values are masked here. Since schema 1.2 every row also carries the cross-source columns `country`, `deadline`, `valueAmount`, `valueCurrency` and `cpvOrNaics` next to the original ones (`buyerCountry`, `deadlineAt`, `estimatedValue`, `currency`, `cpvCodes`/`naicsCodes`), which are unchanged.

```json
{
  "title": "LK - Urbane Datenplattform Smart City 2027",
  "source": "de-oeffentlichevergabe",
  "country": "DE",
  "noticeType": "cn-standard",
  "publishedAt": "2026-11-05T07:01:16Z",
  "deadline": "2026-12-01T14:30:00+01:00",
  "buyerName": "Stadt Hameln - Zentrale Vergabestelle - im Auftrag des Landkreises Hameln-Pyrmont",
  "valueAmount": null,
  "valueCurrency": null,
  "cpvOrNaics": "72000000",
  "setAside": null,
  "url": "https://oeffentlichevergabe.de/ui/de/search/details?noticeId=26005758",
  "buyerContactName": null,
  "buyerContactEmail": null,
  "buyerContactPhone": null
}
```

### Limits and notes

- **Data source:** oeffentlichevergabe.de (Datenservice Öffentlicher Einkauf) open notice data.
- **Access:** No login or API key.
- **Delays and gaps:** Notices are in German. Value is often not published. Notices only published on regional portals without forwarding to the national data service may be missing.
- **Contacts:** No buyer contact persons are extracted.
- Fields the portal does not publish stay `null`; nothing is guessed or filled in.

### FAQ

**Is this legal?** Yes. The data comes from the official public export of oeffentlichevergabe.de, published under CC0. Personal data is excluded unless you set `includeBuyerContacts: true`.

**Can I use it from an AI agent?** Yes, as an MCP tool through the Apify MCP server, e.g. "Which German hospitals are tendering IT services this week?"

# Actor input Schema

## `keywords` (type: `array`):

Words to look for in title, description and lot titles. Notices are mostly in German, e.g. \["Software", "Reinigung", "Bauleistungen"]. Matches word starts, so "Reinigung" also finds "Reinigungsleistungen".

## `keywordMode` (type: `string`):

Match ANY or ALL keywords.

## `stages` (type: `array`):

tender = calls for tenders (incl. corrections), award = contract award / result notices with winners, planning = prior information notices.

## `contractTypes` (type: `array`):

Empty = all.

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

CPV codes or prefixes; 72000000 or 72 = all IT services, 45 = construction works, 90911 = cleaning.

## `regions` (type: `array`):

NUTS prefix of the buyer or place of performance: DE1 Baden-Württemberg, DE2 Bayern, DE3 Berlin, DE4 Brandenburg, DE5 Bremen, DE6 Hamburg, DE7 Hessen, DE8 Mecklenburg-Vorpommern, DE9 Niedersachsen, DEA Nordrhein-Westfalen, DEB Rheinland-Pfalz, DEC Saarland, DED Sachsen, DEE Sachsen-Anhalt, DEF Schleswig-Holstein, DEG Thüringen. Finer codes work too (DE212 = München); state names like "Bayern" or "NRW" are accepted.

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

e.g. "Stadt", "Deutsche Bahn" or "Universität".

## `publishedFrom` (type: `string`):

YYYY-MM-DD or relative ("7 days"). Default: last 2 days.

## `publishedTo` (type: `string`):

YYYY-MM-DD. Default: yesterday (the official daily export covers completed days).

## `onlyOpen` (type: `boolean`):

Keep only notices whose submission deadline is still in the future.

## `onlyEuWide` (type: `boolean`):

Keep only notices published under the EU procurement directives (above EU thresholds). Off = also national below-threshold notices (Unterschwellenvergabe), which TED does not carry.

## `minValue` (type: `integer`):

Estimated value (or awarded value for award notices) when the buyer publishes it. Many German notices do not publish a value.

## `maxValue` (type: `integer`):

Estimated value (or awarded value for award notices) when the buyer publishes it.

## `includeUnknownValue` (type: `boolean`):

Keep notices that publish no value when a value filter is set.

## `maxResults` (type: `integer`):

0 = no limit. Default 50. oeffentlichevergabe.de publishes about 1,000 notices per working day.

## `includeBuyerContacts` (type: `boolean`):

Include named contact persons, emails and phone numbers published in the notices (buyerContactName/Email/Phone). Off by default for GDPR data minimisation: you then get organization-level info only (buyer name, city, state, notice and document links). Turn on only if you have a lawful basis (e.g. legitimate interest for B2G bid contact) to process this personal data.

## `onlyNew` (type: `boolean`):

Remember what earlier runs delivered and return (and charge for) only notices you have not received yet. Ideal for scheduled daily alerts.

## `monitoringId` (type: `string`):

Name of the watch-list memory used by 'Only new'. Use a different ID per saved search/schedule.

## `includeRawData` (type: `boolean`):

Adds the full OCDS release under `raw` (bigger output). Personal contact keys are removed unless contacts are on.

## Actor input object example

```json
{
  "keywordMode": "any",
  "stages": [
    "tender"
  ],
  "onlyOpen": false,
  "onlyEuWide": false,
  "includeUnknownValue": true,
  "maxResults": 20,
  "includeBuyerContacts": false,
  "onlyNew": false,
  "includeRawData": false
}
```

# Actor output Schema

## `results` (type: `string`):

All normalized records from the default dataset, opened in the Overview view.

# 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 = {
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("tenderfeed/germany-public-tenders").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 = { "maxResults": 20 }

# Run the Actor and wait for it to finish
run = client.actor("tenderfeed/germany-public-tenders").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 '{
  "maxResults": 20
}' |
apify call tenderfeed/germany-public-tenders --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tenderfeed/germany-public-tenders"
        }
    }
}
```

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/vXX3FH4c4R2s3UYpl/builds/ExrsrGYgkEMyx1dIX/openapi.json
