mrkeyoor.com_
Wed 23 Sept 00:33 UTC
npmUtilsupdated 22 Sept 2026

exif-parser review

exif-parser 0.1.12 synchronously reads EXIF metadata from JPEG bytes supplied as a Node Buffer or browser ArrayBuffer. It returns named tags by default, turns GPS coordinates and several rational values into ordinary numbers, finds JPEG dimensions, and can extract the thumbnail stored inside an EXIF block. The current npm version dates from July 2017; its release commit fixed a logic error that had left the tags result empty. It does not alter metadata, rotate pixels from the Orientation tag, or understand HEIC, AVIF, WebP, PNG, XMP, and IPTC. Use it as a narrow JPEG reader, not as a general image inspection layer.

Verdict

exif-parser 0.1.12 installed in 0.6 seconds as one 1 MB package in our sandbox, but it has no types and its published code has not changed since 2017. Keep it for a tested JPEG-only compatibility path; choose exifr or ExifReader for new uploads, broader formats, or maintained browser packaging.

We installed it

Lab card: what happened when we installed exif-parserScreenshot of exif-parser documentation
Install✓ · 0.6s1 package on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browser7.6 KBgzipped (21.4 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does exif-parser install cleanly?

Yes. In a fresh container with an empty cache, npm install exif-parser finished in 0.6s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does exif-parser add to a browser bundle?

7.6 KB gzipped (21.4 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does exif-parser work with both ESM and CommonJS?

Yes. Both import 'exif-parser' and require('exif-parser') worked in Node 22 in our run. The package is published as CommonJS.

Does exif-parser include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

exif-parser or exifr: which should you use?

exifr: Use it for a maintained reader with wider image-format coverage, modern module entry points, and TypeScript declarations. exif-parser 0.1.12 installed in 0.6 seconds as one 1 MB package in our sandbox, but it has no types and its published code has not changed since 2017.

When should you not use exif-parser?

Uploads may be HEIC, AVIF, WebP, PNG, RAW, or standalone TIFF. The parser enters a JPEG section reader first and throws when JPEG markers are absent.

API stability4/5Version 0.1.12 has kept the same factory, parser flags, `tags` result, image-size method, and thumbnail methods since July 2017. That makes pinned legacy behavior predictable. The stability comes from inactivity rather than a stated compatibility policy, and default value simplification changes raw fractions, GPS arrays, and selected date strings into different JavaScript values. Those conversions are part of the observable API.
Docs3/5The README names the accepted Buffer and ArrayBuffer inputs, describes partial JPEG fetching, says `parse()` throws, lists all six parser flags, and explains tags, dimensions, thumbnail detection, extraction, and the separate browser bundle. It leaves important boundaries implicit: standalone TIFF and newer containers do not work, timezone-less EXIF dates are simplified, Orientation is not applied, and TIFF thumbnail sizing follows a JPEG-only code path.
Maintenance1/5npm 0.1.12 was published on July 19, 2017. GitHub shows no releases, a latest commit in November 2020, a repository push timestamp in September 2021, and 14 open issues and pull requests. The repository is unarchived, yet two 2018 commits addressing browser DataView offset failures were never published. There is no current package release covering module exports, declarations, newer formats, or bounds handling.
Ecosystem3/5npm counted 3,973,185 downloads from August 18 through August 24, 2026, and GitHub reports 229 stars. The zero-dependency Buffer API remains common in older dependency trees. New image systems have more suitable choices: exifr and ExifReader cover additional metadata and containers, Sharp combines reading with image processing, and piexifjs handles writes. exif-parser has no plugin system or maintained type package of its own.

Use it if

  • An existing Node service expects version 0.1.12's synchronous `create(buffer).parse()` result shape.
  • The input is known JPEG data and the required fields are common EXIF tags, dimensions, GPS coordinates, or a JPEG thumbnail.
  • A browser path can supply an ArrayBuffer and can carry a small CommonJS parser through its own bundler.
  • You can catch parse errors, cap the input, and treat every returned tag as untrusted metadata.
Skip it if

Setup reality

We installed exif-parser 0.1.12 in a fresh Node 22 Bookworm sandbox in 0.6 seconds. It left one package and 1 MB on disk, with 468 KB unpacked. npm audit reported 0 known vulnerabilities. The package has 0 direct and 0 peer dependencies, no declared license in its npm metadata, and no TypeScript declarations. It is CommonJS without an exports map; require() and ESM import both worked in our checks.

No credentials, config file, or native build step is involved. In Node, call create() with a Buffer. Browser code must pass an ArrayBuffer; if the bytes arrive as a Uint8Array view, slice its exact byteOffset and byteLength before parsing. The npm package has no browser field or ready-made global bundle. The README points script-tag users to a separate bundle repository, while our esbuild test produced 21.4 KB minified and 7.6 KB gzipped.

parse() runs synchronously and throws on invalid JPEG data. Truncation, bad offsets, or unsupported TIFF field layouts can also surface as Buffer or DataView range errors, so wrap every untrusted upload in a size limit and a try/catch. Defaults read tags and image size, resolve known numeric tag IDs to names, omit pointer and binary fields, and simplify several value shapes. Disable those conversions when the original arrays or numeric tag IDs matter.

The README proposes fetching the first 65,635 bytes because a JPEG EXIF section is limited to 65,535 bytes and normally appears near the beginning. A server may ignore the Range header and return the whole image, so check the response. Thumbnail helpers need the thumbnail bytes to be present in the supplied prefix. hasThumbnail() can identify JPEG or TIFF thumbnails, but getThumbnailSize() passes the thumbnail through the JPEG parser and should be limited to image/jpeg.

Patterns

Read tags from a Node Buffer parse-node-buffer

const fs = require('node:fs')
const ExifParser = require('exif-parser')

const bytes = fs.readFileSync('photo.jpg')
let result
try {
  result = ExifParser.create(bytes).parse()
} catch (error) {
  throw new Error(`Bad JPEG metadata: ${error.message}`)
}
console.log(result.tags)

Version 0.1.12 parses synchronously and throws for invalid or truncated JPEG data. Bound the file size before reading an upload into memory.

Read a browser File parse-browser-file

async function readExif(file) {
  const bytes = await file.arrayBuffer()
  return ExifParser.create(bytes).parse()
}

const result = await readExif(input.files[0])

The README's script-tag build exposes `ExifParser` as a global. That bundle lives outside the npm package.

Pass only a Uint8Array view's bytes slice-typed-array

function exactBuffer(view) {
  return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength)
}

const result = ExifParser.create(exactBuffer(view)).parse()

Passing `view.buffer` directly includes unrelated bytes when the view begins after offset 0 or ends before the backing ArrayBuffer.

Fetch the documented JPEG prefix fetch-exif-prefix

const response = await fetch(url, { headers: { Range: 'bytes=0-65634' } })
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const bytes = await response.arrayBuffer()
const result = ExifParser.create(bytes).parse()

The README uses a 65,635-byte prefix. Check the response length because servers can ignore Range and send the full object.

Read camera and orientation tags read-camera-fields

const { Make, Model, Orientation, DateTimeOriginal } = result.tags
console.log({
  camera: [Make, Model].filter(Boolean).join(' '),
  orientation: Orientation || 1,
  capturedAt: DateTimeOriginal
})

Tags may be absent or forged. The parser reports Orientation but does not rotate pixels, and default date simplification may change the value type.

Handle simplified GPS coordinates read-gps

const latitude = result.tags.GPSLatitude
const longitude = result.tags.GPSLongitude
if (Number.isFinite(latitude) && Number.isFinite(longitude)) {
  console.log({ latitude, longitude })
}

Default simplification combines DMS values with N, S, E, or W references. GPS fields reveal location and need an explicit retention policy.

Read JPEG dimensions without decoding pixels read-dimensions

const result = ExifParser.create(bytes)
  .enableReturnTags(false)
  .enableImageSize(true)
  .parse()

console.log(result.getImageSize())

The method returns dimensions only when the supplied bytes contain a supported JPEG start-of-frame section. It does not validate the pixel stream.

Keep fractions and date strings unsimplified preserve-value-shapes

const result = ExifParser.create(bytes)
  .enableSimpleValues(false)
  .parse()

console.log(result.tags.ExposureTime, result.tags.DateTimeOriginal)

Disabling simple values preserves arrays and strings instead of applying GPS, fraction, and date conversions.

Return numeric tag records use-numeric-tags

const result = ExifParser.create(bytes)
  .enableTagNames(false)
  .parse()

for (const tag of result.tags) {
  console.log(tag.section, tag.type, tag.value)
}

This bypasses the package's fixed name table. Callers must interpret each section and numeric tag ID themselves.

Extract an embedded JPEG thumbnail extract-jpeg-thumbnail

const fs = require('node:fs')

if (result.hasThumbnail('image/jpeg')) {
  const thumbnail = result.getThumbnailBuffer()
  fs.writeFileSync('thumbnail.jpg', thumbnail)
}

The original buffer must include the complete thumbnail bytes. Validate the extracted JPEG before serving or processing it.

Inspect JPEG thumbnail dimensions read-thumbnail-size

if (result.hasThumbnail('image/jpeg')) {
  const size = result.getThumbnailSize()
  if (size) console.log(size.width, size.height)
}

Check specifically for `image/jpeg`; `getThumbnailSize()` invokes the JPEG section parser even though EXIF can carry a TIFF thumbnail.

Expose binary EXIF fields include-binary-tags

const result = ExifParser.create(bytes)
  .enableBinaryFields(true)
  .parse()

Binary values are Buffers in Node and ArrayBuffers in browsers. Leave them disabled unless a known field requires its raw bytes.

Alternatives

PackageRegistryPick it when
exifrnpmUse it for a maintained reader with wider image-format coverage, modern module entry points, and TypeScript declarations.
exifreadernpmUse it when EXIF must be read alongside IPTC, XMP, ICC, PNG, WebP, HEIC, and other metadata families.
sharpnpmUse it when metadata inspection belongs in a Node pipeline that also rotates, resizes, converts, or strips images.
piexifjsnpmUse it when a JPEG workflow needs to modify or remove EXIF fields as well as read them.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.