New York tolls: how to maintain

Files: /srv/toll/draft/NY, last built 2026-10-09 06:42 ET · the NY toll page · map test · facts below are read from the files each time this page is built (python3 /home/geo1/system/handbuilt/maintain_pages.py NY)

Procedure for this state

ny_state.py builds New York from its own sources (no published layer). Port Authority crossings (GWB, Lincoln, Holland, Goethals, Bayonne, Outerbridge) are on the NJ page; the Canada bridges are recorded as not routable (the router is United States only).

When to check

Refresh

  1. From geo1: python3 /home/geo1/system/handbuilt/fetch_list.py NY [names] (Bridge Authority, Niagara/Peace bridges, Port Authority guide, Atlantic Beach Bridge).
  2. thruway.ny.gov and mta.info refuse geo1. Fetch every thruway_* and mta_* source on b100: node ~/apitest/fetch_b100.mjs ~/nyfetch thruway_gantry_api=<url> ... (URLs are in /home/geo1/maps/toll/NY/urls.txt), then rsync -a ~/nyfetch/ geo1@192.168.50.220:/home/geo1/maps/toll/NY/sources/.

Rebuild

  1. Congestion-zone gantries (after an OSM refresh only): python3 cbd_classify.py writes osm/ny_cbd_gantries.json (every MTA detection gantry in Manhattan, the way it stands on, which side of the zone line each end is).
  2. Full chain with NY; OSM box -79.8,40.45,-71.8,45.05, then python3 tollnode_ways.py NY.
  3. Then rebuild NJ and PA (nj_state.py, pa_state.py): NY writes osm/ny_not_toll_nodes.json (zone exits, excluded roads, interior gantries) and their untied lists must leave them out.

Rules written into the builder (re-check after an OSM refresh)

The chain every state shares

Hosts: geo1 (192.168.50.220) holds the sources, builders, drafts, map and API; b100 (192.168.50.14) is the test client. All times are Eastern.

whatwhere (geo1 unless said)
sources list/home/geo1/maps/toll/NY/urls.txt (name <tab> URL)
archived sources/home/geo1/maps/toll/NY/sources/<name>/<YYYY-MM-DD>/ (file + meta.json: url, fetched, sha256)
builder/home/geo1/system/handbuilt/ny_state.py; shared code toll_common.py
OpenStreetMap inputs/home/geo1/system/handbuilt/osm/ny_* (cut from /home/geo1/maps/osm/us-latest.osm.pbf)
outputdraft /srv/toll/draft/NY/ (the builders write here); published /srv/toll/NY/ (copied from the draft by promote.py publish). The map and the API read the published page, or the draft while it is listed for review
toll enginesource /home/geo1/maps/web/tolls.js, served copy /srv/maps/tolls.js (the API runs the served copy)
API/home/geo1/maps/api/server.mjs on 127.0.0.1:8090 behind nginx /api/; pid in logs/test.pid
regression tripsb100: ~/apitest/site/cases.json, runner ~/apitest/run.py, browser check ~/apitest/browser.mjs

1. Refresh a source

  1. Fetch into a new dated folder: python3 /home/geo1/system/handbuilt/fetch_list.py NY [name ...] (no names = every line of urls.txt). A new source: add a line to urls.txt first, then fetch it by name.
  2. A site that refuses geo1 (HTTP 403) or scripts: fetch it on b100 in headless Chrome with node ~/apitest/fetch_b100.mjs <out> <name>=<url> ..., then rsync -a <out>/ geo1@192.168.50.220:/home/geo1/maps/toll/NY/sources/. Its meta.json records that it came from b100.
  3. Compare the new file with the previous dated one (diff, pdftotext -layout for PDFs). Same content: nothing to do. Changed amounts or a new effective date: rebuild (step 2) and update the expected amounts of the affected regression trips from the operator's own figures.

1b. The corpus (NJ, PA, VA start from it; DE is published from it)

