Project Overview
This project provides programmatic access to Indian Railways’ IRCTC services for checking PNR status and retrieving live train updates. It wraps IRCTC’s web endpoints into a simple, reusable interface, enabling developers to integrate real-time train information into applications without dealing directly with IRCTC’s web forms or HTML parsing.
Main Features
- PNR Status Lookup
Retrieve current booking status, chart preparation status, seat confirmation, and coach details. - Live Train Tracking
Fetch real-time position, expected arrival/departure times, and delay information for any train. - Route & Schedule Retrieval
List station stops, scheduled times, and halt durations for selected trains. - Error Handling & Retries
Built-in mechanisms to handle rate limits, network issues, and IRCTC’s occasional downtime.
When to Use
- Building travel assistant bots or mobile apps that notify users of PNR confirmations and delays
- Integrating train schedules and real-time tracking into booking platforms or logistics dashboards
- Automating customer support workflows that require up-to-date train information
Value Proposition
- Accelerate development by avoiding manual scraping or reverse-engineering of IRCTC’s web interface
- Ensure reliability with automated retry and error-handling strategies tailored for IRCTC’s constraints
- Maintainable codebase that adapts to IRCTC changes without rewriting core business logic
Getting Started & Deployment
This section guides you through cloning the ortux/irctc repository, running it locally, and deploying it to GitHub Pages using the provided GitHub Actions workflow.
Prerequisites
- Git (v2.0+)
- Python 3 (for simple HTTP server) or Node.js (v12+) if you prefer
serve
/live-server
- A GitHub repository named
ortux/irctc
(or your fork) with Pages enabled on the main branch
Clone the Repository
git clone https://github.com/ortux/irctc.git
cd irctc
Run Locally
Using Python HTTP Server
# From the repo root
python3 -m http.server 8000
Open http://localhost:8000/home/ in your browser.
Using npm “serve”
npm install -g serve
serve -l 8000 .
Navigate to http://localhost:8000/home/.
Directory Structure
/
├─ home/ # Train booking homepage (home/index.html)
├─ search/ # Search results page (search/index.html)
├─ status/ # PNR status interface (status/index.html)
├─ train_status/ # Live train tracking (train_status/index.html)
├─ index.html # Client-side redirect to /home/
└─ .github/
└─ workflows/
└─ static.yml # GitHub Actions workflow for Pages
Deploying to GitHub Pages
In your repository Settings → Pages:
- Source: main branch
- Folder: ** / (root)**
Commit and push to main or trigger manually.
The workflow at .github/workflows/static.yml
handles checkout, artifact upload, and Pages deployment:
name: Deploy static content to Pages
on:
push:
branches: ["main"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Configure Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: . # Deploy entire repo root
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v1
Concurrency Settings
Prevent overlapping deployments while letting in-flight jobs finish:
concurrency:
# All deploy runs share the same queue
group: "pages"
# false → queue up new runs; allow current run to complete
cancel-in-progress: false
- Use
cancel-in-progress: true
for non-critical branches (e.g., staging). - Give each environment a unique
group
name when managing multiple workflows.
Customizing the Root Redirect
The root index.html
auto-redirects to /home/
. To change the target URL or message, edit:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=/home/">
<title>Redirecting…</title>
</head>
<body>
<p>Redirecting to the train booking page. If you aren’t redirected automatically, <a href="/home/">click here</a>.</p>
</body>
</html>
Adjust the content
URL and anchor link text as needed.
Code Structure
This section outlines the project layout and the role of each major file. Use this guide to locate functionality and understand how components connect.
Project tree
assets/
background.jpeg
backend/
index.js
navbar.js
pnr.js
results.js
home/
index.html
search/
index.html
status/
index.html
train_status/
index.html
assets/background.jpeg
• High-resolution train image used as page background or header hero.
• Reference in HTML or Tailwind CSS:
<div class="h-64 bg-cover" style="background-image: url('../assets/background.jpeg')"></div>
backend/index.js
Provides station autocomplete, debounced input handling, in-memory caching, timeout/fallback logic, and form submission wiring on the booking homepage.
Key responsibilities
- Attach
input
listeners to#fromStation
and#toStation
- Debounce user keystrokes (200–300 ms)
- Fetch suggestions with abortable timeout (5 s) and local fallback
- Render dropdown items, handle selection, and store station codes
- Listen for form
submit
to redirect to search page with query params
Inclusion in home/index.html
<script type="module" src="../backend/index.js"></script>
backend/navbar.js
Controls responsive navigation and theme toggling across all pages.
Features
- Mobile menu show/hide on toggle button click
- Window resize listener to reset menu state
- Dark/light mode switch and
prefers-color-scheme
fallback - ARIA attributes for accessibility
Include before closing </body>
<script type="module" src="../backend/navbar.js"></script>
backend/pnr.js
Implements client-side PNR status checking on status/index.html
.
Exports
async function checkPNR(pnr: string): Promise<void>
– validates input, fetches API data, and updates DOM
Usage example in status/index.html
<input id="pnrInput" type="text" placeholder="Enter PNR" />
<button id="checkBtn">Check Status</button>
<script type="module">
import { checkPNR } from '../backend/pnr.js';
document.getElementById('checkBtn').addEventListener('click', () => {
const pnr = document.getElementById('pnrInput').value.trim();
checkPNR(pnr);
});
</script>
backend/results.js
Handles train search results on search/index.html
, including filtering and availability refresh.
Exports
async function init(): Promise<void>
– entry point: reads URL params, fetches trainsasync function fetchAndProcessTrains(params): Promise<ProcessedData>
function renderTrainCards(data): void
– injects direct and nearby train cardsfunction refreshAvailability(trainId): Promise<void>
– updates a single card
Initialization in search/index.html
<script type="module">
import { init } from '../backend/results.js';
document.addEventListener('DOMContentLoaded', init);
</script>
home/index.html
Train booking homepage
- Station autocomplete inputs (
#fromStation
,#toStation
) - Route type buttons (One-way, Round-trip)
- Search form redirects to
/search/index.html?from=…&to=…&date=…
- Includes Tailwind CSS utilities and
backend/index.js
search/index.html
Search results page
- Header and nav (scripts from
navbar.js
) - Loading and error states
- Filter panel (class, time, availability)
- Direct vs. nearby train sections
- Includes
backend/results.js
for data fetching and rendering
status/index.html
PNR status checker
- Input field, search button
- Sections for train details, passenger status, booking info
- Error and retry UI
- Imports
backend/navbar.js
andbackend/pnr.js
train_status/index.html
Live train tracking interface
- Inputs: train number, date picker
- “Track Train” button triggers API fetch
- Displays journey timeline, station statuses, and auto-refresh
- Includes
backend/navbar.js
and inline or dedicated script for tracking logic
Navigating the codebase by this structure helps you locate features quickly, understand entry points, and extend functionality with minimal friction.
Customization & Configuration
This section explains how to configure API endpoints, adjust request timeouts, enable dark mode, replace assets, and tweak UI templates.
API Base URLs & Timeouts
Centralize your endpoints and timeouts in a config.js
file:
// backend/config.js
export default {
stationApi: process.env.STATION_API_URL || 'https://api.irctc.co.in/stations',
pnrApi: process.env.PNR_API_URL || 'https://api.irctc.co.in/pnr',
searchApi: process.env.SEARCH_API_URL || 'https://api.irctc.co.in/search',
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 5000
};
Import and use in your fetch functions:
// backend/index.js
import config from './config';
async function fetchWithTimeout(url, options = {}) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), config.requestTimeout);
const res = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(id);
return res.json();
}
export async function fetchStations(query) {
const url = `${config.stationApi}?q=${encodeURIComponent(query)}`;
return fetchWithTimeout(url);
}
Override values via environment variables or by editing config.js
.
Dark-Mode Styling
Use CSS variables and a body class toggle. Create dark.css
:
/* assets/css/dark.css */
:root {
--bg-color: #121212;
--text-color: #e0e0e0;
--card-bg: #1e1e1e;
}
body.dark-mode {
background-color: var(--bg-color);
color: var(--text-color);
}
.train-card {
background-color: var(--card-bg);
}
Load it in your HTML and toggle via JS:
<link rel="stylesheet" href="assets/css/dark.css">
<button id="darkToggle">Toggle Dark Mode</button>
<script>
document
.getElementById('darkToggle')
.addEventListener('click', () => document.body.classList.toggle('dark-mode'));
</script>
Asset Replacement
Replace assets/background.jpeg
with your own image or change its reference:
/* assets/css/main.css */
body {
background: url('../assets/background.jpeg') no-repeat center/cover;
}
To use a different filename:
- Place
my-train.jpg
inassets/
. - Update
main.css
:body { background: url('../assets/my-train.jpg') no-repeat center/cover; }
UI Template Tweaks
Station Autocomplete (backend/index.js)
Default item renderer:
function createDropdownItem(station) {
const li = document.createElement('li');
li.className = 'station-item';
li.textContent = station.name;
return li;
}
To show code and name:
function createDropdownItem(station) {
const li = document.createElement('li');
li.className = 'station-item';
li.innerHTML = `
<span class="station-code">${station.code}</span>
<span class="station-name">${station.name}</span>
`;
return li;
}
PNR Status Checker (backend/pnr.js)
Wrap checkPNR()
to add custom loading indicator:
import { checkPNR } from './pnr';
document.getElementById('pnrForm').addEventListener('submit', async e => {
e.preventDefault();
const loader = document.createElement('div');
loader.id = 'custom-loader';
loader.textContent = 'Checking…';
document.body.append(loader);
try {
await checkPNR();
} finally {
loader.remove();
}
});
Train Results (backend/results.js)
Default card renderer:
function renderTrainCard(train) {
return `
<div class="train-card">
<h3>${train.name}</h3>
<span>${train.availability}</span>
</div>`;
}
To include departure time:
function renderTrainCard(train) {
return `
<div class="train-card">
<h3>${train.name} (${train.number})</h3>
<p>Departs at: ${train.departureTime}</p>
<span>Status: ${train.availability}</span>
</div>`;
}
Place these functions in your own copy of results.js
or override via module aliasing in your build setup.