How to Display Live South African Tender Awards on Your Website
The Tenders-SA Winners Feed widget lets you embed a live feed of recently awarded government tenders on any website. This guide covers the architecture, embed methods, configuration options, and links to the open-source repository.
Why Display Live Tender Award Data?
Every week, South African government departments publish tender awards running into billions of rand. For suppliers, industry analysts, and procurement professionals, tracking who won which contract is essential market intelligence. But keeping up with this data is difficult — awards are scattered across different portals, PDF notices, and press releases.
The Winners Feed widget (github.com/Tenders-SA/widget-winners-feed) solves this by providing an embeddable, auto-updating feed of the most recent tender awards. It is an open-source, zero-dependency JavaScript widget that you can add to any website with a single HTML snippet. This post walks through how the widget works, how to embed it, and how to customise it.
Beyond keeping a business's own site current, an embeddable winners feed changes how visitors perceive the site hosting it. A procurement consultancy that shows a live feed of real government awards signals that it is plugged into the market, not just publishing static advice. A trade association that surfaces award activity for its sector gives members a reason to check back regularly rather than treating the association's website as a one-time reference.
What Data Does the Widget Display?
The widget fetches the 100 most recent awarded tenders from the /api/widgets/winners-feed endpoint and renders them in a scrollable list. Each award entry shows:
| Field | Type | Description |
|---|---|---|
| supplierName | string | The winning supplier or contractor |
| amount | number | Awarded contract value in ZAR |
| date | string | Date the award was published |
| orgName | string | Government department or municipality that issued the tender |
| province | string | Province where the contract is managed |
Values are formatted using compact number notation (R 1.5M, R 250K) for readability. The list is sorted by award date, most recent first, and capped at 100 entries to keep the widget lightweight.
The combination of supplier name, amount, organisation, and province in a single scrollable list means a visitor does not need to click through to individual award pages just to get a sense of who is winning work and where. For someone scanning the feed on a competitor-tracking page, this at-a-glance format is often enough to spot a pattern — for example, noticing that a particular supplier has picked up several awards from the same municipality in a short period.
Architecture: How the Widget Works
The widget is a vanilla TypeScript class compiled to a self-contained JavaScript bundle via tsup. It has no external dependencies — no jQuery, no React, no framework required. The core architecture follows three layers:
- Data layer (
api.ts) — AfetchWinnersFeed()function that calls the API endpoint with anAbortSignalfor cancellable requests. The API base URL defaults tohttps://tenders-sa.orgbut can be overridden. - Rendering layer (
renderer.ts) — A DOM-based renderer that builds the widget tree node by node. It injects styles into the document head (deduplicated by ID) and constructs the widget skeleton — header with branded dot indicator, scrollable award list, and a footer CTA. - Widget class (
index.ts) — TheWinnersFeedWidgetclass orchestrates the lifecycle: constructor (reads data attributes and config),render()(shows loading state, fetches data, delegates to renderer), anddestroy()(cancels in-flight requests and clears the DOM).
The widget also includes an auto-initialisation function that scans the DOM for [data-tendersa-winners-feed] elements and instantiates a WinnersFeedWidget for each. This runs on DOMContentLoaded (or immediately if the DOM is already ready), which is how the script-tag embed method works without any JavaScript setup.
This separation of data-fetching, rendering, and lifecycle management is a pattern repeated across every Tenders-SA widget, and it is a deliberate design choice rather than an accident. It means a contributor fixing a rendering bug never needs to touch the fetch logic, and a contributor adjusting the API integration never needs to understand the DOM construction code. For a website owner embedding the widget, none of this internal structure is visible — but it is the reason the widget can be updated and improved over time without breaking the simple script-tag embed that most users rely on.
Embed Methods
There are two ways to embed the widget, depending on whether you want a simple script-tag approach or programmatic control.
Method 1: HTML Data Attribute (Recommended)
Add a div with the data-tendersa-winners-feed attribute and include the script. That is all you need.
1<!-- Place the container where you want the feed to appear --> 2<div data-tendersa-winners-feed data-theme="light"></div> 3 4<!-- Include the widget script (async recommended) --> 5<script 6 src="https://unpkg.com/@tenders-sa-org/widget-winners-feed@latest/dist/widget-winners-feed.global.js" 7 async 8></script>HTML
The widget auto-initialises when the script loads. The optional data-theme attribute switches between light and dark themes. If omitted, the widget respects the user's prefers-color-scheme media query.
Method 2: Programmatic (NPM / Bundler)
Install the package via npm for use in a JavaScript build pipeline:
1npm install @tenders-sa-org/widget-winners-feedBASH
Then instantiate the widget programmatically:
1import { WinnersFeedWidget } from '@tenders-sa-org/widget-winners-feed' 2 3const container = document.getElementById('my-widget-container') 4const widget = new WinnersFeedWidget(container, { 5 theme: 'dark', 6}) 7 8widget.render().then(() => { 9 console.log('Winners feed rendered') 10}) 11 12// Clean up when no longer needed (e.g. in a SPA navigation) 13// widget.destroy()JAVASCRIPT
The programmatic method is the right choice if you are building a single-page application (React, Vue, Svelte, etc.) and need to control the widget lifecycle manually. Call destroy() in your component's cleanup phase to cancel pending network requests and remove DOM nodes.
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
| theme | 'light' | 'dark' | System preference |
| apiBase | string | 'https://tenders-sa.org' | Base URL for the API endpoint (useful for self-hosted deployments) |
When using the data-attribute method, set data-theme="dark" on the container element. When using the programmatic method, pass the options in the constructor's second argument.
A Practical Walkthrough
Picture a regional business directory that lists suppliers across the security services sector. Adding the Winners Feed widget to the directory's homepage with a single div data-tendersa-winners-feed tag gives visitors a live sense of activity in government procurement without the directory having to build or maintain its own data pipeline. Because the widget auto-initialises and fetches fresh data on every page load, the directory's operator never has to remember to update it manually — it stays current automatically.
For a supplier-facing SaaS product that already has its own dashboard, the programmatic embed is usually the better fit. A product team could mount the WinnersFeedWidget inside a "market activity" panel of their own application, matching their existing colour scheme via the theme option, and call destroy() whenever the panel is closed or the user navigates away, keeping the host application's memory footprint clean.
Browser Support and Performance
The widget uses standard DOM APIs (document.querySelectorAll, fetch, AbortController, DOMContentLoaded) and ES2015+ features. It supports all modern browsers — Chrome, Firefox, Safari, and Edge. Internet Explorer is not supported.
Performance characteristics:
- Bundle size: approximately 6 KB (minified and gzipped)
- API response time: typically under 200 ms server-side (the endpoint uses ISR with 3600-second revalidation)
- Render time: under 50 ms on desktop after data is received
- No layout shift: the container element reserves space; the loading state displays immediately
The Open Source Package
The Winners Feed widget is published as @tenders-sa-org/widget-winners-feed on npm and is open source under the MIT license. The source code is available at github.com/Tenders-SA/widget-winners-feed.
The repository includes:
- Full TypeScript source with type definitions exported
- Unit tests via Vitest
- Build pipeline via tsup (outputs ESM, CJS, and IIFE bundles)
- Comprehensive README with embed examples
- Issues and pull requests welcome
If you are interested in the underlying platform API, the endpoint /api/widgets/winners-feed returns a JSON array of recent awards and is also accessible independently (CORS-enabled with Access-Control-Allow-Origin: *).
Getting Started
To add the winners feed to your site:
- Add a
<div data-tendersa-winners-feed></div>element to your HTML where you want the feed to appear. - Include the script tag pointing to the unpkg CDN (or host the file yourself from the dist directory).
- Optionally add
data-theme="dark"if your site uses a dark colour scheme. - That is it — the widget auto-initialises on page load.
The source code and documentation are on GitHub at github.com/Tenders-SA/widget-winners-feed. Issues, feature requests, and pull requests are welcome. If you are building on top of SA procurement data, you may also find the Tenders-SA JavaScript SDK useful for accessing the full Developer API.
Tags
Based on this article's topics, here are some current tenders that might interest you
PROVISION OF COMPLETE ELECTRICAL/ELECTRONICS ENGINEERING PROFESSIONAL SERVICES FOR THE DEVELOPMENT OF THE INFORMATION, COMMUNICATION AND TECHNOLOGY(ICT) INFRASTRUCTURE FOR THE MMSEZ NORTH SITE PHASE 1I
PROVISION OF COMPLETE ELECTRICAL/ELECTRONICS ENGINEERING PROFESSIONAL SERVICES FOR THE DEVELOPMENT OF THE INFORMATION, COMMUNICATION AND TECHNOLOGY(ICT) INFRASTRUCTURE FOR THE MMSEZ NORTH SITE PHASE 1I
This Request for Information (RFI) invites qualified vendors, advisors and technology providers to submit information on tools, models, workflows and enablement services required to close these identified gaps and integrate with the existing Enerweb ETRM, phased across Day-1 go-live (Phase 1), controlled expansion (Phase 2, Year 1–2) and a mature state (Phase 3, Year 3+).
Feasibility Study on Hydrogen-Powered Mining Equipment Conversion using Hydrogen Combustion Technology for Surface and Underground Mining.
VIRTUALIZATION TECHNOLOGY REQUIREMENTS AND CAPABILITIES FOR SABC
REQUEST FOR INFORMATION: CLOUD-HOSTED OBSERVABILITY SOLUTION FOR THE ROAD ACCIDENT FUND (RAF) TO SUPPORT ENTERPRISE-WIDE MONITORING, ANALYTICS AND OPERATIONAL INTELLIGENCE ACROSS ITS HYBRID TECHNOLOGY ENVIRONMENT
Want to see all available tenders?
Browse All Tenders →Share this article
How to Display Live South African Tender Awards on Your Website
The Tenders-SA Winners Feed widget lets you embed a live feed of recently awarded government tenders on any website. This guide covers the architecture, embed methods, configuration options, and links to the open-source repository.