# India eProcure Tender Notices Scraper (`automation-lab/india-government-tender-feeds`) Actor

Refresh current India eProcure tender notices from CPPP central, state and IOCL feeds. Export titles, references, agencies or states, dates and source links for bid monitoring.

- **URL**: https://apify.com/automation-lab/india-government-tender-feeds.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 40.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.96 / 1,000 item extracteds

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?

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

## India eProcure Tender Notices Scraper

Refresh **India eProcure tender notices** from the current CPPP central and state feeds and the Indian Oil Corporation (IOCL) homepage. Export a small, normalized snapshot for supplier bid monitoring, spreadsheet review and downstream comparisons.

This is a **snapshot feed scraper**, not an exhaustive Indian procurement search engine. Each selected feed usually shows ten notices. Central notices include defence agencies when present in the current feed; there is no separate defence search.

### Who is this for?

- Government suppliers checking newly surfaced opportunities during their daily bid review.
- Procurement analysts combining central, state and IOCL notices in a spreadsheet.
- Sales operations teams collecting dated snapshots for their own comparison pipeline.

### Why use this Actor?

Three public feeds share one consistent dataset. Every notice retains its source and reference, and missing source fields remain null rather than being guessed. Lightweight requests avoid loading browsers or downloading bid documents.

The useful distinction is a bounded, source-attributed snapshot. It does not promise the richer search, detail extraction or archive coverage available from other products.

### Getting started

1. Open the Actor and keep the three default feeds selected.
2. Set a global `maxItems` between 1 and 30.
3. Optionally enter a phrase to filter the fetched snapshot locally.
4. Run the Actor and inspect the dataset.
5. Export JSON, CSV or Excel through Apify's dataset tools.

The default input is:

```json
{"sources":["central","state","iocl"],"maxItems":30,"keyword":""}
```

### Supported India eProcure tender notices

| Feed | Public surface | Included fields |
| --- | --- | --- |
| `central` | CPPP latest active central tenders | Title, reference, tender ID, organisation and dates |
| `state` | CPPP latest active state tenders | Title, reference, tender ID, state and dates |
| `iocl` | IOCL latest-tenders homepage | Title, reference, closing/opening dates and source link |

Only the first snapshot page is fetched. Notices can change between runs. No forms are submitted and no CAPTCHA is solved. The state feed does not expose the buying agency in its list; IOCL homepage does not expose the tender ID or publication date.

### Input parameters

| Parameter | Default | Meaning |
| --- | --- | --- |
| `sources` | All three | Nonempty selection of `central`, `state`, `iocl`, fetched in supplied order; duplicates removed |
| `keyword` | Empty | One literal case-insensitive substring across title, reference, agency and state |
| `maxItems` | 30 | Global saved-notice limit, 1–30, after filtering and deduplication |

Keyword whitespace is trimmed and collapsed. It is not whole-word matching, a source search or comma-separated ANY/ALL matching. An empty string accepts all fetched notices. A rare phrase may match nothing because it is applied only to the current snapshots.

All selected feeds are checked even if `maxItems` is small. The first selected feed has priority when the limit truncates results. Zero and unlimited limits, custom URLs, agency search forms and unsupported fields are rejected.

### Output fields

| Field | Meaning |
| --- | --- |
| `source` | `central`, `state` or `iocl` |
| `title` | Displayed notice title; source truncation is preserved |
| `reference` | Tender reference, including internal slashes |
| `tenderId` | CPPP tender identifier; null on the IOCL homepage |
| `agency` | Central organisation or IOCL; null for state list rows |
| `state` | State-list jurisdiction; null otherwise, never inferred from title |
| `publishedAt` | Source publication text; null for IOCL |
| `closingAt` | Source bid closing date text |
| `openingAt` | Source bid opening date text |
| `sourceUrl` | Source-provided notice link; may be session-bound |
| `feedUrl` | Stable snapshot page URL |
| `scrapedAt` | UTC ISO retrieval timestamp |

Procurement dates are preserved as India-local source strings, such as `20-Oct-2026 06:00 PM`; they are not converted to UTC. Only `scrapedAt` is a UTC timestamp. Source links may expire; use the stable feed URL and tender reference to locate a notice later.

