Skip to content

feat(carriers): add ST Courier tracking - #25

Merged
Aswinmcw merged 1 commit into
mainfrom
feat/stcourier-carrier
Sep 4, 2026
Merged

feat(carriers): add ST Courier tracking#25
Aswinmcw merged 1 commit into
mainfrom
feat/stcourier-carrier

Conversation

@Aswinmcw

@Aswinmcw Aswinmcw commented Sep 4, 2026

Copy link
Copy Markdown
Member

Adds ST Courier (stcourier.com) as a tracked carrier.

Why it needs a scraper

ST Courier publishes no developer API — no docs, no keys, no portal. The only third-party options are paid aggregators (TrackingMore, Track123, Shipway). So this scrapes their public tracking page, same as the existing Blue Dart carrier.

How it works

Unlike Blue Dart's single GET, ST Courier needs two requests because the AWB lives in a server session, not the URL:

POST /track/doCheck   awb_no=<n>   → {"code":200,"msg":"Track Shipment"} + Set-Cookie: ci_session
GET  /track/shipment  (that cookie) → server-rendered summary table + scan timeline

The POST returns no shipment data — it only binds the AWB to the session. A bare GET /track/shipment returns the empty search form.

Parsing notes

  • Selectors are label- and structure-based, not class-based — ST Courier emits randomised CSS class names (D2Q59l54, 153Iq5) that can't be relied on.
  • Summary labels carry their own typos, matched as-is: Orgin SRC, Destination (trailing space).
  • Not-found is the absence of the Status of AWB No. heading. The page returns HTTP 200 either way. The word "Invalid" is deliberately not used as a signal — it appears in inline JS validation strings on every page, including successful ones.
  • Scan ordering isn't documented, and a single-scan shipment can't reveal it. parseScans sorts by parsed timestamp rather than assuming, which guarantees the oldest-first contract Timeline and the poller depend on. Worth confirming against a multi-scan shipment.
  • estimatedDelivery is always unset — ST Courier exposes no expected-delivery date.

Testing

Verified against the live site through the real API route:

Request Result
/api/track/stcourier/64424565531 200in_transit, TNNMK-NML → TNPDY, 1 scan
/api/track/stcourier/99999999999 404 not_found
/api/track/stcourier/abc123 400 invalid_input
/api/carriers lists ST Courier

tsc --noEmit clean, next build passes. (npm run lint isn't configured in the repo — it prompts for interactive ESLint setup — so it wasn't run.)

Risk

Same fragility class as the Blue Dart scraper: an ST Courier redesign breaks parsing. Two round trips per lookup makes it slower than the single-GET carriers, but the 15–30 min poll interval absorbs that fine. Their rate limits are unknown; 429 is handled.

🤖 Generated with Claude Code

ST Courier publishes no developer API, so this replicates the two-step
CodeIgniter flow their own site uses: POST /track/doCheck stores the AWB
against a fresh ci_session and returns only an ack, then GET
/track/shipment carries that cookie to get the server-rendered summary
table and scan timeline. The AWB lives in the session rather than the
URL, so step 2 without step 1's cookie just returns the empty form.

Parsing follows the Blue Dart scraper's approach — loose, label-based
selectors rather than ST Courier's randomised CSS class names. Not-found
is detected via the absence of the "Status of AWB No." heading; the page
returns HTTP 200 either way, and the word "Invalid" is unusable as a
signal because it appears in inline JS validation on every page,
successful ones included.

Their render order for multiple scans isn't documented and a single-scan
shipment can't reveal it, so parseScans sorts by parsed timestamp to
guarantee the oldest-first contract that Timeline and the poller expect.

ST Courier exposes no expected-delivery date, so estimatedDelivery is
left unset.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Aswinmcw
Aswinmcw requested review from a team and Aswin-coder as code owners September 4, 2026 04:24

@Aswincloud-Bot Aswincloud-Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-approved: @Aswinmcw is a member of @Aswincloud/admins.

@Aswinmcw
Aswinmcw added this pull request to the merge queue Sep 4, 2026
Comment thread src/carriers/stcourier.ts
Comment on lines +67 to +70
return s
.replace(/<[^>]*>/g, " ")
.replace(/&nbsp;/g, " ")
.replace(/&amp;/g, "&")
Merged via the queue into main with commit ad0b7cb Sep 4, 2026
3 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants