# Brazil Public Tenders (PNCP) Scraper (`dankhael/brazil-tenders-pncp`) Actor

Search open Brazilian government tenders (licitações) by keyword, state and contract value. Reads the official PNCP registry, which has no keyword search of its own. Returns buyer, city, estimated value, proposal deadline and a direct link — ready for daily bid monitoring.

- **URL**: https://apify.com/dankhael/brazil-tenders-pncp.md
- **Developed by:** [Danilo Mikhael da Silva Melo](https://apify.com/dankhael) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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/platform/actors/running/actors-in-store#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

## Brazil Public Tenders (PNCP) Scraper

Find every open Brazilian government tender that matches your business — by
keyword, state and contract value — from the official federal registry.

Brazil publishes all public procurement to **PNCP** (*Portal Nacional de
Contratações Públicas*), the registry mandated by Lei 14.133/2021. At any
given moment there are **15,000+ tenders open for proposals**. The official
portal lets you filter by state and modality, but **not by what is actually
being bought** — so finding the contracts relevant to you means reading
thousands of records by hand.

This Actor does that filtering for you and returns clean, structured results.

### What you get

Search across every open tender in Brazil and export only the ones that match:

- **Keyword search** over the tender object, description and buying agency —
  accent-insensitive, so `ambulancia` also matches `ambulância`
- **Exclude terms** to kill recurring false positives
- **AND / OR matching** for narrow searches like `software` + `gestão`
- **State (UF) filter** — one state, several, or the whole country
- **Contract value range** in BRL
- **All 13 procurement modalities** (Pregão Eletrônico, Dispensa,
  Concorrência, Credenciamento, …)
- **Direct links** to each tender's public PNCP page

### Who uses this

- **Companies that sell to government** — daily alerts for new contracts in
  your category, without paying for a full bid-monitoring subscription
- **Bid-writing consultancies** tracking opportunities for many clients
- **Market researchers** sizing public demand for a product category
- **Journalists and civic-tech projects** auditing public spending

### Example

A software vendor searching `software`, `sistema de gestão` and
`licenciamento` across São Paulo, Rio de Janeiro and Minas Gerais scanned
**1,800 open tenders and returned 45 matches** — a combined
**R$ 205 million** in open contract value, all still accepting proposals:

| Object | Buyer | Value | Closes |
| --- | --- | --- | --- |
| Fornecimento, implantação e suporte de sistema | Santo André, SP | R$ 1,262,707.16 | 2026-08-25 |
| Solução tecnológica em ambiente web (SaaS) | Itapetininga, SP | R$ 80,166.66 | 2026-08-19 |
| Plataforma de inteligência artificial (IA) | São Paulo, SP | R$ 180,672.00 | 2026-09-03 |
| Software de proteção contra vírus | Campinas, SP | não divulgado | 2026-08-27 |

A health-equipment supplier searching `ambulancia` in São Paulo found one
R$ 5.6M ambulance contract in Guarulhos — **out of several hundred records**.

That ratio is the point: the relevant contracts are always there, buried in
thousands of irrelevant ones.

### Input

```json
{
  "keywords": ["software", "licenciamento"],
  "excludeKeywords": ["limpeza"],
  "matchAllKeywords": false,
  "states": ["SP", "RJ", "MG"],
  "modalities": [6],
  "minValueBRL": 50000,
  "daysAhead": 90,
  "maxItems": 1000
}
```

Leave `keywords` empty to export every open tender. Leave `states` empty to
search all of Brazil.

### Output

Each result is a flat record with English field names and the original
Portuguese values preserved (the tender text is legal wording and is never
reformatted):

```json
{
  "pncpControlNumber": "46319000000150-1-000203/2026",
  "url": "https://pncp.gov.br/app/editais/46319000000150/2026/203",
  "object": "Locação de ambulâncias com motoristas",
  "modality": "Pregão - Eletrônico",
  "status": "Divulgada no PNCP",
  "estimatedValueBRL": 5637898.2,
  "proposalOpensAt": "2026-08-12T08:00:00",
  "proposalClosesAt": "2026-08-25T09:00:00",
  "buyerName": "PREFEITURA MUNICIPAL DE GUARULHOS",
  "buyerCnpj": "46319000000150",
  "city": "Guarulhos",
  "state": "SP",
  "legalBasis": "Lei 14.133/2021, Art. 28, I",
  "sourceSystemUrl": "https://..."
}
```

Full field list: control number, URL, object, modality, status, dispute mode,
instrument type, estimated and awarded value, price-registry flag, proposal
open/close dates, publication and update timestamps, process and purchase
numbers, buyer name/CNPJ/sphere/branch, administrative unit, city, state,
IBGE code, legal basis, additional information, and source-system links.

### Run it on a schedule

The highest-value use is a **daily scheduled run**. Set your keywords once,
schedule the Actor, and connect the dataset to Slack, email, Google Sheets or
a webhook via Apify integrations. New matching tenders reach you the morning
they are published, while the proposal window is still open.

### Notes on the data

- **Many tenders publish no estimated value** and appear as `0`. This is
  normal on PNCP. Setting `minValueBRL` will exclude them, so leave it empty
  if you would rather see everything.
- **`daysAhead`** controls the proposal deadline window. The default of 90
  days covers the practical bidding horizon.
- Results are **deduplicated** by PNCP control number across states and
  modalities.
- **PNCP occasionally times out.** It is a government service and a
  nationwide scan reads thousands of records, so an outage on one page is
  normal. When that happens the Actor keeps everything it already found and
  logs a warning that results are partial, rather than throwing the run away.
  Re-running picks up whatever was missed. A run only fails if PNCP returned
  nothing at all.
- A **nationwide** search (no states selected) reads 15,000+ records and can
  take 10–20 minutes. Selecting the states you actually sell to is much
  faster and cheaper.

### Source and legality

Data comes from the **public PNCP consultation API**
(`pncp.gov.br/api/consulta/v1`), which is open, documented and requires no
authentication. Brazilian public procurement data is public information under
the Lei de Acesso à Informação (Lei 12.527/2011).

This Actor reads only that public API. It performs no authentication, solves
no CAPTCHAs and circumvents no access controls. It is an independent tool and
is not affiliated with or endorsed by PNCP or the Brazilian government.

# Actor input Schema

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

Only return tenders whose object, description or buyer name contains at least one of these terms. Accent- and case-insensitive, so 'ambulancia' also matches 'ambulância'. Leave empty to return every open tender.

## `excludeKeywords` (type: `array`):

Discard tenders containing any of these terms. Useful for filtering out recurring false positives such as 'locacao' or 'manutencao'.

## `matchAllKeywords` (type: `boolean`):

When enabled, a tender must contain every keyword instead of just one. Use for narrow searches like \['software', 'gestao'].

## `states` (type: `array`):

Restrict results to these Brazilian states. Leave empty to search the whole country.

## `modalities` (type: `array`):

Which procurement modalities to search, as defined by Lei 14.133/2021. Defaults to Pregão Eletrônico (6), which covers the large majority of open tenders.

## `minValueBRL` (type: `integer`):

Skip tenders below this estimated value. Note: many PNCP tenders publish no value (shown as 0); setting a minimum excludes those.

## `maxValueBRL` (type: `integer`):

Skip tenders above this estimated value. Tenders with no published value are kept.

## `daysAhead` (type: `integer`):

Include tenders whose proposal deadline falls within this many days from today.

## `maxItems` (type: `integer`):

Stop after exporting this many matching tenders. Protects you from an unexpectedly broad keyword set.

## Actor input object example

```json
{
  "keywords": [
    "software",
    "licenciamento"
  ],
  "matchAllKeywords": false,
  "modalities": [
    "6"
  ],
  "daysAhead": 90,
  "maxItems": 1000
}
```

# Actor output Schema

## `tenders` (type: `string`):

One row per matching tender, with the purchase object, buying agency, city and state, estimated value in BRL, proposal opening and closing dates, legal basis, and a direct link to the tender's public page on PNCP.

# 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 = {
    "keywords": [
        "ambulancia",
        "equipamento hospitalar"
    ],
    "modalities": [
        "6"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dankhael/brazil-tenders-pncp").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 = {
    "keywords": [
        "ambulancia",
        "equipamento hospitalar",
    ],
    "modalities": ["6"],
}

# Run the Actor and wait for it to finish
run = client.actor("dankhael/brazil-tenders-pncp").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 '{
  "keywords": [
    "ambulancia",
    "equipamento hospitalar"
  ],
  "modalities": [
    "6"
  ]
}' |
apify call dankhael/brazil-tenders-pncp --silent --output-dataset

```

## MCP server setup

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

```

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/Xzyq0VNVAswAPYnGg/builds/KiDGB6VAbFYd9iEfA/openapi.json
