Skip to main content

Geographic Information from National ID

The getPlaceByIranNationalId utility extracts the birthplace (city and province) information encoded in Iranian National ID numbers.

Basic Usage

import { getPlaceByIranNationalId } from '@persian-tools/persian-tools';

Simple Extraction

getPlaceByIranNationalId("0499370899");
// Output: { city: 'خمین', province: 'مرکزی' }

getPlaceByIranNationalId("0684159415");
// Output: { city: 'شیراز', province: 'فارس' }

getPlaceByIranNationalId("0076229645");
// Output: { city: 'تهران', province: 'تهران' }

How It Works

Iranian National IDs encode geographic information in their first 3 digits, which correspond to the registration office where the ID was issued (typically the birthplace).
The first 3 digits represent a unique code for each registration office across Iran’s provinces and cities.
Supports all 31 provinces and hundreds of cities across Iran with their registration office codes.
Only works with valid National IDs - invalid IDs return null.

Advanced Examples

User Registration with Location

interface UserRegistration {
	nationalId: string;
	name: string;
	phone: string;
}

function processRegistration(userData: UserRegistration) {
	// Validate National ID first
	if (!verifyIranianNationalId(userData.nationalId)) {
		throw new Error("کد ملی معتبر نیست");
	}

	// Extract location information
	const location = getPlaceByIranNationalId(userData.nationalId);

	return {
		...userData,
		birthPlace: location,
		isFromTehran: location?.province === "تهران",
		registrationRegion: location ? `${location.city}, ${location.province}` : "نامشخص",
	};
}

Demographics Analysis

function analyzeUserDemographics(nationalIds: string[]) {
	const locations = nationalIds
		.filter((id) => verifyIranianNationalId(id))
		.map((id) => getPlaceByIranNationalId(id))
		.filter((location) => location !== null);

	// Group by province
	const provinceStats = locations.reduce(
		(stats, location) => {
			const province = location!.province;
			stats[province] = (stats[province] || 0) + 1;
			return stats;
		},
		{} as Record<string, number>,
	);

	// Group by city
	const cityStats = locations.reduce(
		(stats, location) => {
			const city = location!.city;
			stats[city] = (stats[city] || 0) + 1;
			return stats;
		},
		{} as Record<string, number>,
	);

	return {
		totalValid: locations.length,
		provinceDistribution: provinceStats,
		cityDistribution: cityStats,
		topProvinces: Object.entries(provinceStats)
			.sort(([, a], [, b]) => b - a)
			.slice(0, 5),
	};
}

Geographic Filtering

function filterUsersByRegion(
	users: Array<{ nationalId: string; name: string }>,
	targetProvince?: string,
	targetCity?: string,
) {
	return users
		.filter((user) => {
			const location = getPlaceByIranNationalId(user.nationalId);

			if (!location) return false;

			if (targetProvince && location.province !== targetProvince) {
				return false;
			}

			if (targetCity && location.city !== targetCity) {
				return false;
			}

			return true;
		})
		.map((user) => ({
			...user,
			location: getPlaceByIranNationalId(user.nationalId),
		}));
}

// Usage
const tehranUsers = filterUsersByRegion(allUsers, "تهران");
const shirazUsers = filterUsersByRegion(allUsers, "فارس", "شیراز");

Major Cities and Codes

  • Tehran Province
  • Isfahan Province
  • Fars Province
  • Khuzestan Province
Code RangeCity
001-085تهران
136-151ورامین
196-200پاکدشت
219-229اسلامشهر
297-300شهریار

Return Value Structure

interface PlaceInfo {
	city: string; // City name in Persian
	province: string; // Province name in Persian
}

// Function signature
function getPlaceByIranNationalId(nationalId: string): PlaceInfo | null;

Edge Cases

Invalid National IDs

getPlaceByIranNationalId("1234567890"); // null (invalid checksum)
getPlaceByIranNationalId("0000000000"); // null (invalid pattern)
getPlaceByIranNationalId(""); // null (empty string)
getPlaceByIranNationalId(null); // null

