Kenya PPIP Tender Scraper
Pricing
from $1.00 / 1,000 tenders
Kenya PPIP Tender Scraper
Extract Kenyan public tenders and contract awards from the Public Procurement Information Portal (tenders.go.ke): active, closed, AGPO and terminated tenders, procuring entity, dates, documents, awarded supplier and contract amount.
Pricing
from $1.00 / 1,000 tenders
Rating
5.0
(1)
Developer
Public Money
Maintained by ApifyActor stats
1
Bookmarked
1
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
This Actor reads Kenya's Public Procurement Information Portal (PPIP, tenders.go.ke): active, closed, AGPO and terminated tender notices, and published contract awards. It reads the portal's own JSON API, filters on the server, walks the pages, and returns one record per tender or award with every procurement field the API publishes (personal data of private individuals is removed, see Gotchas).
Source
| Mode | Portal list | Records on 2026-10-04 |
|---|---|---|
active | Active Tenders | 546 |
closed | Closed Tenders | 144,283 |
agpo | AGPO Tenders (the portal's AGPO groups: women, youth, people with disabilities) | 148 |
terminated | Terminated Tenders | 5,780 |
all | All tenders | 144,672 |
awards | Published contract awards | 144,410 |
The portal's "Restricted Tenders" list answered with zero records on 2026-10-04 and is not offered.
Input
| Field | Modes | Sent to the portal as | Verified 2026-10-04 |
|---|---|---|---|
mode | all | which list is read | see table above |
title | all | title / tender:title (substring) | supply 167 of 546 active; SANITARY 551 awards |
tenderRef | all | tender_ref / tender:tender_ref | AWD/AWARD 10 active; JUD/ELRAV 8 awards |
procuringEntity | all | pe:name | AWENDO 10 active; Judiciary 1,123 awards |
procurementMethod | all | procurementMethod:title | Open Tender 443 active; 34,754 awards |
procurementCategory | all | procurementCategory:title | Works 281 active; 48,246 awards |
financialYear | all | financialYear:name | 2025/2026 19,758 closed; 10,974 awards |
publishedDate | tender modes | published_at (substring of YYYY-MM-DD hh:mm:ss) | 2026-09 377 active |
closingDate | tender modes | close_at | 2026-10-05 40 active |
supplierName | awards | supplier:name | NASACHE 5 |
contractNumber | awards | contract_number | PO 26/27 3 |
awardDate | awards | award_date | 2026-09 32 |
maxItems | all | — | caps records returned; 0 returns everything |
schemaOrg | all | — | appends a schema.org block, charged once per run |
Every filter returned zero records for a nonsense value. Each is matched by the portal as a substring. A tender-only filter given with awards, or an awards-only filter given with a tender mode, stops the run with an error rather than returning the unfiltered list.
{"mode": "awards","procuringEntity": "Judiciary","financialYear": "2025/2026","maxItems": 500}
Output
Every record is the portal's own JSON, field names unchanged, with these added at the top level:
| Field | Meaning |
|---|---|
recordType | tender or award |
mode | the list it was read from |
procuringEntity | pe.name |
tenderTitle, tenderRef, supplierName | awards only: tender.title, tender.tender_ref, supplier.name |
tenderUrl | https://tenders.go.ke/tenders/<tender id>, the portal's own tender page |
documentUrls | absolute links to every document listed for the tender |
scrapedAt | when the record was read |
Tender records carry id, ocid, tender_ref, title, published_at, close_at, opening_date, tender_fee, venue, validity_in_days, the nested pe (procuring entity with type, contacts and pin), procurement_method, procurement_category, financial_year, submission_methods, documents, addenda, bidders (bidder name, tender sum, bid security, evaluation results), team_members, contracts, agpo_groups and branch.
Award records carry id, contract_number, amount, award_date, notification_of_award_date, sign_date, start_date, end_date, agpo_certificate_number, the nested supplier (company, pin_number, bus_reg_number, tcc_number, directors), owners (beneficial owners), tender (with its documents), pe, financial_year, variation and termination.
{"recordType": "award","mode": "awards","id": 169562,"contract_number": "PO 26/27-002374","tender_id": 307384,"amount": 55720,"award_date": "2026-09-22","procuringEntity": "The Judiciary","tenderTitle": "SUPPLY OF SANITARY MATERIALS","tenderRef": "JUD/ELRAV/1Q/2/2026/2027","supplierName": "NASACHE DISTRIBUTIONS","tenderUrl": "https://tenders.go.ke/tenders/307384"}
Gotchas
- Fields fill in as a tender progresses. On an active tender
bidders,team_members,contracts,opening_dateand the evaluation dates are empty because nothing has happened yet; they are populated on closed and terminated tenders. - Personal data is removed. The API also embeds private individuals' details next to the procurement record. The Actor drops the
subscriberslist (members of the public who signed up for updates), national ID numbers and dates of birth of directors and owners, staff personnel numbers, account tokens, the personal e-mail and phone of evaluation committee members, and reducescreated_byto the account id and name. - Rate limit. The API allows 60 requests a minute per IP and answers
429past it. The Actor paces its requests to one every 1.1 s and waits outRetry-After; a fullclosedwalk is about 1,443 pages of 100. - Keyword search does not exist. The site sends a
searchparameter, but every list ignores it, so it is not offered; usetitle. - Amounts are in Kenyan shillings (KES), as the portal publishes them.