Tidal datums explained: which shoreline is the shoreline

Problem statement

The coastline on your map is a line somebody chose. In a place with a three-metre tide it could be drawn at high water, at low water, at mean sea level or at the chart datum, and those lines can be hundreds of metres apart across a gently sloping beach.

That is not a mapping subtlety; it is the whole basis of coastal measurement. Area of a tidal flat, length of shoreline, distance from a building to the sea, whether a parcel is above the foreshore โ€” all of them are answers to "at which datum?" and none of them is well defined without it.

This guide sets out the datums, shows real values from a tide gauge, and covers the conversion that trips people up most: tidal datums are local, and they are not heights in a national vertical datum.

Quick answer

A tidal datum is a statistical surface derived from observations over a 19-year epoch. From the NOAA station at Boston, Massachusetts, over the 1983โ€“2001 epoch:

datum metres above station datum
MHHW โ€” mean higher high water 4.205
MHW โ€” mean high water 4.071
MSL โ€” mean sea level 2.660
MTL โ€” mean tide level 2.624
MLW โ€” mean low water 1.178
MLLW โ€” mean lower low water 1.074
NAVD88 โ€” national vertical datum 2.752

The great diurnal range, MHHW โˆ’ MLLW, is 3.131 m. A shoreline drawn at MHHW and one drawn at MLLW are separated by whatever horizontal distance 3.1 m of elevation covers โ€” metres on a cliff, hundreds of metres on a flat.

Stack of tidal datums from mean higher high water down to mean lower low water with a national datum alongside.
Seven surfaces, all called "sea level" by somebody, spanning 3.1 m at one station.

Step-by-step solution

1. Know the datums you will meet

  • MHHW / MHW โ€” mean of the higher high waters, or of all high waters. The legal shoreline in much of the United States and the usual "coastline" on a topographic map.
  • MSL / MTL โ€” mean sea level over the epoch, and the midpoint of mean high and mean low water. Close but not identical.
  • MLW / MLLW โ€” the low-water equivalents. MLLW is the US chart datum.
  • LAT / Chart Datum โ€” lowest astronomical tide, the chart datum for most of the world outside the US.
  • Station datum โ€” an arbitrary local zero the gauge reports against.
  • NAVD88 / ODN / NAP โ€” national orthometric datums, defined geodetically rather than tidally.

2. Remember the epoch

A tidal datum is an average over a National Tidal Datum Epoch โ€” currently 1983โ€“2001 in the US. It is not the average of the last year, and it is updated infrequently, so published datums lag actual sea level where it is rising.

3. Do not assume a datum transfers between stations

Tidal datums are local because the tide is local. The range at one station tells you nothing about the range fifty kilometres along the coast, and a datum conversion published for one gauge does not apply at the next.

4. Convert through the geodetic datum, not by eye

Published datums include the offset to the national vertical datum โ€” NAVD88 is 2.752 m above station datum at Boston, MHHW is 4.205 m, so MHHW is 1.453 m above NAVD88. That is the number you need to combine a tidal surface with a LiDAR DTM.

5. Check the units

The NOAA metadata API returns datums in feet by default. The same request with units=metric returns metres. The values differ by a factor of 3.28 and both look plausible for a tide.

# default: feet
MHHW 13.800  MLLW 3.530  range 10.270
# units=metric
MHHW  4.205  MLLW 1.074  range  3.131

6. Choose the datum from the purpose

Navigation uses a low-water datum so charted depths are conservative. Legal boundaries usually use a high-water datum. Flood modelling uses a geodetic datum because that is what the terrain model is in. Habitat mapping uses whichever band it cares about.

7. Record the datum with every shoreline you produce

A coastline layer with no datum in its metadata is not reusable, and the difference between two vintages of the same coast is meaningless if they were drawn at different datums.

Scene showing a gently sloping beach with high water, mean sea level and low water shorelines at very different horizontal positions.
A 3.1 m vertical range on a 1% slope is 310 m of horizontal difference.

Code examples

Example 1 โ€” fetch the published datums, in the units you asked for

import urllib.request, json

def datums(station, metric=True):
    url = (f"https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/stations/"
           f"{station}/datums.json" + ("?units=metric" if metric else ""))
    with urllib.request.urlopen(url, timeout=60) as r:
        d = json.loads(r.read())
    return {"units": d.get("units"), "epoch": d.get("DatumAnalysisPeriod"),
            "values": {e["name"]: float(e["value"]) for e in d["datums"]}}

d = datums("8443970")
print(d["units"], d["epoch"])
v = d["values"]
print(f"great diurnal range MHHWโˆ’MLLW: {v['MHHW'] - v['MLLW']:.3f} m")
print(f"MHHW above NAVD88: {v['MHHW'] - v['NAVD88']:.3f} m")
meters ['01/01/1983 - 12/31/2001']
great diurnal range MHHWโˆ’MLLW: 3.131 m
MHHW above NAVD88: 1.453 m

Always read the units field back rather than trusting the parameter.

Example 2 โ€” check the published datums against observed water levels

import urllib.request, json, pandas as pd