Unknown Geographic Codes

// Very rare cases where code might not be in database
getPlaceByIranNationalId("9999999999"); // null (if code 999 doesn't exist)

Different Input Formats

// Works with Persian and Arabic digits
getPlaceByIranNationalId("۰۴۹۹۳۷۰۸۹۹");
// Output: { city: 'خمین', province: 'مرکزی' }

getPlaceByIranNationalId("٠٤٩٩٣٧٠٨٩٩");
// Output: { city: 'خمین', province: 'مرکزی' }

Performance Considerations

  • Lookup time: ~0.02ms (hash table lookup)
  • Memory overhead: ~50KB (geographic database)
  • Batch processing: Excellent scaling
  • Cache results for repeated lookups
  • Validate National ID first to avoid unnecessary lookups
  • Use in combination with validation for better UX

TypeScript Support

import { getPlaceByIranNationalId, PlaceInfo } from "persian-tools";

// Type-safe usage
const location: PlaceInfo | null = getPlaceByIranNationalId("0499370899");

if (location) {
	console.log(`City: ${location.city}, Province: ${location.province}`);
}

// Custom type guards
function isFromTehran(nationalId: string): boolean {
	const location = getPlaceByIranNationalId(nationalId);
	return location?.province === "تهران";
}

Real-world Applications

E-commerce Shipping

function calculateShippingCost(nationalId: string, basePrice: number): number {
	const location = getPlaceByIranNationalId(nationalId);

	if (!location) return basePrice;

	// Different rates for different provinces
	const provinceMultipliers: Record<string, number> = {
		تهران: 1.0,
		اصفهان: 1.2,
		فارس: 1.3,
		خوزستان: 1.4,
		// Remote provinces
		"سیستان و بلوچستان": 2.0,
		کردستان: 1.8,
	};

	const multiplier = provinceMultipliers[location.province] || 1.5;
	return Math.round(basePrice * multiplier);
}

Regional Service Availability

function checkServiceAvailability(nationalId: string, service: string): boolean {
	const location = getPlaceByIranNationalId(nationalId);

	if (!location) return false;

	const serviceMap: Record<string, string[]> = {
		"express-delivery": ["تهران", "اصفهان", "فارس", "خراسان رضوی"],
		"same-day-delivery": ["تهران"],
		"premium-support": ["تهران", "اصفهان", "فارس"],
	};

	return serviceMap[service]?.includes(location.province) || false;
}

Marketing Segmentation

function segmentUsersByRegion(users: Array<{ nationalId: string }>) {
	const segments = {
		metropolitan: [] as any[],
		urban: [] as any[],
		rural: [] as any[],
	};

	const metropolitanProvinces = ["تهران", "اصفهان", "فارس"];
	const urbanProvinces = ["خراسان رضوی", "آذربایجان شرقی", "خوزستان"];

	users.forEach((user) => {
		const location = getPlaceByIranNationalId(user.nationalId);
		if (!location) return;

		if (metropolitanProvinces.includes(location.province)) {
			segments.metropolitan.push({ ...user, location });
		} else if (urbanProvinces.includes(location.province)) {
			segments.urban.push({ ...user, location });
		} else {
			segments.rural.push({ ...user, location });
		}
	});

	return segments;
}

Integration Examples

React Component

function UserLocationDisplay({ nationalId }: { nationalId: string }) {
  const location = getPlaceByIranNationalId(nationalId);

  if (!location) {
    return <span>محل تولد: نامشخص</span>;
  }

  return (
    <div className="location-info">
      <span>محل تولد: {location.city}</span>
      <span>استان: {location.province}</span>
    </div>
  );
}

Database Model

interface User {
	id: string;
	nationalId: string;
	name: string;
	birthCity?: string;
	birthProvince?: string;
}

function enrichUserWithLocation(user: Omit<User, "birthCity" | "birthProvince">): User {
	const location = getPlaceByIranNationalId(user.nationalId);

	return {
		...user,
		birthCity: location?.city,
		birthProvince: location?.province,
	};
}