### Example result

A representative central notice observed during testing:

```json
{
  "source": "central",
  "title": "Construction of Bathing Ghat at Basundha",
  "reference": "NTPC/Darlipali STPP/9900335586",
  "tenderId": "2026_NTPC_112893_1",
  "agency": "NTPC Limited",
  "state": null,
  "publishedAt": "20-Oct-2026 06:30 PM",
  "closingAt": "02-Nov-2026 04:00 PM",
  "openingAt": "03-Nov-2026 10:00 AM",
  "sourceUrl": "https://eprocure.gov.in/cppp/tendersfullview/...",
  "feedUrl": "https://eprocure.gov.in/cppp/latestactivetendersnew/cpppdata",
  "scrapedAt": "2026-10-20T14:00:00.000Z"
}
```

The long source link above is shortened for readability. Actual output retains the full source-supplied URL.

### How much does it cost to extract India eProcure tender notices?

Pay per event: a **$0.003 start fee per run**, plus each saved notice. Filtered-out and duplicate notices do not incur an item fee. A legitimate no-match snapshot still incurs the start fee.

| Apify plan tier | Price per saved notice |
| --- | --- |
| FREE | $0.00184 |
| BRONZE | $0.0016 |
| SILVER | $0.001248 |
| GOLD | $0.00096 |
| PLATINUM | $0.00096 |
| DIAMOND | $0.00096 |

At BRONZE, 1 notice costs $0.0046; 10 notices cost $0.019; 30 notices cost $0.051. These are Actor event charges, not a statement of your overall Apify subscription costs. Check current Store pricing before running. Configure an adequate run charge limit; a restrictive limit may stop saved output early.

### Limits and failure behavior

- Approximately ten current rows per feed; at most 30 saved notices per run.
- No pagination, exhaustive archives, awards, document downloads, protected searches, login or automated bidding.
- No tender value, EMD, category or contact enrichment.
- No built-in historical store, cross-run comparison, alert delivery or guaranteed update frequency.
- All selected feeds must parse before output is saved; an unavailable feed fails the run instead of returning silent partial coverage.
- Transient network errors, HTTP 429 and 5xx get at most three attempts per feed, with bounded delays. Stable other HTTP errors and unexpected page/table shapes fail explicitly.
- Requests are direct and sequential. There is no paid proxy fallback or browser mode.

A deadline is not a guarantee that a tender remains open. Verify the official notice, current corrigenda and bid documents manually before taking action.

### Integrations

Schedule this Actor in Apify to collect recurring snapshots, then compare `source` plus `tenderId` or `reference` in your database. Scheduling does not turn a first-page feed into complete tender coverage.

Use dataset exports for Excel or Google Sheets, webhooks for your own completed-run pipeline, and Make, Zapier or n8n for notifications you implement. Save the full dataset outside an AI conversation when maintaining a history.

### API usage

Start a run once, then retain its run ID. Retrieve dataset items after successful completion.

```bash
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~india-government-tender-feeds/runs' \
  -H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: application/json' \
  -d '{"sources":["state"],"maxItems":10}'
```

JavaScript with the Apify client:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/india-government-tender-feeds')
  .call({ sources: ['iocl'], maxItems: 10 });
if (run.status !== 'SUCCEEDED') throw new Error(run.status);
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 30 });
console.log(items);
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/india-government-tender-feeds').call(
    run_input={'sources': ['central'], 'maxItems': 10})
if run['status'] != 'SUCCEEDED':
    raise RuntimeError(run['status'])
print(client.dataset(run['defaultDatasetId']).list_items(limit=30).items)
```

### MCP usage

Use the Actor-specific hosted endpoint in a compatible client:

```bash
claude mcp add --transport http apify \
  'https://mcp.apify.com?tools=automation-lab/india-government-tender-feeds'
```

Equivalent configuration for Claude Desktop, Cursor, and VS Code (adapt the client-specific MCP settings container):

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/india-government-tender-feeds"}}}
```

Discover actual names and input schemas with `tools/list`; the selection also includes run/data helpers, not exactly one tool. Authentication and tool access depend on your client and Apify account. Example prompt: “Fetch the current IOCL tender snapshot with maxItems 10, then summarize closing dates.”

