npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

osm-kenya-boundaries

v1.0.3

Published

Complete Kenya administrative boundaries data (47 Counties, 290+ Constituencies, 300+ Sub-Counties, 1,450+ Wards) with TypeScript support. Zero dependencies, tree-shakeable, and fully typed.

Readme

OSM Kenya Boundaries 🇰🇪

A comprehensive TypeScript/JavaScript library providing complete administrative boundary data for Kenya, including all 47 Counties, 290+ Constituencies, and 1,450+ Wards.

npm version License: MIT TypeScript GitHub Sponsors

✨ Features

  • Complete Data: All 47 counties, 290+ constituencies, and 1,450+ wards
  • 🎯 TypeScript Support: Full type definitions included
  • 🔍 Search Functions: Easy search and lookup across all administrative levels
  • 📦 Zero Dependencies: Lightweight and fast (< 200KB)
  • 🌳 Tree-shakeable: Import only what you need
  • 📖 Well Documented: Comprehensive examples and API documentation
  • 🗺️ OSM Compatible: Data structure optimized for mapping applications
  • 🚀 Performance: Optimized for fast queries and low memory usage

📦 Installation

npm install osm-kenya-boundaries

Or using yarn:

yarn add osm-kenya-boundaries

Or using pnpm:

pnpm add osm-kenya-boundaries

🚀 Quick Start

import {
  getCounties,
  getCountyByName,
  getConstituenciesByCounty,
  searchWard
} from 'osm-kenya-boundaries';

// Get all counties
const counties = getCounties();
console.log(`Kenya has ${counties.length} counties`);

// Get specific county
const nairobi = getCountyByName('Nairobi');
console.log(nairobi);
// Output: { county_code: 47, county_name: 'Nairobi', constituencies: [...] }

// Get constituencies in a county
const constituencies = getConstituenciesByCounty(47);
console.log(`Nairobi has ${constituencies.length} constituencies`);

// Search for a ward
const results = searchWard('Kilimani');
console.log(results);

📚 API Reference

County Functions

getCounties(): County[]

Returns all 47 counties in Kenya.

const allCounties = getCounties();
console.log(allCounties.length); // 47

getCountyByCode(code: number): County | undefined

Get a county by its numeric code (1-47).

const mombasa = getCountyByCode(1);
const nairobi = getCountyByCode(47);

getCountyByName(name: string): County | undefined

Get a county by name (case-insensitive).

const mombasa = getCountyByName('Mombasa');
const kisumu = getCountyByName('KISUMU'); // Case insensitive
const county = getCountyByName('  Nairobi  '); // Handles whitespace

Constituency Functions

getAllConstituencies(): Array<Constituency & { county_name: string; county_code: number }>

Get all constituencies with their parent county information.

const allConstituencies = getAllConstituencies();
allConstituencies.forEach(c => {
  console.log(`${c.constituency_name} in ${c.county_name}`);
});

getConstituenciesByCounty(countyCode: number): Constituency[]

Get all constituencies in a specific county.

const nairobiConstituencies = getConstituenciesByCounty(47);
const mombasaConstituencies = getConstituenciesByCounty(1);

getConstituencyByName(name: string): SearchResult | undefined

Find a constituency by name and get its parent county.

const result = getConstituencyByName('Westlands');
console.log(result?.county.county_name); // "Nairobi"
console.log(result?.constituency.wards); // ["Kitisuru", "Parklands/Highridge", ...]

Ward Functions

getAllWards(): Array<{ ward: string; constituency: string; county: string }>

Get all wards with their parent constituency and county.

const allWards = getAllWards();
console.log(`Total wards: ${allWards.length}`);

getWardsByConstituency(constituencyName: string): string[]

Get all wards in a specific constituency.

const westlandsWards = getWardsByConstituency('Westlands');
console.log(westlandsWards);
// ["Kitisuru", "Parklands/Highridge", "Karura", "Kangemi", "Mountain View"]

searchWard(wardName: string): SearchResult[]

Search for wards by name. Returns all matches as some ward names may appear in multiple locations.

const results = searchWard('Central');
results.forEach(result => {
  console.log(`${result.ward} in ${result.constituency?.constituency_name}, ${result.county?.county_name}`);
});

Search & Utility Functions

search(query: string): SearchResult[]

Search across all administrative levels (counties, constituencies, and wards).

const results = search('Nairobi');
// Returns matches from counties, constituencies, and wards containing "Nairobi"

validateLocation(county?: string, constituency?: string, ward?: string): boolean

Validate if a location exists in the administrative hierarchy.

// Valid location
const isValid = validateLocation('Nairobi', 'Westlands', 'Kilimani');
console.log(isValid); // true

