The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Indonesia Civic Stack listing page.
Production-ready scrapers, normalizers, and API wrappers for Indonesian government data sources.
The infrastructure layer beneath halalkah.id, legalkah.id, and a public good for the Indonesian civic tech and developer community.
Indonesian public data is nominally open but practically inaccessible. Every developer building civic tooling re-solves the same scraping problems independently: BPOM product registrations, BPJPH halal certificates, AHU company records. Scrapers bit-rot within months as portals change. There is no shared, maintained layer.
This repo is that layer. One pip install to query Indonesian government portals — no more bespoke scrapers.
This SDK is designed for both humans and AI agents:
CivicStackResponse envelope, never raw dicts| Module | Source | Data | Proxy | Status |
|---|---|---|---|---|
bpom | cekbpom.pom.go.id | Food, drug, cosmetic registrations | 🌐 | ✅ Active |
bpjph | cmsbl.halal.go.id | Halal certificates (1.98M+ records) | 🌐 | ✅ Active — migrated to REST API (v1.0.0) |
ahu | ahu.go.id | Company registry — PT, CV, Yayasan, Koperasi | 🇮🇩 | ⚠️ Page restructured — search input changed (Apr 2026) |
ojk | www.ojk.go.id/waspada-investasi | Licensed financial institutions + Waspada list | 🇮🇩 | ⚠️ Portal migrated to SharePoint (Apr 2026) — scraper needs rewrite |
oss_nib | oss.go.id | Business identity (NIB) | 🇮🇩 | ⚠️ Page restructured — Playwright can't find inputs (Apr 2026) |
lpse | spse.inaproc.id | Government procurement | 🇮🇩 | ✅ Active — un-deprecated (v1.0.0) |
kpu | infopemilu.kpu.go.id | Election data — candidates, results, finance | 🌐 | ✅ Active |
bps | webapi.bps.go.id | Statistical datasets (1,000+) | 🌐 | ✅ Active (requires BPS_API_KEY) |
bmkg | data.bmkg.go.id | Weather, earthquake, and disaster data | 🌐 | ✅ Active |
simbg | simbg.pu.go.id | Building permits (PBG) — multi-portal | 🌐 | ✅ Active |
jdih | peraturan.go.id | National legal database — UU, PP, Perpres, Permen | 🇮🇩 | ✅ New — Playwright scraping |
ksei | web.ksei.co.id | Securities statistics (62 monthly PDFs) + registered securities | 🌐 | ✅ New — HTML scraping (no proxy needed) |
djpb | data-apbn.kemenkeu.go.id | APBN budget themes — target/realization/achievement | 🇮🇩 | ✅ New — clean REST JSON API |
lhkpn | elhkpn.kpk.go.id | Wealth declarations (officials) | — | ✅ Active — reCAPTCHA v3 solved via Playwright |
🌐 = works globally 🇮🇩 = requires Indonesian proxy (set PROXY_URL)
Every module returns the same CivicStackResponse envelope — swap data sources without touching application logic.
| Module | Scraper | Normalizer | MCP | Tests | Portal Status |
|---|---|---|---|---|---|
| bpom | ✅ | ✅ | ✅ | ✅ | ✅ |
| bpjph | ✅ | ✅ | ✅ | ✅ | ✅ REST API |
| ahu | ✅ | ✅ | ✅ | ✅ | ⚠️ page restructured |
| ojk | ✅ | ✅ | ✅ | ✅ | ⚠️ SharePoint migration |
| oss_nib | ✅ | ✅ | ✅ | ✅ | ⚠️ page restructured |
| lpse | ✅ | ✅ | ✅ | ✅ | 🇮🇩 geo-blocked |
| kpu | ✅ | ✅ | ✅ | ✅ | ✅ |
| bps | ✅ | ✅ | ✅ | ✅ | ✅ |
| bmkg | ✅ | ✅ | ✅ | ✅ | ✅ |
| simbg | ✅ | ✅ | ✅ | ✅ | ✅ |
| jdih | ✅ | ✅ | ❌ | ❌ | 🇮🇩 Playwright |
| ksei | ✅ | ✅ | ❌ | ❌ | ✅ (no proxy needed) |
| djpb | ✅ | ✅ | ❌ | ❌ | ✅ REST JSON API |
| lhkpn | ✅ | ✅ | ✅ | ✅ | ✅ Active (Playwright) |
All 14 modules expose 46 MCP tools for use with Claude, GPT, or any MCP-compatible agent.
MCP server classes support two init styles:
Every module returns CivicStackResponse:
Status values: ACTIVE, EXPIRED, SUSPENDED, REVOKED, NOT_FOUND, ERROR.
When a module can't reach its portal or is missing configuration (e.g., BPS_API_KEY), it returns an error envelope instead of crashing:
The shared/ layer provides:
schema.py — CivicStackResponse Pydantic model, status enum, helper constructorshttp.py — civic_client() factory with auto-proxy, rate limiter, exponential backoff retry, URL rewriting for CF Worker proxiesmcp.py — CivicStackMCPBase abstract base class for MCP serversMost Indonesian government portals (*.go.id) restrict access to Indonesian IP addresses. If deploying outside Indonesia, you must set PROXY_URL to route requests through an Indonesian endpoint.
Without a proxy, expect: DNS resolution failures, connection timeouts, or HTTP 403/404 responses from most modules.
The SDK auto-reads PROXY_URL from environment — no code changes needed in scrapers or MCP servers.
| Mode | PROXY_URL example | How it works |
|---|---|---|
connect | socks5://id-proxy:1080 | Standard HTTP/SOCKS CONNECT proxy via httpx transport |
rewrite | https://x.workers.dev | Rewrites URLs to ?url=<target> (auto-detected for *.workers.dev) |
none | (unset) | Direct connection |
Override auto-detection with PROXY_MODE=connect|rewrite.
A ready-to-deploy CF Worker proxy is included in proxy/. Deploy with:
⚠️ CF Worker limitation: Many
.go.idportals are themselves behind Cloudflare. CF Workers makingfetch()calls to other CF-protected origins receive 403/522 errors. This is a known Cloudflare limitation.
Verified through CF Worker proxy:
| Portal | Status | Notes |
|---|---|---|
| data.bmkg.go.id | ✅ Works | JSON API, not behind CF |
| cekbpom.pom.go.id | ❌ 403/522 | Portal is CF-protected |
| api.ojk.go.id | ❌ DNS dead | NXDOMAIN since March 2026 |
| infopemilu.kpu.go.id | ❌ 403 | CF-protected |
| lpse.*.go.id | ❌ 403 | CF-protected |
| elhkpn.kpk.go.id | ✅ 200 | reCAPTCHA v3 solved via Playwright headless browser |
For production with CF-protected portals, use an Indonesian VPS with a SOCKS5/HTTP proxy and set PROXY_MODE=connect.
Tested from three locations to map which portals enforce geo-blocking vs WAF:
| Portal | Sydney (AU) | Singapore | Jakarta (ID) | Verdict |
|---|---|---|---|---|
| ahu.go.id | ❌ | ✅ | ✅ | Geo-blocked (SEA+ OK) |
| elhkpn.kpk.go.id | ❌ | ✅ | ✅ | Geo-blocked (SEA+ OK) |
| ojk.go.id | ❌ 403 | ❌ 403 | ✅ | ID-only |
| jaga.id (KPK) | ✅ | ✅ | ✅ | No restriction |
| data.bmkg.go.id | ✅ | ✅ | ✅ | No restriction |
| cekbpom.pom.go.id | ⚠️ | ⚠️ | ⚠️ | CF-protected (all locations) |
| webapi.bps.go.id | ❌ 403 | ❌ 403 | ❌ 403 | WAF, not geo (needs API key) |
| lpse.lkpp.go.id | ❌ | ❌ | ❌ | Unreliable (all locations) |
| coretaxdjp.pajak.go.id | ❌ | ❌ | ❌ | Unreliable (all locations) |
Takeaway: An Indonesian proxy (e.g., CloudKilat Jakarta) unlocks OJK — the most important geo-restricted portal. Singapore unlocks AHU + LHKPN. BPS and LPSE failures are not geo-related.
⚠️ Never disable password auth and restart sshd in one automated script on a fresh VPS. If the SSH key wasn't copied correctly, you're locked out with no recovery path except a web console. Always: (1) copy key, (2) verify key login works in a separate session, (3) then disable password auth.
Indonesian government portals frequently change their URL structure without notice. Known changes as of March 2026:
| Module | Old URL | New URL | Status |
|---|---|---|---|
| BPOM | /index.php/home/produk/1/{keyword}/... | /all-produk?q={keyword} | ✅ Updated |
| KPU | /Pemilu/caleg/list | /Pemilu/Peserta_pemilu | ✅ Updated |
| BMKG | /DataMKG/MEWS/Warning/cuacasignifikan.json | /DataMKG/TEWS/gempadirasakan.json | ✅ Updated |
| LHKPN | /portal/user/check_search_announ | reCAPTCHA v3 (Playwright) | 🟢 Active |
Modules that fail for 60 days are flagged DEGRADED and may be archived.
Some portals require a real browser (JavaScript rendering, anti-bot protection):
| Module | Browser | Anti-bot |
|---|---|---|
| bpjph | Playwright (Chromium) | Standard |
| ahu | Playwright + Camoufox | Bot management (datacenter IP blocking) |
| oss_nib | Playwright (Chromium) | Standard |
Install browser dependencies:
| Module | Key Required | Env Var | Registration |
|---|---|---|---|
| BPS | Yes | BPS_API_KEY | webapi.bps.go.id/developer/register (free) |
| All others | No | — | — |
Without BPS_API_KEY, the BPS module returns an error envelope (not a crash):
All 11 modules expose 40 MCP tools total:
| Module | Tools | Count |
|---|---|---|
| bpom | check_bpom, search_bpom, get_bpom_status | 3 |
| bpjph | check_halal_cert, lookup_halal_by_product, get_halal_status, cross_reference_halal_bpom | 4 |
| ahu | lookup_company_ahu, get_company_directors, verify_company_status, search_companies_ahu | 4 |
| ojk | check_ojk_license, search_ojk_institutions, get_ojk_status, check_ojk_waspada | 4 |
| oss_nib | lookup_nib, verify_nib, search_oss_businesses | 3 |
| lpse | lookup_vendor_lpse, search_lpse_vendors, search_lpse_tenders, get_lpse_portals | 4 |
| kpu | get_candidate, search_kpu_candidates, get_election_results_kpu, get_campaign_finance_kpu | 4 |
| lhkpn | get_lhkpn, search_lhkpn, compare_lhkpn, get_lhkpn_pdf | 4 |
| bps | search_bps_datasets, get_bps_indicator, list_bps_regions | 3 |
| bmkg | get_bmkg_alerts, get_weather_forecast, get_earthquake_history, get_latest_earthquake | 4 |
| simbg | lookup_building_permit, search_permits_by_area, list_simbg_portals | 3 |
This repo is built for AI agents as first-class consumers.
| File | Purpose | Agent |
|---|---|---|
AGENTS.md | Architecture, patterns, critical rules, gotchas | All coding agents |
CLAUDE.md | Commands, do/don't rules, style guide | Claude Code |
.cursorrules | Project rules for Cursor | Cursor |
.github/copilot-instructions.md | Instructions for Copilot | GitHub Copilot |
CONTRIBUTING.md | Module contract + PR checklist | All |
SKILL.md | Skill discovery (AgentSkills format) | Skill-aware agents |
PROMPTS.md | Example prompts + interactive artifact recipes | All AI agents |
Option A — Self-hosted remote server (deploy your own):
Note: There is no shared hosted server. Each user deploys their own instance to control proxy settings, rate limits, and API keys.
Option B — Local install via pip:
Option C — Clone repo (auto-discovery):
All three options give you the same 40 tools. Then ask:
"Check if BPOM registration MD 123456789 is still active" "Search for companies named 'Maju Bersama' in the AHU registry" "What was the latest earthquake in Indonesia?"
See PROMPTS.md for more example prompts and interactive artifact recipes.
Once MCP tools are connected, try these with your AI agent:
Food Safety "Check if BPOM registration number
MD 123456789is still active" "Search for all paracetamol products registered with BPOM"
Halal Verification "Is product XYZ halal certified? Cross-reference with BPOM registration" "Find all halal certificates issued to PT Indofood"
Company Due Diligence "Look up PT Maju Bersama in the AHU company registry and check who the directors are" "Is this company OJK-licensed? Check both the license registry and the waspada (warning) list"
Public Finance "Search LHKPN wealth declarations for officials in Jakarta" "Find government procurement tenders for road construction on LPSE"
Disaster & Weather "What was the latest earthquake in Indonesia?" "Get the weather forecast for DKI Jakarta from BMKG"
Statistics "Find BPS datasets about poverty rates by province" "Get the inflation indicator for the last 5 years"
Multi-Source Queries "I want to verify a food company: check AHU for registration, OJK for financial license, BPOM for product registrations, and BPJPH for halal certificates" "Compare LHKPN wealth declarations for these two officials over the last 3 reporting periods"
CivicStackResponse with the same fields. Agents don't need module-specific parsing logic.check_<module>, search_<module>, get_<module>_status pattern across all modules.| Feature | Config | Default |
|---|---|---|
| API key auth | CIVIC_API_KEY env var | Disabled (open) |
| Rate limiting | CIVIC_RATE_LIMIT env var | 60 req/min per IP |
| Proxy allowlist | CIVIC_ALLOWED_PROXIES env var | Any non-private IP |
| SSRF prevention | Built-in | Blocks RFC 1918 + localhost |
| Container user | Dockerfile | Non-root (civicapp, uid 1000) |
See CONTRIBUTING.md. Every module PR must include:
fetch() and search() returning CivicStackResponseA module that breaks for 60 days is flagged DEGRADED and archived.
A single-page app that checks if a product is halal-certified. One module, no proxy needed for Indonesian users.
A compliance tool that cross-checks a company across multiple government databases. Runs behind a proxy for overseas deployment.
An AI assistant that answers natural language questions about Indonesian civic data using MCP tools. The agent reasons about which portals to query.
MIT — see LICENSE