python3 /home/geo1/maps/toll/bin/tollup.py NY update fetches the adapter's sources (bin/adapters/ny.py), stores a document only when its content changes, writes one rate file per version under /home/geo1/maps/toll/NY/rates/ and appends every price change to history.csv (every run to runs.log). TOLL_WEB=/home/geo1/maps/toll/corpus python3 /home/geo1/maps/toll/bin/publish.py NY writes the corpus /home/geo1/maps/toll/corpus/NY from it (DE: plain publish.py DE writes /srv/toll/DE). Never hand-edit either. Then rebuild the draft (step 2) so it picks up the new rates.

2. Rebuild

3. Load it into the API and test from b100

  1. The API reads the toll pages and tolls.js when it starts. Restart it: cd /home/geo1/maps/api && kill $(cat logs/test.pid); (nohup /home/geo1/maps/node/bin/node server.mjs > logs/server.log 2>&1 & echo $! > logs/test.pid) (it is started by hand, not a service).
  2. From b100 only: python3 ~/apitest/run.py ~/apitest/site/cases.json. Every trip must be OK. Add a trip for every rate or rule you change, with the amount taken from the operator's own source.
  3. Engine change (tolls.js): edit /home/geo1/maps/web/tolls.js, check with /home/geo1/maps/node/bin/node --check, copy to /srv/maps/tolls.js with sudo install -o www-data -g www-data -m 644, restart the API, run the trips.

4. OpenStreetMap refresh (all states at once)

The builders match toll points to the OSM way ids the router drives, so the extracts here must come from the same us-latest.osm.pbf the router (Valhalla, /home/geo1/maps/valhalla_data) was built from (now 2026-09-27). New OSM data means: rebuild the router tiles, then for each state cut the box, rebuild its OSM inputs and run the full chain, then compare untied_toll_nodes.csv and the estimated positions below. The box for NY and the cutting commands are in the state's procedure above; the toll-node and way index comes from python3 tollnode_ways.py NY.

5. Publish

A rebuild writes the draft (/srv/toll/draft/NY); the published page (/srv/toll/NY) does not change. python3 /home/geo1/maps/toll/bin/promote.py review NY lists the draft for review: the map and the API then read it instead of the published page. Run the regression trips from b100. After approval, python3 /home/geo1/maps/toll/bin/promote.py publish NY copies the draft to /srv/toll/NY (the previous page is kept under /home/geo1/maps/toll/NY/published/<time>/) and takes it off the review list. After a change, update the coverage line for NY in the API page (/api.html, generator /home/geo1/maps/api/doc/api_page.py) and rebuild this page: python3 /home/geo1/system/handbuilt/maintain_pages.py NY.

Sources (21)

Each fetch is kept in its own dated folder under /home/geo1/maps/toll/NY/sources/<name>/; the builder always reads the newest one, so a new fetch takes effect at the next rebuild and the old one stays for comparison.

