mrkeyoor.com_
Sat 08 Aug 21:58 UTC
npmUtilsupdated 08 Aug 2026

exif-parser

exif-parser is a synchronous, dependency-free JPEG metadata reader for Node buffers and browser ArrayBuffers. It walks JPEG sections, decodes EXIF TIFF directories, resolves a fixed table of tag names, simplifies rational values, converts GPS coordinates and selected dates, reports JPEG dimensions, and can locate or extract an embedded EXIF thumbnail. It reads metadata only; it does not decode pixels, apply orientation, validate authenticity, remove privacy data, write tags, or support modern image containers.

Verdict

Keep exif-parser only for narrow, tested JPEG metadata paths that depend on its exact old output. For new upload, browser, or multi-format work, exifr or ExifReader provides a maintained surface and avoids several unreleased fixes and lossy conversion surprises.

API stability4/5The factory, chainable parser flags, result.tags shape, getImageSize, and thumbnail helpers have remained unchanged since the 0.1 series, and there are no dependencies to shift behavior. Existing callers can pin 0.1.12 confidently. The score stops short of five because stability comes from a frozen 2017 artifact, later browser offset fixes on the repository were not published, and several results depend on lossy defaults and environment-specific string decoding rather than a formally versioned schema.
Docs3/5The README explains Node and browser inputs, partial JPEG fetching, parse errors, every configuration flag, named versus numeric tags, image dimensions, thumbnail detection, thumbnail extraction, and the separate browser bundle. It does not clearly state that standalone TIFF and modern containers are unsupported, that date results are Unix seconds interpreted as UTC, that Orientation is not applied, that browser strings are decoded differently, that typed-array views are risky, or that getThumbnailSize assumes JPEG even when a TIFF thumbnail is detected.
Maintenance1/5npm 0.1.12 was published in July 2017. GitHub's latest default-branch commit returned by the API is a November 2020 npmignore change, the repository's push timestamp is September 2021, and 14 issues and pull requests remain open combined. The repository is not archived or deprecated, but fixes committed in 2018 for browser DataView offset errors never reached npm, while no releases address new containers, modern packaging, types, fuzzing, bounds hardening, or long-standing decoding limitations.
Ecosystem3/5The package recorded 3,735,486 downloads in the measured week and has 229 GitHub stars, showing substantial legacy and transitive use in Node image workflows. Its zero-dependency Buffer API and familiar tag object made it easy to embed. The active metadata ecosystem has moved toward exifr, ExifReader, and full pipelines such as Sharp, which cover more formats, metadata families, module systems, typings, and browser loading strategies; exif-parser has no plugin or integration layer of its own.

Use it if

  • You maintain an existing JPEG-only pipeline that already expects version 0.1.12's tag names and timestamp conversions
  • You need a small synchronous reader with no runtime dependencies and can catch failures from untrusted binary input
  • You only need common EXIF tags, JPEG dimensions, GPS coordinates, or an embedded JPEG thumbnail
  • You can pass a Node Buffer or browser ArrayBuffer and do not need streams, TypeScript declarations, writes, XMP, or IPTC
Skip it if

Setup reality

npm install exif-parser adds a CommonJS package with no runtime dependencies, peer requirements, native compilation, config, credentials, engines declaration, ESM exports, or TypeScript declarations. In Node, pass a Buffer; in a browser, pass a real ArrayBuffer. Typed-array views are not documented inputs, so slice the exact underlying byte range when a Uint8Array has a nonzero offset. create() detects the environment through ArrayBuffer and otherwise assumes Node Buffer methods. parse() is synchronous and can throw on non-JPEG data, truncated sections, invalid offsets, malformed TIFF headers, unsupported formats, and out-of-range DataView or Buffer reads. Treat every upload as hostile, cap input size, and catch errors. The README says fetching the first 65,635 bytes is enough because JPEG APP1 is limited to 65,535 bytes and appears near the start; that optimization is useful for EXIF, but a Range request can be ignored by a server and image dimensions or unusual layouts still deserve testing. Defaults resolve known tag ids to names, simplify singletons and rational pairs, convert GPS DMS to signed decimal degrees, interpret a few date strings as Unix seconds, read image dimensions, omit pointer and binary tags, and return all other tags. These conveniences are lossy. Disable simplification or name resolution when exact section and type ids matter. Browser users do not get a browser field or dist file from npm; the README sends them to a separate prebuilt-bundle repository or an old Makefile using Browserify and Uglify. Embedded thumbnails can be JPEG or TIFF according to hasThumbnail, but getThumbnailSize always invokes the JPEG section parser, so use it only for a JPEG thumbnail. Parsing metadata does not prove it is accurate or safe to display, and returned GPS fields are privacy-sensitive.