For an authorized execution, start once and retain the run and storage IDs. They are metadata, not records. If still running after the server wait (maximum 45 seconds), check the same run with 2/4/8-second backoff capped at 10 seconds and a 120-second total deadline. Do not restart after a client timeout; recover the known run or report uncertainty. At deadline report pending and the run ID.

After success, read dataset pages with explicit offset/limit/fields. For example, read at most 100 source rows in pages of 20 and at most 64 KiB of serialized UTF-8 result content admitted to model context, whichever comes first. Enforce the byte ceiling host-side, disclose oversized/truncated records and preserve the next source offset. A client unable to intercept oversized results cannot promise that ceiling. Failed runs are failures even if partial rows exist. Full exports belong in storage, not model context. No numeric token-savings guarantee is made.

### Legality and responsible use

This independent tool is not affiliated with CPPP, NIC or Indian Oil. Use public procurement notices responsibly, comply with source terms and applicable law, and verify official records before bidding. It does not supply legal, procurement or eligibility advice.

Failed operations send sanitized diagnostic input, exceptions and Actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed; reports are retained for 30 days. No login credentials are accepted by this Actor. No AI is used during runs or to transform output. Public procurement text is collected without contact-detail enrichment. Apify stores results and logs under your account retention settings; delete datasets and key-value stores when no longer needed. We keep no separate tender archive. For help, open an issue on the Actor's Apify Store page.

### FAQ and troubleshooting

**Why are there fewer than 30 rows?** A selected feed can contain fewer notices, a local filter can exclude them, or your global/charge limit can truncate output. Selecting one feed normally gives ten rows, not thirty.

**Why does my keyword return nothing?** It filters the snapshot, not the entire portal. Remove it to inspect the current source data; no extra pages are fetched to fill the limit.

**Can I monitor every Indian tender?** No. This is a current first-page snapshot. Use it as one signal, not an exhaustive procurement registry.

**Why did the run fail when two feeds worked?** The Actor refuses partial-source success. Retry later after a temporary outage or deliberately select only the sources you need.

**Why does a source link no longer open?** Some portals issue session-bound links. Use `feedUrl` and the reference on the official portal. The Actor does not fetch details to refresh those links.

### Related workflows

For another jurisdiction, [Cal eProcure Solicitations Scraper](https://apify.com/automation-lab/cal-eprocure-solicitations-contracts) serves California contracts rather than Indian tenders. Keep jurisdiction and record identity separate when combining procurement feeds.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/india-government-tender-feeds/changelog.md

# Actor input Schema

## `sources` (type: `array`):

Select central (CPPP, including defence notices), state (CPPP state feed), or iocl (IOCL homepage). Each is fetched once, in supplied order; duplicates are removed. All selected feeds must succeed. About ten notices per feed; not exhaustive India-wide coverage.

## `keyword` (type: `string`):

Optional case-insensitive substring of combined title, reference, agency and state. Whitespace is collapsed and trimmed. Not whole-word or source-side search. One literal phrase, not comma-separated ANY/ALL terms. Blank accepts all snapshot notices; filtering never fetches more pages.

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

Global maximum saved notices after deduplication and local filtering, in selected feed order. Defaults to 30, allowed 1–30; zero/unlimited is unsupported. All selected feed snapshots are checked even for a small limit. A feed normally exposes ten rows; fewer matches can be returned.

## Actor input object example

```json
{
  "sources": [
    "central",
    "state",
    "iocl"
  ],
  "keyword": "",
  "maxItems": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Normalized snapshot rows with tender references, nullable source fields, India-local date text and source links.

# 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 = {
    "sources": [
        "central",
        "state",
        "iocl"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/india-government-tender-feeds").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 = {
    "sources": [
        "central",
        "state",
        "iocl",
    ],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/india-government-tender-feeds").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 '{
  "sources": [
    "central",
    "state",
    "iocl"
  ],
  "maxItems": 20
}' |
apify call automation-lab/india-government-tender-feeds --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/india-government-tender-feeds"
        }
    }
}
```

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/eVE0gknhcYqDAkDoS/builds/gfU6z3HmxfeE7YUYY/openapi.json