def water_levels(station, begin, end, datum="MLLW"):
    url = (f"https://api.tidesandcurrents.noaa.gov/api/prod/datagetter"
           f"?product=water_level&application=spatialworkflow-docs"
           f"&begin_date={begin}&end_date={end}&datum={datum}&station={station}"
           f"&time_zone=gmt&units=metric&format=json")
    with urllib.request.urlopen(url, timeout=120) as r:
        raw = json.loads(r.read())
    df = pd.DataFrame(raw["data"])
    df["t"] = pd.to_datetime(df["t"], utc=True)
    df["v"] = pd.to_numeric(df["v"], errors="coerce")
    return df.dropna(subset=["v"]).set_index("t")

wl = water_levels("8443970", "20260101", "20260131")
daily = wl["v"].resample("1D")
print(f"{len(wl):,} six-minute observations")
print(f"above MLLW: min {wl.v.min():.2f} m, max {wl.v.max():.2f} m, "
      f"monthly range {wl.v.max() - wl.v.min():.2f} m")
print(f"mean daily high {daily.max().mean():.2f} m, mean daily low {daily.min().mean():.2f} m")
print(f"mean daily range {(daily.max() - daily.min()).mean():.2f} m, "
      f"spring/neap spread {(daily.max()-daily.min()).max() - (daily.max()-daily.min()).min():.2f} m")
7,440 six-minute observations
above MLLW: min -0.38 m, max 3.80 m, monthly range 4.18 m
mean daily high 3.24 m, mean daily low 0.04 m
mean daily range 3.19 m, spring/neap spread 1.82 m

The observed mean daily range of 3.19 m matches the published 3.131 m to within the month-to-month variation, which is the check worth doing before trusting either.

Example 3 โ€” convert a tidal surface into the datum your DTM uses

def to_geodetic(value_m, station_datums, from_datum, to_datum="NAVD88"):
    """Convert a height between datums published for the same station."""
    v = station_datums["values"]
    return value_m + v[from_datum] - v[to_datum]

# MHHW expressed in NAVD88, which is what a LiDAR DTM is usually in
mhhw_navd88 = to_geodetic(0.0, d, "MHHW", "NAVD88")
print(f"MHHW is {mhhw_navd88:+.3f} m NAVD88")
MHHW is +1.453 m NAVD88

This is the conversion that lets a tidal shoreline be cut from a terrain model: threshold the DTM at +1.453 m rather than at 0.

Explanation

Why tidal datums are statistical, not physical

There is no surface in the sea at "mean high water" โ€” it is the average of the observed high waters over a 19-year epoch, chosen because 18.6 years is the period of the lunar nodal cycle. That means the datum is only as good as the record, it is local to the gauge, and it drifts as sea level changes.

Why MSL and MTL differ

Mean sea level is the average of all observations; mean tide level is the midpoint of mean high water and mean low water. In a symmetric tide they coincide. Where the tide is asymmetric โ€” a fast flood and a slow ebb, or strong shallow-water harmonics โ€” they do not, and at Boston they differ by 0.036 m.

Why the shoreline moves so far horizontally

Horizontal displacement is the vertical range divided by the slope. A 3.1 m range on a beach sloping at 1% moves the waterline 310 m; on a 45ยฐ cliff it moves it 3.1 m. That is why tidal flats and estuaries are where datum choice dominates every area calculation, and cliffs are where it does not matter.

Why chart datum is not mean sea level

A chart exists so a mariner does not run aground. Charted depths are therefore referenced to a low-water surface โ€” LAT in most of the world, MLLW in the US โ€” so that the actual depth is almost always greater than charted. Using charted depths as if they were relative to mean sea level understates the water column by roughly half the tidal range.

Two panels showing the NOAA datums endpoint returning feet by default and metres when asked, with MHHW of 13.800 and 4.205 respectively.
A factor of 3.28 between two responses that are both plausible tide ranges.

Edge cases or notes

  • The epoch is not the present. Published datums lag current sea level where it is rising.
  • Datums are per station. Do not interpolate them across a complex coast.
  • The NOAA datums API defaults to feet. Read the units field back.
  • LAT and MLLW are different. They can differ by tens of centimetres.
  • Meteorological surge is not in a tidal datum. Storm levels exceed MHHW routinely.
  • Some places are effectively non-tidal. In the Baltic and the Mediterranean, wind dominates.
  • River gauges use other datums entirely. Do not mix them with coastal ones.
  • Record the datum in the metadata. A shoreline without one cannot be compared.

FAQ

What is a tidal datum?

A statistical surface derived from tide gauge observations over a 19-year epoch โ€” mean high water, mean sea level, mean lower low water and so on. It is local to the station.

Which datum is "the coastline"?

Whichever the producer chose. Topographic maps often use a high-water datum, nautical charts a low-water one, and flood models a geodetic datum.

How far apart are the high-water and low-water shorelines?

The vertical range divided by the slope. A 3.1 m range on a 1% beach is 310 m; on a cliff it is 3.1 m.

How do I convert a tidal datum to a national vertical datum?

Through the published offsets for the same station. At Boston, MHHW is 4.205 m and NAVD88 is 2.752 m above station datum, so MHHW is 1.453 m NAVD88.

Why does my datum value look ten times too big?

The NOAA metadata API returns feet unless you ask for metric. MHHW at Boston is 13.800 ft or 4.205 m.

Can I use one station's datums along the whole coast?

No. Tidal range varies rapidly along a coast, and a conversion published for one gauge does not apply at the next.