SteelheadTracker

Columbia Basin Steelhead Migration Dashboard
Loading...
Data: DART, PTAGIS, USGS
Hot Rivers & River Conditions are WIP
Season insight — updated Aug 24, 2026
This year's early-returning "A-run" (one-salt) steelhead have largely not shown up. PIT-tagged smolts from the 2025 outmigration are returning at roughly 1/20th of last year's same-date pace — and the drop is uniform across every region and origin we track (hatchery and wild; Clearwater, Grande Ronde/Imnaha, Salmon/Snake, Mid- and Upper Columbia), which points to ocean survival, not a data artifact. It explains why the overall Bonneville count ranks 16th of the last 17 years to date. The two-salt fish returning now went to sea a year earlier and are arriving in normal proportions. See Fish Biology → Ocean Age for the breakdown, and the run-timing forecast wedge for where the season may land.

Hot Rivers — Which Runs Are Surging?

Rivers ranked by run progress. Expected fish from v117p expansion model (PIT tags × expansion factor at reference dam). Unique PIT tags at river entry gates multiplied by the same expansion factor gives estimated arrivals. % remaining = fish still to come. Rivers with high % remaining approaching their peak date are "hottest."
Loading chart...

Daily Passage — Bonneville Dam Live

Day-of-year overlay across all years. Toggle between raw counts, 7-day, and 14-day averages.
Loading chart...

Daily Passage — Lower Granite Dam Live

Last dam on the Snake River before fish enter tributaries. Key indicator for Clearwater, Salmon, and Grande Ronde runs.
Loading chart...

Annual Run Size by Dam

Total steelhead passage at each major Columbia & Snake River dam, 2010–present.
Loading chart...

Daily Passage by Destination River New

