pythaiidcard

October 24, 2025 ยท View on GitHub

Python library for reading Thai national ID cards using smartcard readers.

pythaiidcard Cover

Thai ID Card Reader Demo

Table of Contents

Features

  • โœ… Full Card Data Extraction: Read all information from Thai ID cards
  • ๐Ÿ“ธ Photo Support: Extract and save card photos (JPEG format)
  • ๐Ÿฅ NHSO Health Insurance: Read National Health Security Office data
  • ๐Ÿ”– Laser ID Support: Read laser-engraved ID from cards
  • ๐Ÿ”’ Data Validation: Automatic CID checksum validation and date parsing
  • ๐Ÿ“… Date Conversion: Buddhist Era to Gregorian calendar conversion
  • ๐Ÿ›๏ธ Structured Data Models: Name and Address parsed into structured objects
  • ๐ŸŽจ Modern Web UI: Streamlit-based debug interfaces
  • ๐Ÿ Type-Safe: Full type hints and Pydantic models
  • ๐Ÿ” Error Handling: Comprehensive exception handling and system checks
  • ๐Ÿ“ฆ Zero Config: Auto-detects readers and connects to cards
  • ๐Ÿš€ Fast: Efficient APDU command implementation

What's New in v0.3.0

Debug Interface Improvements

  • ๐ŸŽจ Consolidated Modern Interface: Merged debug interfaces into a single sidebar-based layout
  • ๐Ÿ“ฑ Better Organization: Expandable reader list with status indicators in sidebar
  • โœจ Quick Copy Buttons: One-click copy for CID, names, and address fields
  • ๐ŸŒ“ Dark Gradient Theme: Modern, production-ready appearance with card-based design

API Server Updates (v2.3.0)

  • โšก Event-Driven Monitoring: New PCSCMonitor with real-time PC/SC state change detection
  • ๐Ÿ”„ Auto-Read by Default: Reliable automatic card reading on insertion
  • ๐Ÿ”ง Improved Reliability: Better handling of reader availability and connection states
  • ๐Ÿ› Field Mapping Fixes: Corrected web app field names to match API model

Documentation

  • ๐Ÿ“š Organized Structure: Moved documentation files to notes/ directory
  • ๐Ÿ“ Updated Guides: Comprehensive documentation for all interfaces
  • ๐Ÿงช Test Coverage: Added event-driven monitoring tests

Quick Start

# 1. Install system dependencies
sudo apt-get install -y pcscd libpcsclite-dev python3-dev swig

# 2. Install Python dependencies
uv sync --group dev

# 3. Run the web interface
uv run streamlit run debug/app.py

Then open http://localhost:8501 in your browser, insert your Thai ID card, and click "Scan Readers" โ†’ "Connect" โ†’ "Read Card".

Flutter Library Development

We are actively working on a Flutter version of this library for cross-platform mobile support (iOS/Android). The development is in progress at playground/thai_idcard_reader_test/.

Key Features

  • Package: Uses the ccid Flutter package for smartcard reading
  • Platform Support: iOS (13.0+) and Android with USB OTG smartcard readers
  • Architecture: Mirrors the Python implementation using APDU commands over PC/SC
  • CI/CD: Automated iOS builds via GitHub Actions and Fastlane

Getting Started with Flutter Version

cd playground/thai_idcard_reader_test/

# Install dependencies
flutter pub get

# Run on Android device
flutter run

# For iOS builds, see the CI/CD workflow or use GitHub Actions

See the Flutter project README for detailed setup instructions, hardware requirements, and iOS cloud build configuration.

Note: Thai National ID cards do NOT support NFC - external USB OTG (Android) or MFi-certified (iOS) smartcard readers are required.

iOS Testing Limitation: The author currently lacks access to a Mac, making iOS testing challenging. However, the project includes GitHub Actions CI/CD for automated iOS builds. Community contributions and testing on iOS devices are highly appreciated!

Credits

This project is inspired by and based on:

Prerequisites

System Dependencies

This project requires the following system packages:

  • pcscd - PC/SC Smart Card Daemon
  • libpcsclite-dev - PC/SC development files
  • python3-dev - Python development headers
  • swig - Interface compiler for Python bindings

Install them using:

sudo apt-get update
sudo apt-get install -y pcscd libpcsclite-dev python3-dev swig

Or if you have mise installed:

mise run install-deps

Installation

This project uses uv for Python package management.

# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install Python dependencies
uv sync

Or with mise:

mise run setup

Usage

Command Line

Connect your smartcard reader and insert a Thai ID card, then run:

uv run python thai-idcard.py

Or:

mise run run

The script will:

  • Detect available smartcard readers
  • Connect to the first reader automatically
  • Read personal data from the Thai ID card including:
    • Citizen ID
    • Thai/English full name
    • Date of birth
    • Gender
    • Card issuer
    • Issue/Expiry dates
    • Address
    • Photo (saved as {CID}.jpg)

Web Interface (Streamlit)

