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

Search every Brazilian public tender from the official PNCP register by keyword, state, value and deadline. Public data, no API key. 27 flat fields, deduplicated, Excel-ready.

- **URL**: https://apify.com/dimitrigaulia/brazil-public-tenders-pncp.md
- **Developed by:** [Dimitri Fernandes Gaulia](https://apify.com/dimitrigaulia) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

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

Search every public tender in Brazil by **keyword, state, value and deadline** — and get a clean spreadsheet instead of nested JSON.

Data comes from **PNCP** (Portal Nacional de Contratações Públicas), the official federal register that every Brazilian public body is legally required to publish to. Public data, no API key, no login, no cookies.

Brazil's public sector buys around **R$ 1 trillion a year**. Every one of those contracts is announced here first.

### Why not just call the PNCP API yourself

You can. Here is what you run into:

| PNCP raw API | This Actor |
|---|---|
| `codigoModalidadeContratacao` is **mandatory and single-valued** — "all tenders in São Paulo" means 13 separate paginated crawls | Pick any set of modes, it crawls them all |
| **No keyword search at all** — you cannot ask for "software" | Accent- and case-insensitive keyword include/exclude on the tender object |
| No value filter | Min/max estimated value |
| No "still open for bids" filter | One checkbox |
| Nested objects (`orgaoEntidade`, `unidadeOrgao`, `amparoLegal`) | 27 flat columns, ready for Excel |
| **Returns duplicates** when new tenders are inserted mid-crawl | Deduplicated by tender control number |
| Answers **HTTP 429** after a few dozen pages and dies | Backs off and finishes the job |

### Use cases

- **Sell to the government** — get a daily feed of open tenders matching what your company actually supplies
- **Competitive intelligence** — track what a specific public body (by CNPJ) is buying
- **Market sizing** — how much is spent on your category, by state, per quarter
- **Lead generation** — buyers with an active budget and a published deadline
- **Feed an AI agent** — clean rows for RAG, alerts or classification pipelines

### Input

| Field | What it does |
|---|---|
| `diasRetroativos` | Days back from today. Use `1` for a daily monitor. |
| `dataInicial` / `dataFinal` | Explicit window (`YYYY-MM-DD`), overrides the above |
| `modalidades` | Procurement modes. Default `6` (Pregão Eletrônico), the most common |
| `ufs` | States, e.g. `["SP","RJ"]`. Empty = whole country |
| `palavrasChave` | Keep only tenders containing any of these words |
| `palavrasExcluir` | Drop tenders containing any of these words |
| `valorMin` / `valorMax` | Estimated value range in BRL |
| `somenteAbertas` | Only tenders whose bidding deadline has not passed |
| `cnpj` | Watch one specific public body |
| `maxResultados` | Hard cap on rows |

#### Example: IT tenders open for bids in São Paulo

```json
{
  "diasRetroativos": 7,
  "modalidades": ["6"],
  "ufs": ["SP"],
  "palavrasChave": ["software", "licenca de uso", "sistema de gestao"],
  "somenteAbertas": true,
  "valorMin": 30000,
  "maxResultados": 500
}
```

### Output

One flat row per tender, 27 fields:

```json
{
  "numeroControlePNCP": "01612441000107-1-000131/2026",
  "objetoCompra": "Contratação de licença de uso de programa de informática...",
  "valorTotalEstimado": 46150.0,
  "modalidadeNome": "Pregão - Eletrônico",
  "situacaoCompraNome": "Divulgada no PNCP",
  "dataAberturaProposta": "2026-08-25T08:00:01",
  "dataEncerramentoProposta": "2026-09-10T08:00:01",
  "orgaoCnpj": "01612441000107",
  "orgaoRazaoSocial": "MUNICIPIO DE BELA VISTA DO CAROBA",
  "uf": "PR",
  "municipio": "Bela Vista da Caroba",
  "urlPncp": "https://pncp.gov.br/app/editais/01612441000107/1-000131/2026"
}
```

Plus `valorTotalHomologado`, `modoDisputaNome`, `dataPublicacaoPncp`, `numeroCompra`, `anoCompra`, `processo`, `orgaoPoder`, `orgaoEsfera`, `unidadeNome`, `unidadeCodigo`, `codigoIbge`, `amparoLegal`, `informacaoComplementar`, `linkSistemaOrigem`.

Export as JSON, CSV, Excel or XML, or read it from the API.

### Daily monitor

Schedule the Actor with `diasRetroativos: 1` and your keywords. Every morning you get only what was published in the last 24 hours matching your business — connect it to Slack, email, Make or n8n through Apify integrations.

### Notes

- PNCP rate-limits aggressively. The Actor throttles and backs off, so a wide query takes minutes rather than failing.
- `valorTotalEstimado` is sometimes `0` when the body chooses to keep the budget confidential — that is the source data, not a bug.
- Data is published by thousands of public bodies with varying diligence; text quality reflects the original filing.

# Actor input Schema

## `diasRetroativos` (type: `integer`):

How many days back from today to search. Ignored if you set explicit dates below. Use 1 for a daily monitor.

## `dataInicial` (type: `string`):

Explicit start of the publication window. Overrides 'Days back'.

## `dataFinal` (type: `string`):

Explicit end of the publication window. Overrides 'Days back'.

## `modalidades` (type: `array`):

PNCP requires exactly one mode per request. Pick as many as you like here and the Actor crawls each one for you.

## `ufs` (type: `array`):

Leave empty for the whole country.

## `palavrasChave` (type: `array`):

Accent and case insensitive, matched against the tender object and complementary info. Empty means no keyword filter. This is the filter PNCP itself does not offer.

## `palavrasExcluir` (type: `array`):

Drop tenders whose object contains any of these words. Useful to strip out categories you never bid on.

## `valorMin` (type: `integer`):

Ignore tenders estimated below this value. Leave empty for no floor.

## `valorMax` (type: `integer`):

Ignore tenders estimated above this value. Leave empty for no ceiling.

## `somenteAbertas` (type: `boolean`):

Drops anything whose proposal deadline has already passed.

## `cnpj` (type: `string`):

Digits only. Use it to watch one specific public body.

## `maxResultados` (type: `integer`):

Hard cap on rows. Keeps a broad query from running away.

## Actor input object example

```json
{
  "diasRetroativos": 7,
  "modalidades": [
    "6"
  ],
  "ufs": [
    "SP"
  ],
  "palavrasChave": [
    "software",
    "licenca de uso",
    "sistema de gestao"
  ],
  "palavrasExcluir": [],
  "somenteAbertas": false,
  "maxResultados": 1000
}
```

# Actor output Schema

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

All tenders matching your filters, as JSON.

## `tendersCsv` (type: `string`):

Same rows as CSV, ready to open in Excel or Google Sheets.

## `datasetView` (type: `string`):

Interactive table of the results.

# 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 = {
    "ufs": [
        "SP"
    ],
    "palavrasChave": [
        "software",
        "licenca de uso",
        "sistema de gestao"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dimitrigaulia/brazil-public-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 = {
    "ufs": ["SP"],
    "palavrasChave": [
        "software",
        "licenca de uso",
        "sistema de gestao",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("dimitrigaulia/brazil-public-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 '{
  "ufs": [
    "SP"
  ],
  "palavrasChave": [
    "software",
    "licenca de uso",
    "sistema de gestao"
  ]
}' |
apify call dimitrigaulia/brazil-public-tenders-pncp --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dimitrigaulia/brazil-public-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/3i8RosfY3rnN4Pbko/builds/knfhonGZuOZnARaJW/openapi.json
