# Ausschreibung.at Scraper — Austrian Public Procurement Tenders (`studio-amba/ausschreibung-at-scraper`) Actor

Search and extract Austrian public and restricted construction tender notices from ausschreibung.at (ANKÖ / Hubexo). Filter by keyword and Bundesland (region). Returns title, region, trade category, publication date and submission deadline. No login required.

- **URL**: https://apify.com/studio-amba/ausschreibung-at-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Ausschreibung.at Scraper — Austrian Public Procurement Tenders

Search and extract Austrian public and restricted construction tender notices from ausschreibung.at, the ANKÖ / Hubexo Austria portal used by federal, regional and municipal bodies (and private developers) to publish construction-sector calls for bids. Filter by keyword and Bundesland (region). Returns the tender title, region, trade category (Gewerk), publication date, submission deadline, and a direct link to the notice. No login required.

### How to scrape Austrian public procurement data

This actor calls the same JSON endpoint ausschreibung.at's own region map uses (`/Home/AusschreibungenRegion`) to pull every currently open tender for a Bundesland in a single request — no pagination, no session cookies, no login. A live check on 2026-09-01 returned 1,402 open tenders for Wien and 806 for Niederösterreich in one call each, with plain HTTP and zero cookies.

Enter a keyword (or leave it blank for the default "Bau", German for construction, which matches most of the site), pick a region or leave it on "All regions", and run. The actor loops through the selected region(s) and stops as soon as it has collected `maxResults` matching tenders.

#### Who benefits from this data?

- **Construction contractors and subcontractors** — Monitor new Austrian public and restricted tenders in your trade (Baumeister, Elektroinstallation, Dachdecker, and 100+ other Gewerk categories) as soon as they're published.
- **Building material suppliers and manufacturers** — Spot upcoming projects in your region before ordering deadlines, and see which trades are being tendered together on the same site.
- **B2B sales and business development teams** — Build a live feed of Austrian construction procurement by Bundesland instead of checking the ANKÖ map manually.
- **Market and competitive researchers** — Track construction tender volume by region and trade category across Austria over time.
- **Bid consultancies and public-sector advisors** — Feed fresh tender alerts into a client-facing monitoring tool without maintaining a scraper against ANKÖ's platform yourself.

#### Search by keyword

`searchQuery` is matched (case-insensitive) against the tender title and the trade category text. This is a client-side filter — ausschreibung.at's free listing endpoint does not accept a full-text search parameter itself, only a region. Leave `searchQuery` empty and the actor defaults to `Bau`, which alone matches roughly a quarter of all Wien titles, so an empty `{}` input always returns real data.

#### Filter by region (Bundesland)

Use `region` to only fetch one of Austria's ten tracked regions (the nine Bundesländer plus Ost-Tirol, which the site tracks separately from the rest of Tirol). Leave it on `ALL` to search every region — the actor fetches regions one at a time and stops as soon as `maxResults` matching tenders have been collected, so a small `maxResults` with `region: ALL` is still fast.

#### Filter by publication date

Use `publishedAfter` (format `YYYY-MM-DD`) to only keep tenders published on or after that date. Useful for daily monitoring runs that only want fresh notices.

### Input parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|--------------|
| `searchQuery` | String | `Bau` | Keyword matched against the tender title and trade category (case-insensitive) |
| `region` | Enum | `ALL` | One of the 10 tracked Austrian regions, or `ALL` |
| `publishedAfter` | String | — (no filter) | Only keep tenders published on or after this date (`YYYY-MM-DD`) |
| `maxResults` | Integer | `50` | Maximum number of tender notices to return (1–5,000) |
| `proxyConfiguration` | Object | Apify proxy | Apify proxy settings |

### What data does this scraper extract?

| Field | Type | Description |
|-------|------|--------------|
| `itemTitle` | String | Tender title, as published on the region listing. Very long titles are truncated by the source site itself (ends in "...") — see Limitations |
| `tenderId` | String | ausschreibung.at's internal tender ID |
| `organization` | String | Always empty in this version — see Limitations |
| `region` | String | Austrian Bundesland the tender belongs to |
| `tradeCategory` | String | Trade(s)/Gewerk this tender covers, e.g. "Baumeisterarbeiten", "Elektroinstallationsarbeiten" (can list several trades per tender) |
| `publicationDate` | String | Date the notice was published (ISO date) |
| `deadline` | String | Bid submission deadline (ISO date). Empty when `isOpenEnded` is `true` |
| `isOpenEnded` | Boolean | `true` for framework/ongoing tenders with no fixed submission deadline (the source site uses a `31.12.2999` sentinel for these) |
| `status` | String | `Open` or `Closed`, derived from whether the deadline has passed (always `Open` when `isOpenEnded`) |
| `url` | String | Direct link to the tender on ausschreibung.at |
| `scrapedAt` | String | ISO timestamp of when the data was scraped |

### Example output

```json
{
    "itemTitle": "Baumeisterarbeiten Sanitäranlagen Sektor C",
    "tenderId": "568656",
    "organization": "",
    "region": "Wien",
    "tradeCategory": "Baumeisterarbeiten",
    "publicationDate": "2026-08-31",
    "deadline": "2026-09-22",
    "isOpenEnded": false,
    "status": "Open",
    "url": "https://www.ausschreibung.at/Ausschreibung/568656",
    "scrapedAt": "2026-09-01T09:17:22.497Z"
}
```

### Tips for best results