sourcefetched (newest)fetches kepthowlisted in urls.txtrows using it
mta_cbd_about
https://www.mta.info/fares-tolls/tolls/congestion-relief-zone/about
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes
mta_cbd_charges
https://www.mta.info/document/138931
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes521
mta_crossing_charges
https://www.mta.info/document/180046
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes210
mta_vehicle_types
https://www.mta.info/fares-tolls/tolls/vehicle-types
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes
ncba_ezpass
https://www.ncbaabb.com/ezpass/
2026-10-091fetch_list.pyyes
ncba_home
https://www.ncbaabb.com/
2026-10-091fetch_list.pyyes
ncba_toll_schedule_2024
https://www.ncbaabb.com/wp-content/uploads/2024-Toll-Rate-Schedule.pdf
2026-10-091fetch_list.pyyes12
nfbc_tolls
https://www.niagarafallsbridges.com/crossing-info/toll-cost-vehicle-definitions
2026-10-091fetch_list.pyyes
nysba_toll_history
https://www.nysba.ny.gov/toll-history
2026-10-091fetch_list.pyyes
nysba_toll_rates
https://www.nysba.ny.gov/toll-rates
2026-10-091fetch_list.pyyes85
panynj_truckers_guide_2026
https://www.panynj.gov/content/dam/bridges-tunnels/truckers-guides/Truckers%20Guide_Eng_Ap
2026-10-091fetch_list.pyyes
peacebridge_tolls
https://www.peacebridge.com/?p=708
2026-10-091fetch_list.pyyes
thruway_2024_non_ny_tbm_cpm
https://www.thruway.ny.gov/sites/default/files/2025-07/2024-non-ny-tbm-cpm.pdf
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes3708
thruway_2024_ny_ezpass_cpm
https://www.thruway.ny.gov/sites/default/files/2025-07/2024-ny-e-zpass-cpm.pdf
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes3714
thruway_2026_incentive_charts
https://www.thruway.ny.gov/sites/default/files/2025-12/2026-incentive-tolls-charts.pdf
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes218
thruway_classes
https://www.thruway.ny.gov/travelers/classes
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes
thruway_gantry_api
https://webdataapi.thruway.ny.gov/api/data/gantrylocations/xml
2026-10-091fetch_list.pyyes
thruway_gantry_rate_charts
https://www.thruway.ny.gov/sites/default/files/2025-07/gantry-rate-toll-charts.pdf
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes135
thruway_gmmcb_toll_charts
https://www.thruway.ny.gov/sites/default/files/2025-07/gmmcb-toll-charts.pdf
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes21
thruway_interchanges
https://data.ny.gov/api/views/7jkf-259w/rows.csv?accessType=DOWNLOAD
2026-10-091fetch_list.pyyes
thruway_schedules_page
https://www.thruway.ny.gov/travelers/tolls/schedules
2026-10-081b100 (192.168.50.14), headless Chrome: the site refuses geo1 / scripts (HTTP 403)yes

Facilities (24)

idfacilityoperatorpointsrate / trip rowseffective dates in the rowssource
NY-NYSTA-S5New York State Thruway - Segment 5New York State Thruway Authority1727722024-01-01thruway_2024_ny_ezpass_cpm
NY-NYSTA-S4New York State Thruway - Segment 4New York State Thruway Authority1223762024-01-01thruway_2024_ny_ezpass_cpm
NY-NYSTA-S3New York State Thruway - Segment 3New York State Thruway Authority42162024-01-01thruway_2024_ny_ezpass_cpm
NY-NYSTA-S2New York State Thruway - Segment 2New York State Thruway Authority65402024-01-01thruway_2024_ny_ezpass_cpm
NY-NYSTA-S1New York State Thruway - Segment 1New York State Thruway Authority53602024-01-01thruway_2024_ny_ezpass_cpm
NY-NYSTA-S6New York State Thruway - Segment 6New York State Thruway Authority810082024-01-01thruway_2024_ny_ezpass_cpm
NY-NYSTA-FXNew York State Thruway - fixed tollsNew York State Thruway Authority163522024-01-01, 2026-01-01thruway_gantry_rate_charts
NY-NYSTA-GMMCBGovernor Mario M. Cuomo BridgeNew York State Thruway Authority21642026-01-01thruway_gmmcb_toll_charts
NY-MTA-VNBVerrazzano-Narrows BridgeMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-MTA-RFKRobert F. Kennedy BridgeMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-MTA-BWBBronx-Whitestone BridgeMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-MTA-TNBThrogs Neck BridgeMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-MTA-QMTQueens Midtown TunnelMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-MTA-HLCHugh L. Carey TunnelMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-MTA-HHBHenry Hudson BridgeMetropolitan Transportation Authority Bridges and Tunnels (TBTA)192026-01-04mta_crossing_charges
NY-MTA-MPBMarine Parkway-Gil Hodges Memorial BridgeMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-MTA-CBBCross Bay Veterans Memorial BridgeMetropolitan Transportation Authority Bridges and Tunnels (TBTA)1242026-01-04mta_crossing_charges
NY-NYSBA-BMBear Mountain BridgeNew York State Bridge Authority116(none printed)nysba_toll_rates
NY-NYSBA-NBNewburgh-Beacon BridgeNew York State Bridge Authority116(none printed)nysba_toll_rates
NY-NYSBA-MHMid-Hudson BridgeNew York State Bridge Authority116(none printed)nysba_toll_rates
NY-NYSBA-KRKingston-Rhinecliff BridgeNew York State Bridge Authority116(none printed)nysba_toll_rates
NY-NYSBA-RVWRip Van Winkle BridgeNew York State Bridge Authority116(none printed)nysba_toll_rates
NY-MTA-CBDCongestion Relief Zone (CBD toll)Metropolitan Transportation Authority Bridges and Tunnels (TBTA)415202025-01-05mta_cbd_charges
NY-NCBAAtlantic Beach BridgeNassau County Bridge Authority1112024ncba_toll_schedule_2024