Patterns

Parse EXIF from a Node bufferparse-node-buffer

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

const buffer = fs.readFileSync('photo.jpg');
let result;
try {
  result = exif.create(buffer).parse();
} catch (error) {
  throw new Error(`Invalid or unsupported JPEG: ${error.message}`);
}
console.log(result.tags);

parse is synchronous and throws for malformed, truncated, or non-JPEG input. Cap upload sizes and reject errors rather than assuming every image-like file is parseable.

Parse a browser File as ArrayBufferparse-browser-file

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

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

The browser build is not included in the npm package; the README points to a separate bundle exposing the ExifParser global. A bundler can import the CommonJS package instead.

Pass the exact bytes from a Uint8Array viewparse-typed-array-slice

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

const result = exif.create(exactArrayBuffer(bytes)).parse();

Passing view.buffer directly includes unrelated leading or trailing bytes when byteOffset or byteLength does not cover the whole underlying buffer.

Request only the JPEG EXIF prefixfetch-jpeg-prefix

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

The 65,635-byte prefix follows the README's APP1 guidance. Servers may ignore Range and return the full file; verify response size and test image-size discovery on your camera corpus.

Read common named tags safelyread-common-tags

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

Tags can be absent or forged. DateTimeOriginal becomes Unix seconds under default simplification and timezone-less EXIF dates are interpreted as UTC.

Read simplified GPS coordinatesread-gps

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

Default simplification converts DMS arrays and N/S/E/W references to signed decimal degrees. Location metadata is sensitive personal data; minimize retention and access.

Read JPEG dimensions without decoding pixelsget-image-size

const parser = exif.create(buffer)
  .enableReturnTags(false)
  .enableImageSize(true);
const size = parser.parse().getImageSize();
if (size) console.log(size.width, size.height);

Dimensions come from a JPEG SOF section and may be undefined when none was found in the supplied bytes. This does not validate or decode the pixel payload.

Keep rational arrays and EXIF date stringspreserve-raw-values

const result = exif.create(buffer)
  .enableSimpleValues(false)
  .parse();

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

Disabling simplification preserves arrays and strings and avoids automatic GPS and date casting, but raw rational components are still read into JavaScript numbers.

Return section and numeric tag idsreturn-numeric-tags

const result = exif.create(buffer)
  .enableTagNames(false)
  .parse();

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

This avoids dependence on the package's fixed tag-name table. Section constants are internal numbers, and the returned entries do not include the original EXIF format id.

Return undefined-format binary fieldsinclude-binary-fields

const result = exif.create(buffer)
  .enableBinaryFields(true)
  .parse();

Binary format 7 values are Buffer objects in Node and ArrayBuffers in browsers. They can be large and opaque, so enable them only when a known tag requires the bytes.

Extract an embedded JPEG thumbnailextract-jpeg-thumbnail

const result = exif.create(buffer)
  .enableReturnTags(false)
  .parse();

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

The input buffer must contain the complete embedded thumbnail. Validate the extracted bytes before serving them; EXIF metadata and thumbnails are untrusted file content.

Read dimensions of a JPEG thumbnailread-thumbnail-size

if (result.hasThumbnail('image/jpeg')) {
  const size = result.getThumbnailSize();
  console.log(size && `${size.width}x${size.height}`);
}

Call getThumbnailSize only for image/jpeg. Although hasThumbnail can recognize image/tiff, the size method always parses the thumbnail as JPEG.

Alternatives

PackageRegistryPick it when
exifrnpmUse a maintained JavaScript reader with broader image formats, modern browser and Node APIs, chunked parsing, and richer metadata support
exifreadernpmUse a current cross-platform parser when EXIF, IPTC, XMP, ICC, PNG, WebP, HEIC, and other metadata families matter
sharpnpmUse a Node image pipeline when metadata inspection must be paired with rotation, resizing, conversion, or stripping, and native binaries are acceptable
piexifjsnpmUse a JPEG EXIF reader and writer when changing or removing tags is the actual requirement