Malaysia Statutory Rates
Malaysian statutory rate data — EPF, SOCSO, EIS, PCB, minimum wage, HRDF, public holidays.
Data only, no calculation engine.
Install
pip install malaysia-statutory-rates
For scraping:
pip install malaysia-statutory-rates[scraper]
Quick Start
Python
from malaysia_statutory_rates import load_rates
rates = load_rates()
# EPF rates
epf = rates["epf_rates"]
employee_rate = epf["rates"]["malaysian_pr_nonmy_before_aug98_below_60"]["employee"]["rate"] # 0.11
employer_rate = epf["rates"]["malaysian_pr_nonmy_before_aug98_below_60"]["employer"]["wage_lte_5000"]["rate"] # 0.13
# Minimum wage
mw = rates["minimum_wage"]
min_salary = mw["rates"]["nationwide"]["monthly"] # 1700
# SOCSO wage ceiling
socso = rates["socso_rates"]
ceiling = socso["wage_ceiling"] # 6000
# Public holidays
holidays = rates["public_holidays"]
national = [h for h in holidays["holidays"] if h.get("national")]
CLI
malaysia-statutory-rates show
malaysia-statutory-rates show epf
malaysia-statutory-rates show holidays
malaysia-statutory-rates scrape --all
Data Files
| File | Source | Content |
|---|---|---|
data/epf_rates.json |
kwsp.gov.my | EPF contribution rates by citizenship, age, wage bracket |
data/socso_rates.json |
perkeso.gov.my + booklet PDF | SOCSO metadata + 65-bracket rate table (2 schedules) |
data/eis_rates.json |
perkeso.gov.my + booklet PDF | EIS metadata + 65-bracket rate table |
data/pcb_table.json |
LHDN e-CP39 | PCB/MTD tax brackets and reliefs |
data/minimum_wage.json |
gajiminimum.mohr.gov.my | Minimum wage (monthly + hourly) |
data/hrdf_rates.json |
hrdcorp.gov.my | HRDF levy rates and formula |
data/public_holidays.json |
publicholidays.com.my | National + state public holidays |
data/foreign_worker_rates.json |
Derived | EPF/SOCSO/EIS rates for foreign workers |
Scraping
Scrapers fetch data from government websites. httpx is used first; blocked sites (kwsp.gov.my, hrdcorp.gov.my) fall back to Firecrawl.
Setup
pip install malaysia-statutory-rates[scraper]
cp .env.example .env # add Firecrawl API key if needed
Run
malaysia-statutory-rates scrape --all
from malaysia_statutory_rates.scrapers import run_scrapers
results = run_scrapers() # {"epf_rates": True, "minimum_wage": False, ...}
How it works
- Checks local cache (
.cache/fetch/) — returns if < 24h old - Checks
robots.txt— skips if disallowed - Tries httpx first (no API cost)
- Falls back to Firecrawl on 403/429 or JS-only pages (1 credit)
- Caches responses for 24 hours
- Writes to
data/*.jsonwith_metadata(scraped_at, source) - Change detection — only writes if data changed
Sources
| Source | Method | Notes |
|---|---|---|
| kwsp.gov.my (EPF) | Firecrawl fallback | Returns 403 to httpx |
| perkeso.gov.my (SOCSO/EIS) | httpx + PDF parse | Metadata from HTML; rate tables from booklet PDF |
| gajiminimum.mohr.gov.my | httpx | Minimum wage gazette |
| hrdcorp.gov.my (HRDF) | Firecrawl fallback | JS SPA — httpx gets empty shell |
| publicholidays.com.my | httpx | Third-party, scrapes table |
| LHDN (PCB) | Manual | e-CP39 requires login |
Scraper Status
| Scraper | Status | Data Source |
|---|---|---|
minimum_wage.py |
Done | HTML |
hrdf.py |
Done | Firecrawl HTML |
holidays.py |
Done | HTML |
epf.py |
Done | HTML |
socso.py |
Done | HTML + PDF |
eis.py |
Done | HTML + PDF |
pcb.py |
Done | PDF download + metadata (data manually verified against LHDN spec) |
foreign_worker_rates.json |
Done | Derived from EPF/SOCSO/EIS |
PDF Parsing
SOCSO and EIS rate tables (65 wage brackets each) are parsed from the PERKESO 2025 Booklet using pymupdf. Pages 36–39 for Act 4, 52–55 for Act 800.
Disclaimer
Data scraped from official government websites. Verify rates against official sources before making payroll or tax decisions.
License
MIT
Metadata
Release files for malaysia-statutory-rates 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| malaysia_statutory_rates-0.1.1.tar.gz | 457.1 kB | Without provenance | Details for malaysia_statutory_rates-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| malaysia_statutory_rates-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for malaysia_statutory_rates-0.1.1-py3-none-any.whl |
Total release size: 526.2 kB
Release files / malaysia_statutory_rates-0.1.1.tar.gz
| Download URL | malaysia_statutory_rates-0.1.1.tar.gz |
|---|---|
| Size | 457.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
00f1226775025dd0143b31e79156a2c0b5edfa34f2ab4801a9fc5bf6fc13853d
|
|
BLAKE2b-256 checksum How to use checksums |
3dce79724190675e80e74b2fcec1362a276c5aee74707ada4d8982fc1d81837a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.3
|
Release files / malaysia_statutory_rates-0.1.1-py3-none-any.whl
| Download URL | malaysia_statutory_rates-0.1.1-py3-none-any.whl |
|---|---|
| Size | 69.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
772fa2a0096fb057966cc83c7a8a0c9e7f0923c0f7a78818ed0027cce885e7d4
|
|
BLAKE2b-256 checksum How to use checksums |
dccfc0e682018f6b957a9b16bd875cb8a5eced450d60236a62797b1544b6153f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.3
|
Security for malaysia-statutory-rates 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.