For a modern web-based interface with visual feedback:

# Modern interface with visual feedback
uv run streamlit run debug/app.py

Features:

  • ๐Ÿ” Visual reader detection and selection
  • ๐Ÿ”Œ Connection status monitoring
  • ๐Ÿ“– Interactive card reading with progress bars
  • ๐Ÿ“ธ Photo preview and download
  • ๐Ÿ’พ Export data as JSON, CSV, or photo
  • ๐Ÿ› Real-time debug logging (full interface)

See debug/README.md for detailed documentation.

Python Library

from pythaiidcard import ThaiIDCardReader

# Basic usage - auto-connect and read card
reader = ThaiIDCardReader()
with reader.card_session():
    card = reader.read_card(include_photo=True)

    print(f"Name: {card.english_fullname}")
    print(f"CID: {card.cid}")
    print(f"Age: {card.age}")
    print(f"Expires: {card.expire_date}")
    print(f"Valid: {not card.is_expired}")

    # Save photo
    if card.photo:
        card.save_photo()  # Saves as {cid}.jpg

# Advanced usage - manual control
from pythaiidcard.reader import ThaiIDCardReader

# List available readers
readers = ThaiIDCardReader.list_readers()
for reader_info in readers:
    print(f"Reader {reader_info.index}: {reader_info.name}")
    print(f"  ATR: {reader_info.atr}")
    print(f"  Connected: {reader_info.connected}")

# Connect to specific reader
reader = ThaiIDCardReader(reader_index=0)
reader.connect()

# Read without photo for faster operation
card = reader.read_card(include_photo=False)

# Read with progress callback
def on_photo_progress(current, total):
    print(f"Reading photo: {current}/{total}")

card = reader.read_card(
    include_photo=True,
    photo_progress_callback=on_photo_progress
)

reader.disconnect()

# Access card data - Structured models
# Names are parsed into structured Name objects
print(f"Thai First Name: {card.thai_name.first_name}")
print(f"Thai Last Name: {card.thai_name.last_name}")
print(f"English Prefix: {card.english_name.prefix}")  # "Mr.", "Mrs.", etc.
print(f"English Full Name: {card.english_name.full_name}")

# Address is parsed into structured Address object
print(f"House Number: {card.address_info.house_no}")
print(f"Moo: {card.address_info.moo}")
print(f"Soi: {card.address_info.soi}")
print(f"Street: {card.address_info.street}")
print(f"Subdistrict: {card.address_info.subdistrict}")
print(f"District: {card.address_info.district}")
print(f"Province: {card.address_info.province}")
print(f"Full Address: {card.address_info.address}")

# Backward compatibility - original string properties still work
print(f"Thai Name: {card.thai_fullname}")  # Returns full name string
print(f"English Name: {card.english_fullname}")  # Returns full name string
print(f"Address: {card.address}")  # Returns full address string

# Other computed properties
print(f"Gender: {card.gender_text}")  # "Male" or "Female"
print(f"Issue Date: {card.issue_date}")
print(f"Days until expiry: {card.days_until_expiry}")

# Export as JSON
import json
card_json = card.model_dump_json(indent=2)
print(card_json)

# Read NHSO (National Health Security Office) data
nhso_data = reader.read_nhso_data()
print(f"Main Hospital: {nhso_data.main_hospital_name}")
print(f"Insurance Type: {nhso_data.main_inscl}")
print(f"Expiry Date: {nhso_data.expire_date}")
print(f"Is Expired: {nhso_data.is_expired}")

# Read Laser ID (laser-engraved ID on card)
laser_id = reader.read_laser_id()
print(f"Laser ID: {laser_id}")

Data Fields

The library extracts and parses card data into structured models:

ThaiIDCard Model

FieldTypeDescription
cidstr13-digit citizen identification number (validated with checksum)
thai_nameNameStructured Thai name (prefix, first_name, middle_name, last_name)
english_nameNameStructured English name (prefix, first_name, middle_name, last_name)
date_of_birthdateBirth date (Buddhist Era โ†’ Gregorian converted)
genderstrGender code ("1"=Male, "2"=Female)
card_issuerstrIssuing organization
issue_datedateCard issue date
expire_datedateCard expiration date
address_infoAddressStructured address (house_no, moo, soi, street, subdistrict, district, province)
photobytesJPEG photo data (optional)

Name Model