Expanded PIT×DART estimates of daily steelhead passage at each dam, broken down by destination river basin. Select a year and toggle rivers on/off.
Loading chart...
How these bars are calculated. Each day, the dam window counts every steelhead that passes — that's a physical census. Separately, some of those fish carry PIT tags whose later detections tell us which river they ended up in. The day's census is split between rivers in proportion to that day's resolved tags: river's fish = (river's tags that day ÷ all resolved tags that day) × the day's dam count. Hover any bar to see its share. The census is exact; the split is an estimate, and days with few tags carry wide uncertainty — early-season days especially. Fish whose tags never resolve to a river are not shown here.

Cumulative Run Timing — Bonneville

What percentage of the run has passed by each day? Compare this year's pace to historical.
Loading chart...

Cumulative Run Timing — Lower Granite

Snake River cumulative timing. Fish arrive later here than at Bonneville due to upstream travel.
Loading chart...

Run Timing by River New

How these fish numbers are built, in three steps: (1) DART counts every steelhead passing Bonneville each day — a census, no modelling. (2) PIT-tagged fish detected at each river's entry arrays give that river's share of the run. (3) The daily dam count is multiplied by that share, so the curve height is real fish and the split between rivers is the estimate. What this cannot tell you: rivers entered through tributary arrays rather than a mainstem site are detected less often, so their share is understated — the Clearwater is seen at its own gate only ~35% of the time. Rivers below 0.5% of the run are omitted unless they are major drainages. Use the dropdown to isolate one river.
Loading chart...

Basin Destination by Year New

Estimated adult steelhead by destination river. Each river's share of resolved PIT tags is multiplied by the DART dam count; every bar segment is labelled with the tags behind it and the expansion each tag carries, so you can see which numbers rest on thin evidence.
Other/Unknown is not a river — it is the part of the dam count we could not attribute, typically 30–35% of the run. Years where the tags cannot support a breakdown at all (MY2011: 63 tags for 414,057 fish) are shown entirely as unresolved rather than split. Rivers entering the Columbia below Bonneville are excluded here: those fish never passed the dam being counted. Yakima uses the Prosser Dam census rather than the model, because a count beats an estimate.
* Method note: these totals now sum to the full dam count, matching how Idaho Fish and Game publish theirs. Fish we cannot attribute to a river are distributed across drainages rather than left in a separate bucket — previously about 35–45% of the run sat unassigned, which made every river read roughly 40% low. Hatchery and wild are allocated separately (they have different basin distributions) and recombined using the fin-clip census at the dam.
Loading chart...

Sub-Basin Destinations New

Where fish go inside each drainage — Lochsa, Selway, Lemhi, Pahsimeroi and the rest. Hatchery and wild are allocated separately, because they go to different places. Hatchery production concentrates at facilities like Dworshak; wild fish spread through the headwater tributaries. Pooling them (our PIT sample is 93–99% hatchery, the run is 52–72%) made every sub-basin number a hatchery number. Hatchery shares come from PIT tags; wild shares from Stark's published sub-basin returns; the mix from the DART fin-clip census.
Loading chart...

Ocean Age × Origin (IDFG Style) New

Stacked by ocean age (winters at sea) and origin, in IDFG's reporting format. Dark = hatchery, light = wild.
How ocean age is known: only for fish PIT-tagged as juveniles, where we know the year they went to sea. Ocean age = (return migration year − smolt migration year) − 1. A fish tagged as an adult has no smolt year, so its ocean age is unknowable and it is excluded. How origin is known: a juvenile tagged at a hatchery is hatchery; one tagged at a screw trap or in-river is wild. The bar heights come from the DART dam census; only the split between age and origin classes is estimated from tags.
Read the labels before trusting a bar. Each shows the PIT tags behind it. Early years rest on very few — MY2013 has 118 tags for 232,795 fish (~1,970 fish per tag), where 2024–25 has 5,154 (~35 per tag). A bar built on a hundred tags can invert if a handful of fish are classified differently; the recent years are solid.
Loading chart...

Returning Adults by Drainage Beta

Estimated adult returns by drainage, by calendar year. Same method as Basin Destination — uses each river's PIT tag share × DART dam count. Includes 3yr/5yr/10yr average reference lines. Hover for expansion details.
Loading chart...

Hatchery vs Wild — Bonneville

How origin is determined: counted at the dam window, not from PIT tags. Wild fish have an intact adipose fin; hatchery fish are fin-clipped before release, so counters can tell them apart on sight. DART publishes Steelhead = the total run and Wild Steelhead = the wild subset of that total, so hatchery = total − wild. (Adding the two columns double-counts every wild fish and inflates the run 28–40%; that error reached this site once before.) This is a census of every fish that passed, not an estimate.
Loading chart...

Hatchery vs Wild — Lower Granite

Snake River hatchery vs wild origin split at Lower Granite Dam.
Loading chart...

Adult Length Distribution

Size distribution of returning adults by river system. Bimodal peaks often correspond to 1-ocean vs 2-ocean fish.
Loading chart...

Adult Length vs Ocean Age New

Each point is one fish. Circles = paired juvenile+adult measurements, orange diamonds = adult measurement only (age estimated from length). Click any fish to open its full tag history on PTAGIS. Colored by ocean class. Use dropdown to filter by river.
Loading chart...

Columbia Basin Migration Flows New

Sankey diagram showing steelhead flow through Columbia & Snake River dams to destination rivers. DART dam counts set the total flow at each dam. Toggle between two methods for splitting fish to destination rivers. View dam map →
Loading Sankey data...

Per-River Migration Flows New

Follow fish from Bonneville through each dam on the route to a specific river, with sub-basin breakdowns where available. Tracks by migration year (July–June cohorts) so fish passing BON in summer and arriving at upper tributaries months later are counted together. Toggle between Detected (raw PIT counts) and Expanded (weighted by tagging rates) modes. Hover for details.
Loading river Sankey data...

Entry-Gate Detections by River New

Daily PIT tag detections at river entry gates across all years. Average row at top shows typical timing; individual years below. Select a river to see its entry-gate detections over time. Toggle years on/off.
Years:
Loading heatmap...

Migration Timing by Year — Dams New

Daily DART passage counts across all years at major dams. Each row is a year, each column is a day of year. Shows how migration timing shifts year to year — earlier runs, later peaks, and unusual patterns.
Years:
Loading heatmap...

PTAGIS Detection Sites — Map

Official PTAGIS map of PIT tag interrogation and MRR sites across the Columbia Basin. Use the built-in search (magnifying glass icon) to find sites by code or name. Cross-reference site codes with the heatmap above.

Streamflow & Fish Detections Live

USGS observed streamflow (last 30 days) with daily PIT fish entries. Shows flow conditions at key gauges alongside fish arrival patterns. Dual y-axis: discharge (cfs) on left, fish detections on right.

Select a river and click "Load Flow Data" to fetch live streamflow

Data from USGS National Water Information System (waterservices.usgs.gov)

How to Use This Dashboard

Every chart on this site is interactive. Here are the key things you can do:

Legend Controls:

  • Single click a year or river in the legend to hide/show it
  • Double-click a legend entry to isolate it — only that item will show. Double-click again to restore all.

Dropdowns & Buttons:

  • Use dropdown menus (top-left of charts) to switch between views — dam totals, individual rivers, smoothing modes, etc.
  • On the Run Timing chart, the dropdown lets you pick Bonneville (BON) or Lower Granite (LWG) scaling and filter to individual rivers. Single-river views color lines by year so you can compare across seasons.

Chart Interaction:

  • Hover over any line or bar to see detailed data — fish counts, percentages, PIT tag info, expansion factors
  • Click + drag to zoom into a region. Double-click to reset zoom.
  • Use the camera icon in the top-right toolbar to download a chart as a PNG image

What Can You Learn?

  • Dam Passage — Compare this year's daily fish counts to historical patterns. Is the run early, late, big, or small?
  • Run Timing — Track cumulative progress: what % of the run has passed? How does each river compare?
  • Destinations — Where are the fish going? Basin destination shows estimated returns per river system. The "expansion" number in the hover tells you how many real fish each PIT tag represents (e.g., 5x means each tagged fish represents ~5 total fish). This is calculated by dividing the DART dam count by the number of PIT tags detected.
  • Fish Biology — Size distributions and ocean age help understand the population mix (1-ocean vs 2-ocean fish).
  • Migration Flows — Sankey diagram traces fish from Bonneville through each dam to their final destination river. Width of each band = number of fish. Use the year dropdown to compare across years.
  • Fish Biology — Click any fish dot on the growth scatter to open its full tag history on PTAGIS. Orange diamond markers are fish with a single adult measurement only (age is estimated from length).

Dam & Site Abbreviations:

BON = Bonneville TDA = The Dalles JDA = John Day MCN = McNary IHR = Ice Harbor LMN = Lower Monumental LGS = Little Goose LWG = Lower Granite PRD = Priest Rapids WAN = Wanapum RIS = Rock Island RRH = Rocky Reach WEL = Wells

About SteelheadTracker

SteelheadTracker is a passion project that tracks Columbia Basin steelhead migration using publicly available data from DART (Columbia Basin Research), PTAGIS (PIT Tag Information System), USGS (water data), and NOAA (weather forecasts).

Data Sources:

  • DART — Dam passage counts (daily & annual)
  • PTAGIS — PIT tag detection data (individual fish tracking)
  • PTAGIS Detection Sites — PIT tag monitoring site locations and metadata
  • USGS — Streamflow and water temperature
  • NOAA — River flow forecasts
  • Columbia Basin Dam Map — Overview of dam locations in the basin

How It Works:

A build script fetches the latest DART dam passage data and combines it with precomputed PIT tag analysis (basin destinations, growth, origin classification). Charts are rendered client-side using Plotly.js — no server computation needed.

Methodology Notes:

  • Destination and returning adult charts use calendar year for consistency with dam passage data
  • H/W classification from DART uses the "Wild Steelhead" column reported by dam operators
  • PIT-based H/W uses release site information to infer hatchery vs wild origin
  • Basin destinations are based on post-dam PIT detections at tributary sites
  • Charts marked "Beta" are under active development and may have known limitations

A Note on the Numbers:

Estimating how many steelhead are heading to each river turns out to be a genuinely hard problem. We only have PIT tags in a fraction of the fish, and those tags have to be expanded out — multiplied by factors that can range from 10× to 50× or more — to estimate total basin destinations. I've done my best to cross-reference DART dam counts, PIT tag detections, and the v117p expansion model to produce something useful, but I'm not a fisheries biologist with access to better data, and I'm not a mathematical genius. There are real limitations here: expansion factors vary by year and river, some rivers have very few PIT tags to work with, and the entry gate detection efficiency isn't 100%. If you spot something that looks off, or you have expertise that could improve the methodology, I'd love to hear from you. This is the best I could do with what's publicly available — and I think it's still pretty useful.

Contact & Support:

Built by Paul Van Valkenburg — paul.vanvalkenburg@gmail.com

If you find this project useful and want to support its development — whether that means buying me a beer, helping me take my wife out to dinner to repair the damage this site has done to my marriage, or just keeping the servers running — any contribution is appreciated. Donate via PayPal

Want to receive updates? Email me to join the mailing list.

What's New

August 2026 — a big update, and an honest one.

This site ran without updates from late February to late August 2026. During that gap I found several real problems in my own numbers, and rather than patch quietly I rebuilt the validation from the ground up. Everything below is now checked against independent published sources — IDFG and ODFW's own figures, dam-by-dam censuses — before it ships, and a hard gate blocks the site from deploying if the numbers fail.

Fixed in this update:

  • Eight charts restored — the live build had silently switched to an older script and dropped them (including the calendar/migration-year toggles).
  • Ocean age corrected — 1-salt fish were dramatically undercounted by a day-counting bug; ages now derive from migration years and are validated against length distributions.
  • One number per quantity — the cumulative run-timing chart and the destinations chart could disagree about the same river by 5x. Both now read from a single source; if you compare them, they match.
  • Hatchery and wild estimated separately — the PIT-tag sample is 93–99% hatchery while the actual run is 52–72% hatchery. Pooling them made every destination estimate quietly a hatchery estimate. Wild allocation now uses wild sources and the dam fin-clip census.
  • New: sub-basin destinations — Lochsa, Selway, Lemhi, Pahsimeroi and 18 more tributaries, from the separate hatchery/wild allocation.
  • Confidence intervals repaired — some intervals didn't contain their own estimate after a late rescaling step; whiskers now wrap every bar.
  • Impossible destinations removed — basins that enter the Columbia below Bonneville can't be destinations for fish counted at Bonneville.
  • 2011 shown as unresolved — only 63 usable tags exist for that migration year, which cannot support per-river estimates. The bar now says so instead of pretending.
  • Detection data current through August 23, 2026.

Known limitations, plainly:

  • Snake River mainstem estimates lean on a model prior (very few tags resolve there) — treat them as indicative, not measured.
  • The current migration year is always partial until the run completes in May.
  • Tag-expansion methodology is under active validation against IDFG's published numbers; expect refinements, and expect me to say so here when they land.

Site build v134l · August 23, 2026