Positions placed by estimate (3): re-check when OpenStreetMap or the operator changes

pointfacilitylocationplaced onwhy
NY-MTA-CBD-39Congestion Relief Zone (CBD toll)Queens Midtown Tunnel entry gantry (estimated): westbound I-495 at the Manhattan portalthe tunnel's westbound exit lanesR3 estimate: no MTA detection gantry is mapped at the Queens Midtown Tunnel's Manhattan portal; the tunnel exits inside the zone (E 37th St), so every westbound pass is an entry: a booth on each westbound lane just past the tunnel's gantries
NY-MTA-CBD-40Congestion Relief Zone (CBD toll)Queens Midtown Tunnel exit gantry (estimated): eastbound I-495 approach lanes at the Manhattan portalthe tunnel's eastbound approach lanes (I-495 and the two ramps from the street grid; the reversible lane is left out: its direction changes)R3 estimate: the Queens Midtown Tunnel credit applies 'If entering or exiting the CBD via' it; no zone gantry is mapped on its Manhattan approach, so a booth on each approach lane upstream of the tunnel's own gantries marks a pass leaving the zone through it
NY-MTA-CBD-41Congestion Relief Zone (CBD toll)Hugh L. Carey Tunnel exit gantry (estimated): southbound approach at the Manhattan portalthe tunnel's one southbound approach lane, after the West Street and Battery Place ramps joinR3 estimate: the Hugh L. Carey Tunnel credit applies 'If entering or exiting the CBD via' it; no zone gantry is mapped on its Manhattan approach, so a booth on each approach lane upstream of the tunnel's own gantries marks a pass leaving the zone through it

Decisions by rule

R1: 70, R2b: 54, R3: 3, direction: 10, not: 56, on: 1, plan: 3 (all in decisions.csv).

Open gaps (0)

None.

Untied OSM toll nodes: 259

Toll booths / gantries mapped in OpenStreetMap on or near this state's roads that no toll point claims; a route through one lists it under unpriced. After an OSM refresh, look at new ones here (untied_toll_nodes.csv): a new gantry on a priced road means a point is missing.

Regression trips for NY (42)

