South Africa Government Supplier Tracker avatar

South Africa Government Supplier Tracker

Pricing

from $5.00 / 1,000 results

Go to Apify Store
South Africa Government Supplier Tracker

South Africa Government Supplier Tracker

Which suppliers win South African government tenders: eTenders awards grouped by supplier, with buyers, signed contract values and official links.

Pricing

from $5.00 / 1,000 results

Rating

0.0

(0)

Developer

Mastazee Data Lab

Mastazee Data Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 days ago

Last modified

Categories

Security

Limited permissions

Share

See which companies win South African government tenders, how often, from which buyers, and for how much. This Actor reads National Treasury's official eTenders open-data API and groups the awards by winning supplier. You get one row per supplier with their award count, the total value of their signed contracts, their main buyers and categories, and a link to every official award record.

Use it to:

  • Watch competitors. Follow named rivals (by name or eTenders supplier id) and get a row whenever they win something new.
  • Find partners and subcontractors. See who keeps winning security, cleaning, IT or construction work in your province.
  • Size a market. Count awards and known contract values per supplier for a buyer or category.

Tested on 26 October 2026 against the live eTenders API:

  • Default input: 500 tenders scanned in about a minute, 38 suppliers from 39 awards (217 tenders skipped by the eTenders server error described below).
  • Monitor mode: a second run of the same monitor straight after the first returned 0 suppliers, repeating nothing.
  • On the Apify platform: the same default run took about 1.5 minutes, and a repeat run of a monitor again returned 0 suppliers.

This is a data tool, not a lead guarantee. Coverage is what buyers publish on eTenders (see Data limitations).

Example input

{
"supplierNames": ["security"],
"provinces": ["KwaZulu-Natal"],
"toOcid": 0,
"recordsToScan": 15000,
"onlyNewAwards": true,
"stateKey": "kzn-security"
}

Leave every filter empty to see all suppliers in the scanned range. Schedule this weekly with onlyNewAwards on, and each run returns only suppliers with awards you haven't received yet. Monitors with different filters keep separate memories, even under the same stateKey.

Example output (one supplier, trimmed)

{
"supplier_key": "id:1442842",
"supplier_name": "QEDANATION",
"supplier_id": "1442842",
"name_variants": ["QEDANATION"],
"other_ids_with_same_name": [],
"award_count": 2,
"awards_with_known_value": 0,
"awards_with_unknown_value": 2,
"total_contract_value_zar": null,
"first_tender_published_date": "2026-03-06",
"buyers": [{"name": "Ingquza Hill Local Municipality", "awards": 2}],
"categories": [{"name": "goods", "awards": 2}],
"awards": [
{"ocid": "ocds-9t57fa-150000", "award_id": "66010", "buyer_name": "Ingquza Hill Local Municipality",
"tender_title": "PROCUREMENT OF STATIONERY", "contract_value_zar": null,
"source_url": "https://ocds-api.etenders.gov.za/api/OCDSReleases/release/ocds-9t57fa-150000"}
]
}

Fields

FieldMeaning
supplier_keyid:<eTenders supplier id>, or name:<normalised name> when eTenders gives no id
supplier_name, name_variantsThe most common spelling and every spelling seen
other_ids_with_same_nameOther eTenders supplier ids using the same name. These are not merged (see below)
award_countAwards in the scanned range. Separate awards in one tender count separately
awards_with_known_value, awards_with_unknown_valueHow many awards have a signed contract value
total_contract_value_zar, largest_contract_value_zarSum and maximum of known contract values only. null when none is known
first_/last_contract_signed_dateEarliest and latest contract signing date (eTenders has no award date)
first_/last_tender_published_dateWhen the related tenders opened
buyers, categories, buyer_provincesCounts of awards per buyer, category and province
enterprise_sizesEME / QSE / GEN as recorded by eTenders
awardsEach award with its official source_url (turn off with includeAwardList)

How suppliers are matched (conservatively)

  • Awards are grouped by eTenders' own supplier id, which stays the same across a company's awards.
  • Different ids are never merged, even if the names match. You'll see them listed in other_ids_with_same_name and can decide for yourself.
  • Awards without a supplier id are grouped by name, separately from any id-based group.
  • Only case, spaces and punctuation are ignored when comparing names. "ACME" and "ACME (PTY) LTD" stay separate suppliers.

Data source and attribution

eTenders OCDS API, published by National Treasury (South Africa) under the Open Data Commons PDDL. Every award links to its official record, as the eTenders publication policy asks. No API key is needed.

Data limitations (please read)

  • About 25–45% of eTenders records can't be read. The official API returns a server error for them (217 of 500 in the default range, 50 of the newest 200 on 26 October 2026). They're skipped and counted in the run's RUN_SUMMARY; re-running the range picks them up if Treasury fixes them.
  • Values come only from signed contracts. eTenders' own award amounts are published with the decimal point dropped (10× or 100× too high), so they're never used. About a third of awards have a contract value. The rest are counted as unknown.
  • There's no award date. Contract signing date and tender publication date are given instead.
  • Province comes from the buyer's name (provincial departments and the big metros). National departments and most municipalities have none.
  • Coverage: eTenders covers national and provincial government plus the municipalities and state entities that choose to publish there. It isn't every public contract in South Africa.
  • Personal contact details are never output. eTenders attaches officials' names, phones and emails to awards.

Running time

The Actor checks tender numbers one by one (about 110 new tenders a day), roughly 8–10 a second at the default 4 parallel requests. Measured on 26 October 2026:

ScanTimeSuppliers
500 tenders (default, May 2026)~1 min38
Newest ~800 tenders (about a week)~1.5 min~125
15,000 tenders (~4–5 months)~25–30 min (estimated)roughly 800–2,000 (estimated)

Pricing

Pay per event: $5.00 per 1,000 supplier rows ($0.005 per supplier), plus Apify's standard tiny start fee. Each row is one supplier with all its awards in the scanned range, and you are charged only for rows written to your dataset.

How you use itSupplier rowsYou pay (approx.)
Default run (500 tenders)~38~$0.19
Weekly run over the newest ~800 tenders, no filter, for a month~550~$2.75 a month
Weekly watch list of a few named competitors0–a few a weekcents a month
  • No double billing in monitor mode: with onlyNewAwards, an award is delivered once. A supplier comes back only when it has an award you haven't received.
  • Spending limits: if you set a maximum cost per run, the Actor stops cleanly when it's reached. Suppliers it didn't deliver come back on the next monitor run.
  • Overlapping runs: if a scheduled run starts while the previous run of the same monitor is still going, it stops at once without output or charges.

Troubleshooting

  • Few rows? Many awards are added weeks or months after a tender opens. To catch them, scan more tenders (15,000 is about 4–5 months) or start from an older number.
  • Many "skipped" tenders in the summary: that's the eTenders server error described above, not a fault in the Actor.
  • Run failed with "could not be reached": the eTenders API is down. Try again later.
  • "Only new awards" returned nothing: everything in the range was already delivered to this monitor. Use a new stateKey to start over.
  • Summary says status: skipped: another run of the same monitor was still in progress, so this one stopped without output or charges.

Known restrictions

  • Up to 50,000 tenders per run, and up to 8 parallel requests, to stay polite to a government server.
  • onlyNewAwards remembers up to 200,000 awards per monitor.
  • Up to 36,000 seconds of scanning per run (maxRuntimeSeconds, default 3,300).
  • A run that hits maxRuntimeSeconds outputs what it found. Its summary says status: partial and gives the lowest tender number reached.