Resolve a natural-language origin + destination + (optional) arrive-by / leave-at time into the public-transport itineraries returned by transportnsw.info: per-itinerary departure / arrival times, duration, leg-by-leg mode + route, fare, real-time delay status. Drives the deterministic URL-param surface; falls back to the form when location IDs aren't yet cached. Read-only.
Automate repetitive workflows and reduce manual effort
Example: Generate reports, summarize documents, draft communications
Save 3-5 hours per week on routine tasks
Learn new skills, understand complex topics, get expert guidance
Example: Explain concepts, provide examples, suggest learning resources
Accelerate learning and skill development by 2x
Enhance output quality through reviews, suggestions, and refinements
Example: Review drafts, suggest improvements, catch errors
Improve work quality by 30-40% with less effort
Time estimate: 15-45 minutes depending on use case complexity
Prerequisites
Submit your Claude Code skill and start earning
browse install transportnsw.info/find-transport-route-yas5pcCompatible with
Supported agents
| name | find-transport-route |
| title | Transport NSW Trip Planner — Find a Route |
| description | >- Resolve a natural-language origin + destination + (optional) arrive-by / leave-at time into the public-transport itineraries returned by transportnsw.info: per-itinerary departure / arrival times, duration, leg-by-leg mode + route, fare, real-time delay status. Drives the deterministic URL-param surface; falls back to the form when location IDs aren't yet cached. Read-only. |
| website | transportnsw.info |
| category | transit |
| tags | - transit - trip-planner - public-transport - sydney - nsw - read-only - url-param |
| source | 'browserbase: agent-runtime 2026-05-20' |
| updated | '2026-05-20' |
| recommended_method | url-param |
| alternative_methods | - method: browser rationale: >- Drive the typeahead + form when stop / suburb IDs are not yet cached for a given origin or destination string. The URL-param surface needs the resolved IDs as input, and the typeahead modal is the only public way to discover them. Persist resolved IDs to a local cache so each location is resolved exactly once. - method: api rationale: >- Transport for NSW publishes an official OAuth-gated Trip Planner REST API at opendata.transport.nsw.gov.au. Use it when the caller has a registered API key — it is the canonical machine surface. For unauthenticated agents the API returns 401/403, and the URL-param path on transportnsw.info documented here is the cheapest deterministic alternative. |
| verified | true |
| proxies | true |
Given a natural-language trip query — origin + destination + (optional) arrival/departure time — return the public-transport itineraries offered by the official NSW trip planner: each itinerary's departure time, arrival time, duration, leg-by-leg mode + route number, transfer count, walk time, fare, and real-time delay status. Read-only — never books, never opens a checkout flow (the planner has no checkout — only journey suggestions).
The Transport NSW trip planner accepts the full origin / destination / time triple via URL query parameters on https://transportnsw.info/trip-planner/plan. A single GET reproduces the same state the UI would reach after five clicks, so the recommended path is to (1) resolve each location string to a stop / suburb ID via the typeahead, then (2) construct the canonical URL.
The Browser fallback (driving the form click-by-click) is documented at the end and is what you should use when you don't yet have IDs cached.
https://transportnsw.info/trip-planner/plan
?from=<originId>
&to=<destinationId>
[&arrivalDateTime=YYYYMMDDHHMM] # arrive-by; Sydney local time
[&departureDateTime=YYYYMMDDHHMM] # leave-at; Sydney local time
[&excludedModes=<csv-of-mode-ids>] # e.g. 11 = school bus, auto-added by the "Plan a trip" splash button
arrivalDateTime and departureDateTime → "Leaving now" (server uses Sydney current time, not the browser's clock).from and to:
200060 = Central Station, Sydney.suburbID:<int>:1:<URL-encoded-label>:<x>:<y>:GDAV. Example: suburbID:95361002:1:Bondi+Beach:4895254:3758264:GDAV. Use this when the user names a suburb / POI rather than a specific stop — the planner routes to a representative point in the suburb.arrivalDateTime / departureDateTime are in YYYYMMDDHHMM and must be interpreted in Australia/Sydney local time (not the browser's TZ — see gotcha). A value in the past returns an empty alert ("No results found"), not an error.Example: Central → Bondi Beach arriving by 17:00 Wed 20 May 2026:
https://transportnsw.info/trip-planner/plan?from=200060&to=suburbID:95361002:1:Bondi+Beach:4895254:3758264:GDAV&arrivalDateTime=202605201700
When the user names an origin or destination without a cached ID, drive the search modal once and harvest the URL the planner produces:
browse open https://transportnsw.info/trip-planner/planbrowse click @<ref of "Origin: No location selected"> — opens the search modal.browse click @<ref of textbox "Search input"> then browse type "<location string>".browse wait timeout 2500 — typeahead is debounced.browse get url — the new URL contains the resolved from= (or to=) ID. Cache it; the IDs are stable across sessions.The same typeahead is what you'd use to discover new IDs at runtime; once resolved, they should be persisted in a local cache so a CI test never re-discovers them.
The cleanest path is to bypass the UI date picker entirely and pass arrivalDateTime / departureDateTime in the URL (see §1). If for some reason you must drive the picker:
browse click @<ref of "Selected time: Leaving now"> — opens the "Choose date and time" dialog.browse click @<ref of "Select Arrive by option"> (or "Select Leave at option").Day, Hour, Minute) are custom listboxes, not native <select> — browse select will return selected: []. Instead, click the combobox to open it, then click the desired option ref. Available values:
Today (<weekday>), Tomorrow (<weekday>), then absolute dates DD MMM (<weekday>) for ~14 days ahead.00–23 (24-hour).00, 05, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55 (5-minute granularity only).browse click @<ref of "Apply"> — the URL now carries arrivalDateTime= / departureDateTime= and results refresh in ~2–4 s.Once the planner has both endpoints + a valid time, the results panel renders a vertical list of button: elements — one per itinerary. Parse each button's aria-label — it's a structured, comma-separated string that enumerates every field cleanly:
"Leaving in <N> minutes
Transfer to <mode-1> Transfer to <mode-2> Walk for <N>min
<interchange-stop>
Departing at HH:MM, Duration is N minutes, Arriving at HH:MM[, next day]
Fare is $X.XX
[On-time | <N> min late | Real-time unavailable]
from <first-stop>, Platform <N>
This service is Accessible
There is an alert for this service"
Each leg is one Transfer to <mode> <route-number> clause (e.g. Transfer to T4 train, Transfer to 379 bus). Walking legs are Walk for <N>min. The final segment usually ends with the interchange stop name (e.g. Bondi Junction).
The same data appears as child StaticText nodes (16:22, 34min, $5.63, ...) but those are formatted in the browser's local TZ, while the aria-label is in Sydney AEST. Always parse the aria-label for deterministic output. (See gotchas.)
Above the list, four tabs gate the mode set: Public Transport (default) / Walk / Cycle / Drive. The Drive tab returns a single car-route summary, not a list — keep the Public Transport tab selected unless the user explicitly asked for driving or active-transport directions.
sid=$(browse cloud sessions create --keep-alive --verified --proxies | …)
export BROWSE_SESSION="$sid"
browse open "https://transportnsw.info/trip-planner/plan" --remote
browse wait load --remote && browse wait timeout 2000 --remote
# Origin
browse click @<ref "Origin: No location selected">
browse click @<ref "Search input"> && browse type "Central Station" --remote
browse wait timeout 2500 --remote
browse click @<ref of first matching result> # URL gets ?from=200060
# Destination
browse click @<ref "Destination: No location selected">
browse click @<ref "Search input"> && browse type "Bondi Beach" --remote
browse wait timeout 2500 --remote
browse click @<ref of first matching result> # URL gets &to=suburbID:…
# Time (optional)
browse click @<ref "Selected time: Leaving now">
browse click @<ref "Select Arrive by option">
browse click @<ref Day combobox> ; browse click @<ref "Tomorrow (Wed)">
browse click @<ref Hour combobox> ; browse click @<ref "17">
browse click @<ref Minute combobox>; browse click @<ref "00">
browse click @<ref "Apply">
# Read results
browse snapshot --remote # parse button aria-labels (see §4)
The first-page render after Apply takes 2–4 s; browse wait timeout 4000 after the Apply click before snapshotting is reliable. A stealth + residential-proxy session (--verified --proxies) is what was used during skill development and is the safer default; the site is fronted by CloudFront but does not appear to gate on bot-detection for this surface.
aria-label on each itinerary button uses Sydney AEST (UTC+10), but the visible StaticText nodes (the 16:22, 34min, 23:55 strings) use the browser session's local timezone. Verified on a Browserbase US-West session (PDT, UTC-7): aria-label "Departing at 16:22" vs StaticText "23:22" — a 17-hour offset for the same departure. Always parse the aria-label; treat the StaticText fields as display chrome, not data. If you must use StaticText, force the session TZ via Australia/Sydney. CI tests should pin the session to Sydney TZ to make the StaticText and aria-label converge.arrivalDateTime / departureDateTime are in Sydney local time, not the browser's clock. A value in the past returns the empty alert: "No results found / There were no services found" panel — there is no explicit error message. If the planner returns "No results" for a route you know is well-served (e.g. Central → Bondi Beach), the most common cause is a stale arrivalDateTime whose date is already in Sydney's past.<select> elements. browse select @<ref> <value> returns selected: [] and silently does nothing. Click the combobox first, then click the option ref inside the resulting listbox. Minutes are 5-minute increments only (00, 05, 10, …, 55).from and to accept two distinct ID shapes — a 6-digit numeric stop ID (e.g. 200060 = Central Station) or a structured suburb / place ID suburbID:<int>:1:<URL-encoded-label>:<x>:<y>:GDAV (e.g. suburbID:95361002:1:Bondi+Beach:4895254:3758264:GDAV). Both from and to accept either shape independently. Picking a "Stop" in the typeahead yields the numeric shape; picking a "Place" yields the suburb shape.excludedModes=11 is auto-injected by the splash "Plan a trip" button. Mode 11 appears to be school-bus services. Directly hitting /trip-planner/plan?from=…&to=… without excludedModes includes all modes, which is usually what you want. Other mode IDs (deduced from the "Mode (7)" filter chip showing 7 modes — Train, Metro, Bus, Light rail, Ferry, Coach, School bus): pass as comma-separated, e.g. excludedModes=4,9 to exclude Light rail and Ferry.button: Selected trip preference: Earliest arrival chip on the results page — there is no tripPref= query param.from and to are set — there is no explicit "Search" / "Submit" button on the form. The "Updated: HH:MM" button in the results panel is a refresh button, not a submit.[3-2451] div: Bondi Beach) is the suburb (Places tab); the next two are bus stops named "Bondi Beach" (Stops tab). Use the Places tab when the user said "Bondi Beach" generically, and the Stops tab when they specified a stop ID / station./trip or /trip-planner as the entry URL — both render a marketing splash with a "Plan a trip" button, not the form. Open /trip-planner/plan directly to skip the splash. (Hitting /trip-planner/plan with no params lands on the empty form, ready for input — equivalent to clicking the splash button.)opendata.transport.nsw.gov.au (TfNSW Open Data Hub) — if the calling agent has a registered API key, prefer that over scraping. For unauthenticated agents, the URL-param surface documented here is the cheapest deterministic path. Don't waste cycles trying to hit the API anonymously./sapi-style public JSON behind the page. The site is a SPA that calls authenticated TfNSW backends; cookie-less direct hits against the internal XHR endpoints return 401/403. The accessibility-tree-driven scrape of aria-label strings is the supported public surface.{
"query": {
"origin": { "raw": "Central Station", "id": "200060", "resolved_label": "Central Station, Sydney" },
"destination": { "raw": "Bondi Beach", "id": "suburbID:95361002:1:Bondi+Beach:4895254:3758264:GDAV", "resolved_label": "Bondi Beach" },
"time_anchor": { "mode": "arrive_by", "datetime_local": "2026-05-20T17:00", "tz": "Australia/Sydney" }
},
"url": "https://transportnsw.info/trip-planner/plan?from=200060&to=suburbID:95361002:1:Bondi+Beach:4895254:3758264:GDAV&arrivalDateTime=202605201700",
"itineraries": [
{
"depart_local": "16:22",
"arrive_local": "16:56",
"next_day": false,
"duration_min": 34,
"fare_aud": 5.63,
"transfers": 1,
"walk_min": 6,
"realtime_status": "Real-time unavailable",
"first_stop": "Central Station, Platform 24",
"interchange": "Bondi Junction",
"accessible": true,
"alerts": true,
"legs": [
{ "mode": "train", "route": "T4" },
{ "mode": "bus", "route": "379" },
{ "mode": "walk", "duration_min": 6 }
]
}
],
"result_status": "ok"
}
Distinct outcome shapes:
// ok — one or more itineraries returned
{ "result_status": "ok", "itineraries": [ ... ] }
// empty — planner returned the "No results found" alert (most often: arrivalDateTime in the past, or genuinely unreachable)
{ "result_status": "no_results", "itineraries": [], "alert_text": "There were no services found. Refine your preferences and try again." }
// ambiguous_location — the typeahead returned 0 matches or multiple equally-ranked matches for an origin/destination string
{ "result_status": "ambiguous_location", "field": "destination", "raw": "...", "candidates": [ { "label": "...", "id": "..." }, ... ] }
AI-first code editor with Composer
Before installing skills in Cursor, ensure your development environment meets these requirements:
node --versionfind-transport-routeExecute the skills CLI command in your project's root directory to begin installation:
browse install transportnsw.info/find-transport-route-yas5pcFetches find-transport-route from transportnsw.info/find-transport-route-yas5pc and configures it for Cursor.
The CLI shows a list of agents. Use arrow keys and space to select Cursor:
Confirm successful installation by checking the skill directory location:
.cursor/skills/find-transport-route
Restart Cursor to activate find-transport-route. Access via /find-transport-routein your agent's command palette.
Learn more:View source on GitHubSkills CLI docsAbout CursorWhat are agent skills?
Steps
Common Pitfalls
✓ Do
✗ Don't
💡 Pro Tips
✓ Use when
Use when skill capabilities match your task, clear ROI on time saved, and you can validate outputs. Best for repetitive tasks, learning, and quality improvement.
✗ Avoid when
Avoid when task requires deep expertise you can't validate, involves sensitive decisions, or when learning process is more valuable than speed of completion.
get-player-stats
pro-football-reference.com/get-player-stats-5pitm4 · sports · tag: read-only
track-live-scores
livescore.com/track-live-scores-txxdp5 · sports · tag: read-only
search-cheapest-flight
skyscanner.net/search-cheapest-flight-v8nvut · travel · tag: read-only
search-flights
google.com/search-flights-ts4g1f · travel · tag: read-only
check-availability
recreation.gov/check-availability-3ldi81 · outdoors · tag: read-only
peptide-research
peptideportal.org/peptide-research-to6qkq · research · tag: read-only
Keeps context tight: find-transport-route is the kind of skill you can hand to a new teammate without a long onboarding doc.
find-transport-route is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
Registry listing for find-transport-route matched our evaluation — installs cleanly and behaves as described in the markdown.
find-transport-route fits our agent workflows well — practical, well scoped, and easy to wire into existing repos.
Useful defaults in find-transport-route — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
We added find-transport-route from the explainx registry; install was straightforward and the SKILL.md answered most questions upfront.
Registry listing for find-transport-route matched our evaluation — installs cleanly and behaves as described in the markdown.
find-transport-route fits our agent workflows well — practical, well scoped, and easy to wire into existing repos.
Keeps context tight: find-transport-route is the kind of skill you can hand to a new teammate without a long onboarding doc.
Registry listing for find-transport-route matched our evaluation — installs cleanly and behaves as described in the markdown.
showing 1-10 of 75