Run from b100 (never on geo1): python3 ~/apitest/run.py ~/apitest/site/cases.json. Every trip must come back OK; a changed amount is either a rate change (update the expected amount from the operator's own source) or a fault.

tripexpected
NY Thruway Stewart/I-84 -> Saugerties (17 -> 20), NJ E-ZPass = Non-NY table $3.38$3.38
NY Thruway Harriman -> Albany (16 -> 23), NJ E-ZPass = Non-NY table $7.94$7.94
NY Thruway Utica area 31 -> Schenectady 26, NJ E-ZPass ($5.80)$5.80
NY Cuomo Bridge southbound Nyack -> Tarrytown, NJ E-ZPass ($12.69)$12.69
NY Cuomo Bridge northbound Tarrytown -> Nyack (no toll)$0.00
NY Verrazzano Staten Island -> Brooklyn, NJ E-ZPass = non-NYCSC ($12.03)$12.03
NY Verrazzano Brooklyn -> Staten Island, Tolls by Mail ($12.03)$12.03
NY Bear Mountain Bridge eastbound, NJ E-ZPass ($1.65)$1.65
NY Bear Mountain Bridge westbound (no toll)$0.00
NY Mid-Hudson Bridge eastbound Highland -> Poughkeepsie, Tolls by Mail ($2.15)$2.15
NY Weehawken -> Midtown 08:30 Wed, NJ E-ZPass: Lincoln Tunnel peak $16.79 + zone $9.00 - $3.00 Lincoln credit$22.79
NY Weehawken -> Midtown 23:00 Wed, Tolls by Mail: Lincoln $23.30 + zone overnight $3.30$26.60
NY Upper West Side -> Midtown 10:00 Wed via 60th St, NJ E-ZPass: zone peak $9.00$9.00
NY Midtown -> Upper West Side 10:00 Wed (leaving the zone: no charge)$0.00
NY Thruway Stewart/I-84 -> Saugerties (17 -> 20), NY E-ZPass table $1.93$1.93
NY Thruway Harriman -> Albany (16 -> 23), NY E-ZPass table $4.54$4.54
NY Thruway Utica area 31 -> Schenectady 26, NY E-ZPass table $3.31$3.31
NY Cuomo Bridge southbound Nyack -> Tarrytown, NY E-ZPass ($7.25)$7.25
NY Verrazzano Staten Island -> Brooklyn, NY E-ZPass NYCSC ($7.46)$7.46
NY Bear Mountain Bridge eastbound, NY E-ZPass ($1.65)$1.65
NY Upper West Side -> Midtown 10:00 Wed, NY E-ZPass: zone peak $9.00$9.00
NY LIC -> Midtown via Queens-Midtown Tunnel, Wed 10:00, E-ZPass: tunnel $12.03 + zone $9.00 - $1.50 QMT credit$19.53
NY LIC -> Midtown via QMT, Wed 23:00, E-ZPass: tunnel $12.03 + zone overnight $2.25$14.28
NY LIC -> Midtown via QMT, Wed 10:00, bill by mail: tunnel $12.03 + zone $13.50 (no credit for mail)$25.53
NY Midtown -> LIC via QMT (pass began inside the zone): tunnel $12.03 only$12.03
NY Upper West Side -> LIC: enters at 60th St, exits via QMT: zone $9.00 - $1.50 exit credit + tunnel $12.03$19.53
NY Red Hook -> Tribeca via Hugh L. Carey Tunnel (Trinity Pl ramp), E-ZPass: tunnel $12.03 + zone $9.00 - $1.50$19.53
NY Red Hook -> Battery Park City via Carey + West St (excluded roadway): tunnel $12.03 only$12.03
NY Tribeca -> Red Hook via Carey (pass began inside the zone): tunnel $12.03 only$12.03
NY RFK Bronx -> Queens, E-ZPass non-NY: $12.03 (Bronx-leg gantries)$12.03
NY RFK Manhattan -> Bronx over the Manhattan span: $12.03 once$12.03
NY RFK Bronx -> Manhattan over the Manhattan span: $12.03 once$12.03
NY Atlantic Beach Bridge Lawrence -> Atlantic Beach, car, E-ZPass ($3.00, NCBA 2024 Toll Rate Schedule)$3.00
NY Atlantic Beach Bridge Atlantic Beach -> Lawrence, car, NY E-ZPass ($3.00; collected each passage, direction not stated)$3.00
NY Atlantic Beach Bridge, car, cash ($4.00)$4.00
NY Atlantic Beach Bridge, car + trailer (3 axles), cash ($4.00)$4.00
NY Atlantic Beach Bridge, 2-axle truck, E-ZPass ($8.00)$8.00
NY Atlantic Beach Bridge, 3-axle truck, cash ($12.00)$12.00
NY Atlantic Beach Bridge, 5-axle truck, E-ZPass ($16.00, 4+ axles)$16.00
NY Atlantic Beach Bridge, 2-axle bus, cash ($4.00 'All Buses - (CASH)')$4.00
NY Thruway 16 -> 23, account_ny = NY E-ZPass table $4.54$4.54
NY Thruway 16 -> 23, account_ca (not accepted) = Tolls by Mail $7.94$7.94