feat(carriers): add ST Courier tracking - #25
Merged
Conversation
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>
Aswincloud-Bot
approved these changes
Sep 4, 2026
Aswincloud-Bot
left a comment
There was a problem hiding this comment.
Auto-approved: @Aswinmcw is a member of @Aswincloud/admins.
Comment on lines
+67
to
+70
| return s | ||
| .replace(/<[^>]*>/g, " ") | ||
| .replace(/ /g, " ") | ||
| .replace(/&/g, "&") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
The POST returns no shipment data — it only binds the AWB to the session. A bare
GET /track/shipmentreturns the empty search form.Parsing notes
D2Q59l54,153Iq5) that can't be relied on.Orgin SRC,Destination(trailing space).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.parseScanssorts by parsed timestamp rather than assuming, which guarantees the oldest-first contractTimelineand the poller depend on. Worth confirming against a multi-scan shipment.estimatedDeliveryis always unset — ST Courier exposes no expected-delivery date.Testing
Verified against the live site through the real API route:
/api/track/stcourier/64424565531200—in_transit, TNNMK-NML → TNPDY, 1 scan/api/track/stcourier/99999999999404 not_found/api/track/stcourier/abc123400 invalid_input/api/carrierstsc --noEmitclean,next buildpasses. (npm run lintisn'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;
429is handled.🤖 Generated with Claude Code