// Invalid constituency
const isInvalid = validateLocation('Nairobi', 'InvalidConstituency');
console.log(isInvalid); // false

// Partial validation
const countyExists = validateLocation('Mombasa');
console.log(countyExists); // true

getStatistics()

Get statistical information about Kenya's administrative divisions.

const stats = getStatistics();
console.log(stats);
// {
//   counties: 47,
//   constituencies: 290,
//   wards: 1450,
//   avgConstituenciesPerCounty: 6.17,
//   avgWardsPerConstituency: 5.0
// }

🎯 Use Cases

📝 Form Dropdowns (Cascading Selects)

import { getCounties, getConstituenciesByCounty, getWardsByConstituency } from 'osm-kenya-boundaries';

// Populate county dropdown
const countyOptions = getCounties().map(c => ({
  value: c.county_code,
  label: c.county_name
}));

// When county is selected
function onCountyChange(countyCode: number) {
  const constituencies = getConstituenciesByCounty(countyCode);
  // Update constituency dropdown
  return constituencies.map(c => ({
    value: c.constituency_name,
    label: c.constituency_name
  }));
}

// When constituency is selected
function onConstituencyChange(constituencyName: string) {
  const wards = getWardsByConstituency(constituencyName);
  // Update ward dropdown
  return wards.map(w => ({
    value: w,
    label: w
  }));
}

✅ Address Validation

import { validateLocation } from 'osm-kenya-boundaries';

interface KenyanAddress {
  county: string;
  constituency: string;
  ward: string;
  street?: string;
}

function validateKenyanAddress(address: KenyanAddress): boolean {
  const isValid = validateLocation(
    address.county,
    address.constituency,
    address.ward
  );
  
  if (!isValid) {
    throw new Error('Invalid Kenyan administrative location');
  }
  
  return true;
}

// Usage
try {
  validateKenyanAddress({
    county: 'Nairobi',
    constituency: 'Westlands',
    ward: 'Kilimani',
    street: 'Argwings Kodhek Road'
  });
  console.log('Address is valid!');
} catch (error) {
  console.error(error.message);
}

🔍 Search Autocomplete

import { search } from 'osm-kenya-boundaries';

function autocompleteLocation(query: string) {
  if (query.length < 2) return [];
  
  const results = search(query);
  
  return results.map(result => {
    if (result.ward) {
      return {
        label: `${result.ward} Ward, ${result.constituency?.constituency_name}, ${result.county?.county_name}`,
        type: 'ward',
        value: result
      };
    } else if (result.constituency) {
      return {
        label: `${result.constituency.constituency_name} Constituency, ${result.county?.county_name}`,
        type: 'constituency',
        value: result
      };
    } else {
      return {
        label: `${result.county?.county_name} County`,
        type: 'county',
        value: result
      };
    }
  });
}

// Usage
const suggestions = autocompleteLocation('Nai');
console.log(suggestions);

🗺️ Mapping Applications

import { getCounties, getConstituenciesByCounty } from 'osm-kenya-boundaries';
import L from 'leaflet';

// Create a choropleth map
const counties = getCounties();
const map = L.map('map').setView([-1.286389, 36.817223], 6);

counties.forEach(county => {
  const constituencies = county.constituencies;
  console.log(`${county.county_name}: ${constituencies.length} constituencies`);
  
  // Add markers or polygons for each county
  // You would need GeoJSON data for actual boundary rendering
});

⚛️ React Example

import { useState, useEffect } from 'react';
import { 
  getCounties, 
  getConstituenciesByCounty, 
  getWardsByConstituency,
  type County,
  type Constituency 
} from 'osm-kenya-boundaries';

export function LocationSelector() {
  const [selectedCounty, setSelectedCounty] = useState('');
  const [selectedConstituency, setSelectedConstituency] = useState('');
  const [selectedWard, setSelectedWard] = useState('');
  
  const [constituencies, setConstituencies] = useState<Constituency[]>([]);
  const [wards, setWards] = useState<string[]>([]);
  
  const counties = getCounties();

  useEffect(() => {
    if (selectedCounty) {
      const county = counties.find(c => c.county_name === selectedCounty);
      if (county) {
        const consts = getConstituenciesByCounty(county.county_code);
        setConstituencies(consts);
        setSelectedConstituency('');
        setSelectedWard('');
      }
    }
  }, [selectedCounty]);

  useEffect(() => {
    if (selectedConstituency) {
      const wardList = getWardsByConstituency(selectedConstituency);
      setWards(wardList);
      setSelectedWard('');
    }
  }, [selectedConstituency]);

  return (
    <div className="space-y-4">
      <div>
        <label className="block text-sm font-medium mb-1">County</label>
        <select
          value={selectedCounty}
          onChange={(e) => setSelectedCounty(e.target.value)}
          className="w-full border rounded px-3 py-2"
        >
          <option value="">Select County</option>
          {counties.map(county => (
            <option key={county.county_code} value={county.county_name}>
              {county.county_name}
            </option>
          ))}
        </select>
      </div>

      <div>
        <label className="block text-sm font-medium mb-1">Constituency</label>
        <select
          value={selectedConstituency}
          onChange={(e) => setSelectedConstituency(e.target.value)}
          className="w-full border rounded px-3 py-2"
          disabled={!selectedCounty}
        >
          <option value="">Select Constituency</option>
          {constituencies.map(constituency => (
            <option key={constituency.constituency_name} value={constituency.constituency_name}>
              {constituency.constituency_name}
            </option>
          ))}
        </select>
      </div>

      <div>
        <label className="block text-sm font-medium mb-1">Ward</label>
        <select
          value={selectedWard}
          onChange={(e) => setSelectedWard(e.target.value)}
          className="w-full border rounded px-3 py-2"
          disabled={!selectedConstituency}
        >
          <option value="">Select Ward</option>
          {wards.map(ward => (
            <option key={ward} value={ward}>
              {ward}
            </option>
          ))}
        </select>
      </div>

      {selectedWard && (
        <div className="p-4 bg-green-50 border border-green-200 rounded">
          <h3 className="font-semibold">Selected Location:</h3>
          <p>{selectedWard} Ward, {selectedConstituency}, {selectedCounty}</p>
        </div>
      )}
    </div>
  );
}

📊 TypeScript Types

interface County {
  county_code: number;
  county_name: string;
  constituencies: Constituency[];
}

interface Constituency {
  constituency_name: string;
  wards: string[];
}

interface SearchResult {
  county?: County;
  constituency?: Constituency;
  ward?: string;
}

📖 Data Structure

The package contains hierarchical administrative data:

Kenya (Country)
├── 47 Counties (e.g., Nairobi, Mombasa, Kisumu)
│   ├── 290+ Constituencies (e.g., Westlands, Langata, Dagoretti)
│   │   └── 1,450+ Wards (e.g., Kilimani, Karen, Kangemi)

Example County Structure:

{
  "county_code": 47,
  "county_name": "Nairobi",
  "constituencies": [
    {
      "constituency_name": "Westlands",
      "wards": [
        "Kitisuru",
        "Parklands/Highridge",
        "Karura",
        "Kangemi",
        "Mountain View"
      ]
    }
  ]
}

🌍 Data Source & Accuracy

This data is compiled from official sources:

  • IEBC (Independent Electoral and Boundaries Commission) - Official electoral boundaries
  • KNBS (Kenya National Bureau of Statistics) - Census and statistical data
  • OpenStreetMap Kenya - Community-maintained geospatial data

Last Updated: October 2024
Data Version: 1.0.0

Data Accuracy

If you notice any inaccuracies or outdated information, please:

  1. Open an issue with details
  2. Provide the official source/reference
  3. Submit a pull request with corrections

💖 Support This Project

If you find this package useful, please consider supporting its development:

GitHub Sponsors

Why Sponsor?

  • 🔄 Keep the data updated with latest changes
  • 🐛 Faster bug fixes and support
  • ✨ New features and improvements
  • 📚 Better documentation and examples
  • 🌍 Help the Kenyan developer community

Sponsorship Tiers

  • Coffee Supporter ($5/month) - Help keep the project maintained
  • 🥉 Bronze Sponsor ($25/month) - Priority support
  • 🥈 Silver Sponsor ($100/month) - Logo on README
  • 🥇 Gold Sponsor ($500/month) - Custom features

Become a sponsor →

🤝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

Ways to Contribute

  • 🐛 Report bugs
  • 💡 Suggest new features
  • 📝 Improve documentation
  • 🔧 Submit pull requests
  • 📊 Update data if you find inaccuracies
  • ⭐ Star the repository
  • 🔀 Share with others

📝 License

MIT © its-kios09

See LICENSE for full details.

🙏 Acknowledgments

  • IEBC for official boundary data
  • KNBS for statistical information
  • OpenStreetMap Kenya community
  • All contributors and supporters

📞 Support & Contact

🔗 Related Projects

📈 Stats

GitHub stars GitHub forks npm downloads GitHub issues GitHub pull requests


Made with ❤️ for the Kenyan developer community

Keywords

kenya osm openstreetmap boundaries counties constituencies wards administrative geography geospatial africa typescript javascript open-source mapping gis location-data