# Colorado & Maine State Bids Scraper (RFPs, IFBs, RFQs) (`civitab/cgi-vss-solicitations`) Actor

Open Colorado and Maine state government bids (RFPs, IFBs, documented quotes, RFIs) from the public CGI Advantage Vendor Self Service portals. One clean record per solicitation with department, type, status and closing dates. No login, buyer contacts removed, source credited on every record.

- **URL**: https://apify.com/civitab/cgi-vss-solicitations.md
- **Developed by:** [Jason Padilla](https://apify.com/civitab) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 solicitations

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

## Colorado & Maine State Bids Scraper (RFPs, IFBs, RFQs)

*Published by **Civitab**. Apify Store ID: `civitab/cgi-vss-solicitations`.*

Get **open state government solicitations from Colorado and Maine** as clean, structured records. Both states publish their bids on **CGI Advantage "Vendor Self Service" (VSS)** portals: **ColoradoVSS** and **Maine VSS**. This Actor reads the portals' anonymous **Public Access** list, the same view a browser shows to anyone, and returns one tidy record per solicitation. No login, no account and no browser are needed.

### What does it do?

- Reads the **published solicitations** list of each selected state portal, 100 rows per request.
- Returns, for each solicitation: solicitation number, title, department, solicitation type and document code, commodity category (when set), status, and the **closing, published, amended, intent-to-award and public bid-opening dates**. The closing date is given both in UTC and in the state's local time.
- Supports all 7 portal lists: **Open** (default), **All published**, **Closing soon**, **Recently published**, **Recent amendments**, **Recent intents to award** and **Recent awards**.
- Filters by **keywords**, **departments** and **document codes** (e.g. `RFP`, `IFB1`, `DQ1`, `RFI`, `RFQ`).
- **Skips non-bid notices by default.** Public notices you can't bid on (in Colorado, Notices of Contractor Settlement `NCS1` and Sole Source notices `NPSS1`) are left out unless you turn on `includeNotices`. If you do, they are added free of charge and flagged `isBidOpportunity: false`.
- **Credits the source on every record** (`source`), and adds the State of Colorado's data notice (`dataNotice`) to Colorado records.
- **Removes buyer personal data.** The portal grid includes the buyer's name, e-mail, phone and fax; these are dropped before saving, and any e-mail address or phone number in free text is redacted.

### Why use it?

- **Two state portals in one schema.** Colorado and Maine use the same CGI software but separate sites. You get one consistent dataset for both.
- **No manual paging.** The portals show 20 rows at a time in an interactive grid. The Actor pages through the full list for you.
- **Ready for automation.** Run it on a schedule with the *Recently published* or *Closing soon* list and send results to a spreadsheet, Slack or e-mail.
- **Polite and resilient.** Plain HTTPS requests with an identified User-Agent, at least 1 s apart, with exponential backoff and support for the portal's `Retry-After` header (up to 120 s). If the portal session breaks, the Actor rebuilds it and continues without creating duplicates. One state failing does not stop the other.

### Use cases

- **Bid alerts**: a daily list of newly published Colorado and Maine solicitations matching your keywords.
- **Deadline tracking**: the *Closing soon* list with local closing times, for your bid calendar.
- **Competitive intelligence**: the *Recent intents to award* and *Recent awards* lists show which solicitations have reached the award stage.
- **Pipeline building** for consultants who track state opportunities for several clients.
- **Research**: export the *All published* list for analysis of state purchasing by department, type and category.

### Who is it for?

- **Bid hunters** who watch state portals every day.
- **Contractors and vendors** (construction, IT, professional services, supplies) selling to Colorado or Maine state agencies and institutions.
- **Govcon consultants** managing opportunity pipelines for clients.
- **Market researchers** studying state procurement activity.

### How to use it

1. Open the Actor in Apify Console and go to the **Input** tab.
2. Pick the **States**: Colorado, Maine or both (default: both). States are processed in the order listed.
3. Pick a **List**: Open (default), All published, Closing soon, Recently published, Recent amendments, Recent intents to award or Recent awards.
4. Optionally add **Keywords** (matched against title, type and category), **Departments** (substring match, e.g. `Transportation`, `CDPHE`) and **Solicitation document codes** (e.g. `RFP`, `IFB1`).
5. Set **Max solicitations** to cap the number of results (and the cost) per run.
6. Click **Start**. Results appear in the **Output** tab.
7. To open a bid on the portal, go to `portalUrl`, choose *View Published Solicitations (Public Access)* and search for the `solicitationNumber` (instructions are in each record's `howToOpen` field).
8. For alerts, add a **Schedule** (e.g. every weekday morning) using the *Recently published* list.

### Input example

Colorado roofing and HVAC invitations for bid and RFPs from the Open list:

```json
{
  "states": ["CO"],
  "listType": "open",
  "keywords": ["roof", "hvac"],
  "documentCodes": ["IFB1", "RFP"],
  "maxItems": 200
}
```

Daily check of newly published solicitations in both states:

```json
{
  "states": ["CO", "ME"],
  "listType": "recentlyPublished",
  "maxItems": 100
}
```

#### Input fields

| Field | Type | Default | Description |
|---|---|---|---|
| `states` | array | `["CO","ME"]` | `CO` = ColoradoVSS, `ME` = Maine VSS. |
| `listType` | string | `open` | `open`, `all`, `closingSoon`, `recentlyPublished`, `recentAmendments`, `recentIntents`, `recentAwards`. |
| `keywords` | array | `[]` | Keep solicitations whose title, type or category contains ANY of these (case-insensitive). |
| `departments` | array | – | Keep only departments whose name contains any of these. |
| `documentCodes` | array | – | Keep only these document codes, e.g. `RFP`, `IFB1`, `DQ1`, `RFI`, `RFQ`. |
| `maxItems` | integer | `200` | Overall cap across all states (1-10,000). Caps cost. |
| `requestDelaySecs` | number | `1.0` | Delay between requests (1-10 s). |
| `includeNotices` | boolean | `false` | Also save non-bid public notices (e.g. Colorado `NCS1`, `NPSS1`). They are free of charge and have `isBidOpportunity: false`. |

### Output example

Real records (scraped 22-23 Oct 2026 UTC). The Colorado record comes from a live run; the Maine record from a saved portal response captured the same day. The `source`, `dataNotice` and `isBidOpportunity` values are shown as the current version of the Actor produces them (the Maine record's `scrapedAt` is omitted).

```json
[
  {
    "state": "CO",
    "portal": "Colorado (ColoradoVSS)",
    "solicitationNumber": "RFP-UHAA-2026000258-4",
    "title": "To procure HCBS and Quality and Member Experience Monitoring",
    "department": "HCPF - Executive Director's Office",
    "solicitationType": "Request for Proposals (RFP)",
    "documentCode": "RFP",
    "departmentCode": "UHAA",
    "documentId": "2026000258",
    "version": 4,
    "categoryCode": "21",
    "category": "Personal Svcs",
    "statusCode": "M",
    "status": "Amended",
    "closingDate": "2026-10-23T21:00:00Z",
    "closingDateLocal": "2026-10-23T15:00:00-06:00",
    "publishedDate": "2026-10-16T06:00:00Z",
    "amendedDate": "2026-10-16T06:00:00Z",
    "intentPostedDate": null,
    "publicBidOpeningDate": null,
    "portalUrl": "https://prd.co.cgiadvantage.com/PRDVSS1X1/Advantage4",
    "howToOpen": "Open portalUrl > View Published Solicitations (Public Access) > search the solicitationNumber",
    "source": "Source: State of Colorado, modified",
    "dataNotice": "The data made available here has been modified for use from its original source, which is the State of Colorado",
    "isBidOpportunity": true,
    "scrapedAt": "2026-10-23T02:24:34Z"
  },
  {
    "state": "ME",
    "portal": "Maine (Maine VSS)",
    "solicitationNumber": "RFP-26A-202608137-2",
    "title": "AFTER HOURS TELEPHONE ANSWERING AND COVERAGE SERVICE",
    "department": "ATTORNEY GENERAL",
    "solicitationType": "RFP - Request for Proposals (RFP)",
    "documentCode": "RFP",
    "departmentCode": "26A",
    "documentId": "202608137",
    "version": 2,
    "categoryCode": null,
    "category": null,
    "statusCode": "M",
    "status": "Amended",
    "closingDate": "2026-10-23T20:00:00Z",
    "closingDateLocal": "2026-10-23T16:00:00-04:00",
    "publishedDate": "2026-10-16T04:00:00Z",
    "amendedDate": "2026-10-16T04:00:00Z",
    "intentPostedDate": null,
    "publicBidOpeningDate": null,
    "portalUrl": "https://mevss.hostams.com/PRDVSS1X1/Advantage4",
    "howToOpen": "Open portalUrl > View Published Solicitations (Public Access) > search the solicitationNumber",
    "source": "Source: State of Maine, modified",
    "dataNotice": null,
    "isBidOpportunity": true
  }
]
```

Each run also writes an `OUTPUT` record to the run's key-value store with items per state, the list used, the stop reason, filtered-out count, non-bid notices skipped or saved free, whether the run fee was charged, requests, request success %, session restarts, HTTP status counts and the amount charged.

### Output fields

| Field | Type | Description |
|---|---|---|
| `state` | string | `CO` or `ME`. |
| `portal` | string | Portal name, e.g. `Colorado (ColoradoVSS)`. |
| `solicitationNumber` | string | Solicitation number as shown on the portal, e.g. `RFP-UHAA-2026000258-4`. Search for this on the portal. |
| `title` | string | null | Solicitation title / description. |
| `department` | string | null | Issuing department or institution. |
| `solicitationType` | string | null | Type label, e.g. `Request for Proposals (RFP)`, `Documented Quote (DQ1)`. |
| `documentCode` | string | null | Document code, e.g. `RFP`, `IFB1`, `DQ1`, `RFI`, `RFQ`. |
| `departmentCode` | string | null | Department code from the document reference. |
| `documentId` | string | null | Document ID from the document reference. |
| `version` | integer | null | Document version (increases with amendments). |
| `categoryCode` / `category` | string | null | Commodity category code and label, when the buyer set one. |
| `statusCode` / `status` | string | null | Status code and label, e.g. `O` Open, `M` Amended. |
| `closingDate` | string | null | Closing date and time in UTC. |
| `closingDateLocal` | string | null | Closing date and time in the state's local time zone (America/Denver or America/New_York). |
| `publishedDate` | string | null | Published date (UTC). |
| `amendedDate` | string | null | Last amendment date (UTC), if amended. |
| `intentPostedDate` | string | null | Date an intent to award was posted (UTC), if any. |
| `publicBidOpeningDate` | string | null | Public bid opening date (UTC), if any. |
| `portalUrl` | string | The state's VSS portal address. |
| `howToOpen` | string | How to find the solicitation on the portal. |
| `source` | string | Source credit: `Source: State of Colorado, modified` or `Source: State of Maine, modified`. |
| `dataNotice` | string | null | The State of Colorado's data notice on Colorado records; `null` for Maine. |
| `isBidOpportunity` | boolean | `true` for solicitations you can respond to; `false` for public notices (only saved when `includeNotices` is on). |
| `scrapedAt` | string | When the record was produced (UTC). |

### Pricing

This Actor uses **pay-per-event** pricing:

| Event | When it is charged | Price |
|---|---|---|
| `solicitation` | Each solicitation saved to your dataset | **$0.006** |
| `run-start` | Once per run, when a portal first returns data | **$0.01** |

The run fee is charged only after a portal returns its first row, so a run where every portal fails or returns nothing costs nothing (apart from Apify's standard synthetic "Actor start" event, $0.00005 per run). Solicitations removed by your filters are not charged, and non-bid notices are never charged. `maxItems` and Apify's **Max cost per run** cap your spend, and the Actor stops cleanly when the budget is reached.

Worked examples:

| What you run | Solicitations | Cost |
|---|---|---|
| Daily *Recently published* check returning 5 items | 5 | $0.01 + 5 × $0.006 = **$0.04** |
| Full *Open* list, both states (22 Oct 2026: 80 rows, of which 16 Colorado notices were skipped free) | 64 | $0.01 + $0.384 = **$0.39** |
| Default `maxItems` fully used | 200 | $0.01 + $1.20 = **$1.21** |
| 1,000 solicitations from the *All published* list | 1,000 | $0.01 + $6.00 = **$6.01** |

A weekday alert that returns about 5 new solicitations per run costs about $0.88 per month (22 runs × $0.04).

### Integrations and export

Like any Apify Actor, you can:

- **Export** results as JSON, CSV, Excel, XML or HTML.
- **Use the Apify API** to start runs and fetch results from your own systems.
- **Schedule** runs in Apify Console (e.g. every weekday at 07:00 Mountain Time).
- **Trigger webhooks** when a run finishes, and send results to Google Sheets, Slack, Zapier, Make and other Apify integrations.

### Limitations and data source notes

- **Two states only.** Colorado and Maine are supported. Other states that run CGI Advantage VSS were reviewed and excluded: Michigan (SIGMA VSS banner restricts use to authorized government users), West Virginia (wvOASIS terms restrict data to individual use and prohibit resale without a contract) and Alabama (the legacy portal shows only past opportunities). Asking for these states returns an explanatory error.
- **Metadata only.** The Actor does not download solicitation documents or attachments. Use it to triage, then open the bid on the portal.
- **No deep links.** The portals don't offer stable public links to individual solicitations, so each record gives the portal URL and the solicitation number to search for.
- **Notice detection is rule-based.** A record counts as a non-bid notice when its document code is a known notice code (`NCS1`, `NPSS1`, `NPSS`, `NCS`, `NOA`, `NOI`) or its type label says "Notice of", "Sole Source" or "Intent to Award Notice". To keep only specific types, also use `documentCodes` (e.g. `["RFP", "IFB1", "DQ1", "RFQ", "RFI"]`).
- **Category is often empty.** Buyers don't always set a commodity category: 29 of the 80 open items had one on 22 Oct 2026, and none of the Maine items sampled that day did.
- **Keyword search** covers title, type and category only (the list view has no long description).
- **Caps.** `maxItems` is an overall cap across states, applied in the order you list them. Each state list is read up to 10,000 rows per run.
- **Run fee.** The $0.01 run-start charge applies once a portal returns data, even if your filters then match no solicitations.

### Data source & attribution

Source: State of Colorado / State of Maine, modified

The data made available here has been modified for use from its original source, which is the State of Colorado.

This Actor is not affiliated with or endorsed by the State of Colorado or the State of Maine.

The data is read from the ColoradoVSS and Maine VSS portals (the `portalUrl` field in every record). Every record also carries its own state's credit in `source`, and Colorado records carry the notice above in `dataNotice`.

### Legal and data note

- The data comes from the states' official procurement portals, ColoradoVSS and Maine VSS (see `portalUrl` in each record). Both states direct the public and vendors to browse solicitations through the portals' **Public Access** view without registering. The Actor uses only that public view and does not bypass any login, CAPTCHA or access control.
- At the time of review (22 Oct 2026) neither portal's `robots.txt` restricted crawling (both returned 404) and neither portal displayed terms of use. Check the states' own terms for your intended use.
- **Reuse confirmation:** Civitab has not received written confirmation from the Colorado State Purchasing Office or Maine's Division of Procurement Services that commercial reuse of the portal data is permitted. Civitab should confirm this with both offices; until then, treat reuse terms as unconfirmed and check them for your own use.
- Buyer names, e-mails, phone and fax numbers are removed. Only information about the solicitations themselves is returned.
- This Actor is not affiliated with CGI. It uses no state seals or logos. Always confirm details on the official portal before you bid.

### FAQ

**Which lists can I scrape?**
All seven "Show Me" lists on the portals' published-solicitations page: Open, All published, Closing soon, Recently published, Recent amendments, Recent intents to award and Recent awards.

**Why only Colorado and Maine?**
Other states use the same software, but a portal is only included when anonymous public access is clearly intended and nothing forbids automated reuse. Michigan, West Virginia and Alabama were reviewed and excluded for the reasons listed under *Limitations*.

**Can I open a solicitation straight from a link?**
Not directly; the portals don't support stable public deep links. Open `portalUrl`, choose *View Published Solicitations (Public Access)* and search for the `solicitationNumber`.

**Does it download bid documents?**
No. It returns solicitation metadata so you can triage quickly, then download the documents on the portal.

**How fresh is the data?**
Live: every run reads the portals at that moment.

**What do the document codes mean?**
They are the states' own codes, shown with a label in `solicitationType`. Examples from the data: `RFP` (Request for Proposals), `IFB1` (Invitation for Bid), `DQ1` (Documented Quote), `RFI` (Request for Information), `RFQ` (Request for Quote), `NPSS1` (Sole Source notice), `NCS1` (Notice of Contractor Settlement), and in Maine `RFA` and `PQVL`. `NPSS1` and `NCS1` are notices, not bids, so they are skipped unless `includeNotices` is on.

**Why are closing dates shown twice?**
`closingDate` is UTC, for sorting and automation. `closingDateLocal` is the same moment in Colorado or Maine local time, which is what the solicitation documents use.

**Why is `category` sometimes empty?**
The buyer didn't set a commodity category on the portal. It is left empty rather than guessed.

**How do I keep costs predictable?**
Each run costs $0.01 (once a portal returns data) plus $0.006 per solicitation saved; non-bid notices are free. Set `maxItems` (for example, `maxItems: 100` caps a run at $0.61) or Apify's "Max cost per run".

# Changelog

This Actor's version history is a separate document: https://apify.com/civitab/cgi-vss-solicitations/changelog.md

# Actor input Schema

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

Which state portals to read. CO = ColoradoVSS, ME = Maine VSS.

## `listType` (type: `string`):

Which portal list to read (the portal's 'Show Me' selector).

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

Keep solicitations whose title, type or category contains ANY of these (case-insensitive).

## `departments` (type: `array`):

Keep only these departments (substring match, e.g. 'Transportation', 'CDPHE').

## `documentCodes` (type: `array`):

Keep only these document codes, e.g. RFP, IFB1, DQ1, RFI, RFQ.

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

Stop after this many results. You pay per solicitation, so this caps cost.

## `requestDelaySecs` (type: `number`):

Politeness delay between requests to the state portal. Minimum 1 s, so at most about 1 request per second.

## `includeNotices` (type: `boolean`):

Some portals also list public notices you can't bid on, e.g. Colorado's Notice of Contractor Settlement (NCS1) and Sole Source notices (NPSS1). By default they are skipped. If you turn this on they are added to the dataset FREE of charge, with isBidOpportunity = false.

## Actor input object example

```json
{
  "states": [
    "CO",
    "ME"
  ],
  "listType": "open",
  "keywords": [],
  "departments": [],
  "documentCodes": [],
  "maxItems": 200,
  "requestDelaySecs": 1,
  "includeNotices": false
}
```

# Actor output Schema

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

Dataset items. Field types are in the dataset schema.

## `runSummary` (type: `string`):

JSON: items pushed, request success rate, stop reason, charged events.

# 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 = {
    "states": [
        "CO",
        "ME"
    ],
    "maxItems": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("civitab/cgi-vss-solicitations").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 = {
    "states": [
        "CO",
        "ME",
    ],
    "maxItems": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("civitab/cgi-vss-solicitations").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 '{
  "states": [
    "CO",
    "ME"
  ],
  "maxItems": 200
}' |
apify call civitab/cgi-vss-solicitations --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,civitab/cgi-vss-solicitations"
        }
    }
}
```

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/exWGDOnN9PHA4kPlE/builds/bzUmBhaCcSptHbx69/openapi.json
