Blog · 2026-05-19 · 9 min read

FITS headers every astrophotographer should know

Every sub-frame in your archive carries a metadata block — the FITS header — that records what was captured, with what gear, when, and at what exposure. Most of us never look at it. But it's the most reliable record of your imaging life, and once you know which keywords to look at, it's the basis of every analysis question worth asking.

What a FITS header actually is

FITS — Flexible Image Transport System — is the file format almost every cooled astrocam writes. Open one in a hex editor and the first thing you see, before any pixel data, is the header: a sequence of fixed-width 80-character "cards", each one a keyword/value pair plus an optional comment. The structure looks like this:

SIMPLE  =                    T / file does conform to FITS standard
BITPIX  =                   16 / number of bits per data pixel
NAXIS   =                    2 / number of data axes
NAXIS1  =                 6248 / length of data axis 1
NAXIS2  =                 4176 / length of data axis 2
OBJECT  = 'M31     '           / target name
FILTER  = 'Ha      '           / filter name
EXPTIME =              300.000 / exposure time in seconds
DATE-OBS= '2024-08-13T22:34:55.123' / UTC start of exposure
IMAGETYP= 'LIGHT   '           / frame type
END

Most images carry somewhere between 30 and 80 of these cards. Everything before the binary pixel data is plain ASCII text — you can in principle read it with any text editor, though the binary section after the END card will look like noise.

The point is: the header is not metadata you have to add. It's metadata your camera and sequencer already wrote, every frame, for years. The whole game is reading it.

How to view a header

You don't need to write code to inspect a header. Common ways in:

  • PixInsight — the FITS Header dialog (right-click any image in the workspace) shows every keyword and value.
  • FITS Liberator — free, cross-platform; shows the header alongside a stretchable preview.
  • AstroImageJ — popular in the variable-star / exoplanet community, exposes the full header in the FITS Editor.
  • astropy — Python; fits.getheader(path) returns the header as a dict-like object. Bundled fitsverify / fitsheader command-line tools also work.
  • Any text editor — the header is ASCII. Open the file and read the first few kilobytes. The binary section that follows will be unreadable, but the header itself is human-friendly.

The "must know" headers

If you only learn five header keywords, learn these. They are the spine of every integration-time, per-target, per-filter analysis you'll ever do.

HeaderTypeExampleWhat it tells you
OBJECTstringM31Target name as the sequencer wrote it. One of the most-edited fields — often hand-typed and inconsistent across sessions.
FILTERstringHaFilter name. Watch for naming drift: the same filter often appears as Ha, H-alpha, H_alpha, or Hydrogen depending on the sequencer and filter-wheel config.
EXPTIME (or EXPOSURE)number300.000Exposure in seconds for this single sub. The multiplier in every integration calculation.
DATE-OBSISO timestamp2024-08-13T22:34:55.123UTC timestamp of the exposure. The canonical "when".
IMAGETYPstringLIGHTSeparates lights from calibration frames. Do not include flats, darks, or biases in integration totals — they're not photons of your target.

These five keywords answer "how much time have I spent on what". Everything below adds nuance.

The "useful" headers (rig identification)

Once you want to ask "which scope earned me those hours" or "what gain was I running last winter", you reach for the rig keywords. These are the ones that turn a flat integration total into something you can attribute.

HeaderTypeExampleWhat it tells you
INSTRUMEstringASI2600MM ProCamera model. The most reliable rig fingerprint — usually written by the camera driver itself.
TELESCOPstringEsprit 100EDTelescope name. User-configurable in most sequencers, so it's only as reliable as how carefully you set it.
FOCALLENnumber (mm)550.0Focal length in millimetres. Useful for distinguishing native vs reducer/extender configurations on the same OTA.
XPIXSZ / YPIXSZnumber (μm)3.76Pixel size in microns. Combined with FOCALLEN gives image scale (arcsec/pixel) without guessing.
GAIN / OFFSETnumber100 / 50Sensor gain and offset settings. Critical when you've changed settings between sessions and are wondering why the stretches don't match.
CCD-TEMP / SET-TEMPnumber (°C)-10.0 / -10.0Actual and target sensor temperature. Mismatches often reveal cooling problems or warm-weather setpoint drift.

The "advanced" headers

These won't be in every file, but when they are, they unlock the more interesting questions.

HeaderTypeExampleWhat it tells you
OBJCTRA / OBJCTDECsexagesimal or degrees00 42 44.3 / +41 16 09Mount-reported RA/Dec at the time of exposure. Cross-checking these against the OBJECT name is the cheapest way to catch mis-labelled frames.
XBINNING / YBINNINGinteger1Sensor binning. A 2×2 binned frame has a different image scale and shouldn't be silently mixed into a 1×1 stack.
BAYERPATstringRGGBBayer pattern (OSC only). Tells debayering tools which colour order the sensor uses.
AIRMASSnumber1.34Atmospheric path length at the time of exposure. Often predictive of SNR — lower is better.
SWCREATE / CREATORstringN.I.N.A. 3.1Which sequencer wrote the file. Useful when you've used more than one — see NINA vs SGP vs APT integration tracking.

What FITS headers don't tell you reliably

The header is the best record you have, but it isn't a perfect one. A few honest caveats:

  • Target names aren't normalised. OBJECT might be M31, Andromeda, NGC 224, or andromeda galaxy across nights — all the same object. Any per-target total has to handle this.
  • Filter names drift. The same Ha filter often appears under several names across sequencers, filter wheels, and config edits. Ha, H-alpha, and Hydrogen are common variants.
  • Framing and rotation aren't in the basics. Two nights labelled M31 might have completely different framing or rotation. The header doesn't tell you "this is the same panel" — you need OBJCTRA/OBJCTDEC, or a plate solve, for that.
  • Older files are sparser. Early DSLR exports, manually captured frames, and files from older capture software often omit FILTER, INSTRUME, or even IMAGETYP. Don't assume every field exists.
  • "LIGHT" vs "LIGHT FRAME". IMAGETYP values aren't fully standardised. Some sequencers write LIGHT, others Light Frame, others nothing at all. A robust reader treats blanks generously.

What you can do with the headers

Once the headers are read and grouped, a long list of analytics that used to need a spreadsheet just works:

  • Per-target integration totals — group by OBJECT, sum EXPTIME.
  • Per-filter mix — see your L:R:G:B:Ha:OIII:SII split for each target.
  • Per-rig hours — group by INSTRUME / TELESCOP to compare productivity across scopes.
  • Time-of-night exposure trends — bucket by hour-of-night from DATE-OBS.
  • "First imaged" / "last imaged" timestamps per target — min/max of DATE-OBS.
  • Dropped-frame detection — gaps in DATE-OBS sequences flag clouded-out or rejected subs.

How Photon Ledger uses these

Photon Ledger walks your archive, reads each FITS header (only the header — pixel data is never touched), and writes the keyword/value pairs into a local database you can query. The "must know" five are the spine of every report; the "useful" rig fields drive the per-scope and per-camera views; the "advanced" fields surface where they exist and are politely ignored where they don't.

For the full keyword-by-keyword reference of what Photon Ledger reads and how each field is interpreted, see the FITS headers docs page.

Related reading

Download Photon Ledger   More posts