Automatically parses names from Thai ID card format (prefix#firstname#middlename#lastname):

FieldTypeDescription
prefixstrName prefix (e.g., "เธ™เธฒเธข", "เธ™เธฒเธ‡", "Mr.", "Mrs.")
first_namestrFirst name
middle_namestrMiddle name (may be empty)
last_namestrLast name
full_namestrComputed full name with proper spacing

Address Model

Automatically parses Thai address format with proper component separation:

FieldTypeDescription
house_nostrHouse number (เธšเน‰เธฒเธ™เน€เธฅเธ‚เธ—เธตเนˆ)
moostrVillage/Moo number (เธซเธกเธนเนˆเธ—เธตเนˆ)
soistrSoi/Lane (เธ‹เธญเธข)
streetstrStreet/Road (เธ–เธ™เธ™)
subdistrictstrSubdistrict/Tambon (เธ•เธณเธšเธฅ) or เนเธ‚เธงเธ‡ (Bangkok)
districtstrDistrict/Amphoe (เธญเธณเน€เธ เธญ) or เน€เธ‚เธ• (Bangkok)
provincestrProvince (เธˆเธฑเธ‡เธซเธงเธฑเธ”)
addressstrComputed full address with Thai prefixes

Computed Properties

PropertyTypeDescription
ageintCurrent age calculated from date of birth
gender_textstrGender as text ("Male" or "Female")
is_expiredboolWhether the card has expired
days_until_expiryintDays remaining until card expires
thai_fullnamestrFull Thai name (backward compatibility)
english_fullnamestrFull English name (backward compatibility)
addressstrFull address string (backward compatibility)

NHSOData Model

National Health Security Office health insurance data:

FieldTypeDescription
main_insclstrMain insurance classification code
sub_insclstrSub insurance classification code
main_hospital_namestrMain registered hospital name
sub_hospital_namestrSub hospital name
paid_typestrPayment type code
issue_datedateNHSO registration issue date
expire_datedateNHSO registration expiry date
update_datedateLast update date
change_hospital_amountstrNumber of hospital changes allowed

Computed Properties:

  • is_expired (bool): Whether the NHSO registration has expired
  • days_until_expiry (int): Days remaining until NHSO registration expires

Laser ID

Thai ID cards also contain a laser-engraved ID that can be read separately:

laser_id = reader.read_laser_id()  # Returns string

This is a unique identifier laser-engraved on the physical card.

Dependencies

Python Packages

  • pyscard (>=2.3.0) - Python smartcard library for PC/SC interface
  • Pillow (>=11.3.0) - Python imaging library for photo handling
  • pydantic (>=2.0) - Data validation and settings management
  • python-dateutil (>=2.8.2) - Date parsing utilities

Development Dependencies

  • streamlit (>=1.28.0) - Web interface framework (optional)
  • ruff (>=0.8.4) - Linting and formatting

Troubleshooting

SystemDependencyError: Missing required system dependencies

The library will automatically check for required system dependencies on Linux systems with apt package manager. If dependencies are missing, you'll see a helpful error message with installation instructions.

Example error:

SystemDependencyError: Missing required system dependencies:

  โœ— PC/SC Smart Card Daemon (pcscd)
  โœ— PC/SC Lite development library (libpcsclite-dev)

To install missing dependencies, run:

  sudo apt-get update && sudo apt-get install -y pcscd libpcsclite-dev python3-dev swig

To skip the dependency check (if you know dependencies are installed via other means):

from pythaiidcard import ThaiIDCardReader

reader = ThaiIDCardReader(skip_system_check=True)

"No such file or directory: winscard.h"

Install the system dependencies listed above, particularly libpcsclite-dev.

"No readers available"

  • Ensure your smartcard reader is connected
  • Check that the pcscd service is running: sudo systemctl status pcscd
  • Start it if needed: sudo systemctl start pcscd

Permission denied

Add your user to the scard group:

sudo usermod -a -G scard $USER

Then log out and log back in.

Project Structure

pythaiidcard/
โ”œโ”€โ”€ pythaiidcard/              # Main library package
โ”‚   โ”œโ”€โ”€ __init__.py       # Package initialization
โ”‚   โ”œโ”€โ”€ reader.py         # ThaiIDCardReader implementation
โ”‚   โ”œโ”€โ”€ models.py         # Pydantic data models
โ”‚   โ”œโ”€โ”€ constants.py      # APDU commands and response codes
โ”‚   โ”œโ”€โ”€ exceptions.py     # Custom exceptions
โ”‚   โ”œโ”€โ”€ utils.py          # Utility functions
โ”‚   โ””โ”€โ”€ system_check.py   # System dependency checking
โ”œโ”€โ”€ debug/                # Debug interface
โ”‚   โ”œโ”€โ”€ app.py           # Modern compact interface
โ”‚   โ””โ”€โ”€ README.md        # Debug interface documentation
โ”œโ”€โ”€ thai-idcard.py       # Legacy CLI script
โ”œโ”€โ”€ pyproject.toml       # Project configuration
โ””โ”€โ”€ README.md            # This file

Key Components

  • ThaiIDCardReader: Main class for reading Thai ID cards
  • ThaiIDCard: Pydantic model with validated card data
  • Name: Structured name model (prefix, first_name, middle_name, last_name)
  • Address: Structured address model (house_no, moo, soi, street, subdistrict, district, province)
  • NHSOData: Health insurance data from National Health Security Office
  • CardReaderInfo: Information about available card readers
  • System Check: Automatic validation of system dependencies
  • Debug Interfaces: Streamlit-based web UIs for testing and debugging

License

See LICENSE file for details.