- **Daily monitoring**: Schedule a run with `publishedAfter` set to yesterday's date to catch only newly published tenders without re-pulling the whole active list every time.
- **Broad discovery first**: Leave `searchQuery` on its `Bau` default and `region` on `ALL` on the first run to see the spread of currently open Austrian construction tenders, then narrow with a trade-specific keyword (e.g. `Elektro`, `Dachdecker`, `Fenster`) once you know your niche.
- **One region at a time for speed**: If you only care about one Bundesland, set `region` explicitly — the actor then makes a single request instead of looping through all ten.
- **Open-ended tenders**: Framework agreements and ongoing calls carry `isOpenEnded: true` and an empty `deadline` — that is the source site's own convention, not a missing field.

### How much does it cost to run?

ausschreibung.at's free listing endpoint is public and requires no login. Your only cost is Apify compute time and proxy usage. The actor makes one request per region (up to 10 for `region: ALL`), each returning hundreds of tenders, so run time and cost barely scale with `maxResults` for small-to-medium requests — cost estimate per result stays well under a cent.

| Search size | Estimated time | Estimated cost |
|-------------|----------------|-----------------|
| 20 tenders | ~5 seconds | ~$0.005 |
| 100 tenders | ~10 seconds | ~$0.01 |
| 500 tenders (region: ALL) | ~30 seconds | ~$0.03 |

Actual cost depends on your Apify plan and proxy usage; a run's final usage cost only settles after the run reports SUCCEEDED — reading the dataset mid-run will undercount it.

### Use as an API

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("studio-amba/ausschreibung-at-scraper").call(run_input={
    "searchQuery": "Elektro",
    "region": "9",
    "maxResults": 50,
})

for tender in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{tender['itemTitle']} | {tender['region']} | deadline {tender['deadline']}")
```

### Limitations

- **`organization` (contracting authority/buyer) is always empty**: ausschreibung.at's free region listing does not include the buyer name — that field is only shown on the individual tender detail page, which sits behind a paid ANKÖ login ("Login erforderlich", confirmed live 2026-09-01). This actor does not authenticate and only scrapes the free listing.
- **No CPV codes, reference numbers, procedure type or full description**: the same login wall applies to these fields. Use the `url` field to open the full notice on ausschreibung.at if you have an ANKÖ account.
- **No native keyword search**: ausschreibung.at's free endpoint only accepts a region filter server-side. `searchQuery` is applied client-side against the title and trade category after fetching a region's full listing.
- **Titles can be truncated**: very long tender titles are cut off by the source site itself with a literal "..." — the full title is only visible on the (login-gated) detail page.
- **Construction sector only**: ausschreibung.at (and ANKÖ) focuses on Bauausschreibungen (construction and construction-adjacent trades). It is not a general cross-sector procurement portal.

### Other European procurement scrapers

Check the [Studio AMBA actor catalog](https://apify.com/studio-amba) for more European public procurement data, including BASE.gov.pt (Portugal), eTenders (Ireland), Udbud.dk (Denmark), e-Vergabe (Germany), and e-Zamówienia (Poland).

### Maintained by Studio Amba

We run 700+ scrapers for European websites, and the priority is keeping
every one of them working. Automated runs test this actor against the live
site and verify the output is complete. When the website changes, the
scraper usually gets repaired the same day, without you having to report
anything. Questions and issues go straight to the people who built it, and
most get an answer the same day.

### Need this data on a schedule, or a custom version?

We run this scraper as a managed service for businesses: scheduled runs,
deduplication, delta detection, and delivery to your inbox, Google Sheets,
or API, maintenance included. We can also build a custom version with your
exact fields and filters, or combine multiple sources into one feed.

See [studioamba.dev/services](https://studioamba.dev/services/) or email
<hello@studioamba.dev> for a free data sample.

### Your feedback

Found a bug or want a feature? Open an issue on the [Issues tab](https://console.apify.com/actors/studio-amba~ausschreibung-at-scraper/issues).

# Actor input Schema

## `searchQuery` (type: `string`):

Filter tenders by keyword, matched (case-insensitive) against the tender title and trade category (Gewerk). Leave empty for a broad default of 'Bau' (German for construction) so the actor always returns data.

## `region` (type: `string`):

Only return tenders from this Austrian region. Choose ALL to search every region (the actor stops early once maxResults is reached).

## `publishedAfter` (type: `string`):

Only return tenders published on or after this date (YYYY-MM-DD). Leave empty for no date filter.

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

Maximum number of tender notices to return. The actor fetches one full region listing per request (no pagination on the site) and stops once this many matching notices have been collected.

## `proxyConfiguration` (type: `object`):

Apify proxy configuration. ausschreibung.at itself has no anti-bot protection, but Apify's datacenter proxy pool times out against this domain -- Austrian RESIDENTIAL is used by default and verified working.

## Actor input object example

```json
{
  "searchQuery": "Bau",
  "region": "ALL",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AT"
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "searchQuery": "Bau",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "AT"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/ausschreibung-at-scraper").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 = {
    "searchQuery": "Bau",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "AT",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/ausschreibung-at-scraper").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 '{
  "searchQuery": "Bau",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AT"
  }
}' |
apify call studio-amba/ausschreibung-at-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/ausschreibung-at-scraper"
        }
    }
}

```

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/VObwa9XgfXoB3FeJN/builds/Mzkj5W8tUVXuP0zR7/openapi.json
