Skip to main content
Technology

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.

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:

FieldTypeDescription
supplierNamestringThe winning supplier or contractor
amountnumberAwarded contract value in ZAR
datestringDate the award was published
orgNamestringGovernment department or municipality that issued the tender
provincestringProvince 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.

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) — A fetchWinnersFeed() function that calls the API endpoint with an AbortSignal for cancellable requests. The API base URL defaults to https://tenders-sa.org
    but 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) — The WinnersFeedWidget class orchestrates the lifecycle: constructor (reads data attributes and config), render() (shows loading state, fetches data, delegates to renderer), and destroy() (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.

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/@tendersa/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 @tendersa/widget-winners-feed
BASH

Then instantiate the widget programmatically:

1import { WinnersFeedWidget } from '@tendersa/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

OptionTypeDefaultDescription
theme'light''dark'System preference
apiBasestring'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.

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 @tendersa/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:

  1. Add a <div data-tendersa-winners-feed></div> element to your HTML where you want the feed to appear.
  2. Include the script tag pointing to the unpkg CDN (or host the file yourself from the dist directory).
  3. Optionally add data-theme="dark" if your site uses a dark colour scheme.
  4. 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

WidgetEmbedOpen SourceGovernment TendersJavaScriptWeb Development
AI-Powered Matching
Never Miss a Perfect Tender Again
Our AI analyzes thousands of tenders and finds the ones YOUR company can actually win
AI Match Scoring for every tender
Instant alerts for 85%+ matches
B-BBEE level optimization
Document readiness checks

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.

https://www.tenders-sa.org/blog/embed-winners-feed-widget