Gathering detailed insights and metrics for exifreader
Gathering detailed insights and metrics for exifreader
Gathering detailed insights and metrics for exifreader
Gathering detailed insights and metrics for exifreader
npm install exifreader
Typescript
Module System
Node Version
NPM Version
4.31.1: Keywords type fix
Updated on Jun 17, 2025
4.31.0: Better FieldOfView calculation, new tag FocalLength35efl
Updated on May 27, 2025
4.30.1: Uncaught type error fix
Updated on May 08, 2025
4.30.0: Pentax MakerNote tags
Updated on May 01, 2025
4.29.0: Rounded aperture value
Updated on Apr 21, 2025
4.28.1: Types for composite tags
Updated on Apr 09, 2025
JavaScript (98.15%)
TypeScript (1.4%)
Dockerfile (0.45%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MPL-2.0 License
882 Stars
607 Commits
95 Forks
13 Watchers
6 Branches
22 Contributors
Updated on Jul 13, 2025
Latest Version
4.31.0
Package Id
exifreader@4.31.0
Unpacked Size
826.14 kB
Size
195.43 kB
File Count
68
NPM Version
10.8.2
Node Version
20.17.0
Published on
May 27, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
23
1
ExifReader is a JavaScript library that parses image files and extracts the metadata. It can also extract an embedded thumbnail. It can be used either in a browser or from Node. Supports JPEG, TIFF, PNG, HEIC, WebP, and GIF files with Exif, IPTC, XMP, ICC, and MPF metadata (depending on file type).
ExifReader is highly and easily configurable and the resulting bundle can be as small as ~4 KiB (gzipped) if you're only interested in a few tags (e.g. date and/or GPS values).
ExifReader supports module formats ESM, AMD, CommonJS, and globals and can therefore easily be used from Webpack, RequireJS, Browserify, Node etc.
You can try it out on the examples site.
Support table
File type | Exif | IPTC | XMP | ICC | MPF | Photoshop | MakerNote | Thumbnail | Image details |
---|---|---|---|---|---|---|---|---|---|
JPEG | yes | yes | yes | yes | yes | some* | some** | yes | yes |
TIFF | yes | yes | yes | yes | ??? | some* | some** | N/A | N/A |
PNG | yes | yes | yes | yes | ??? | ??? | some** | no | yes |
HEIC/HEIF | yes | no | yes | yes | ??? | ??? | some** | yes | no |
AVIF | yes | no | yes | yes | ??? | ??? | some** | yes | no |
WebP | yes | no | yes | yes | ??? | ??? | some** | yes | yes |
GIF | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | yes |
MakerNote
= Manufacturers' proprietary MakerNote tags.Image details
= image width, height, etc. read from image header.N/A
= The feature is not applicable to this file type.???
= may be supported in any file type using Exif but it has only been tested
on JPEGs.*
= A draft implementation of Photoshop tags have been added with
ClippingPathName
and PathInformation
currently supported. Photoshop tags
are very different from other tags and need a lot of extra code so they have
deliberately not been fully implemented. File an issue if there is something
you think should really be supported.**
= Some of the Canon-specific and Pentax-specific tags have been added.
File an issue if you think something more should be supported.If you're missing something that you think should be supported, file an issue with an attached example image and I'll see what I can do.
Notes for exif-js users
If you come here from the popular but now dead exif-js package, please let me know if you're missing anything from it and I will try to help you. Some notes:
Monetary support is not necessary for me to continue working on this, but in case you like this library and want to support its development you are very welcome to click the button below. You can also use GitHub's sponsor feature on the right-hand side on the repository's main page.
Easiest is through npm or Bower:
1npm install exifreader --save
1bower install exifreader --save
If you want to clone the git repository instead:
1git clone git@github.com:mattiasw/ExifReader.git 2cd ExifReader 3npm install
After that, the transpiled, concatenated and minified ES5 file will be in the
dist
folder together with a sourcemap file.
Type definitions for TypeScript are included in the package.
NOTE: See React Native instructions below.
ES module syntax:
1import ExifReader from 'exifreader';
NOTE: TypeScript/Angular seems to sometimes have problems when using the default export. If you're seeing issues, use this syntax instead:
1import * as ExifReader from 'exifreader';
CommonJS/Node modules:
1const ExifReader = require('exifreader');
AMD modules:
1requirejs(['/path/to/exif-reader.js'], function (ExifReader) { 2 ... 3});
script
tag:
1<script src="/path/to/exif-reader.js"></script>
There are two ways to load the tags. Either have ExifReader do the loading of the image file, or load the file yourself first and pass in the file buffer. The main difference is that the first one is asynchronous and the second one is synchronous unless specified.
1const tags = await ExifReader.load(file); 2const imageDate = tags['DateTimeOriginal'].description; 3const unprocessedTagValue = tags['DateTimeOriginal'].value;
Where file
is one of
1const tags = ExifReader.load(fileBuffer);
Where fileBuffer
is one of
ArrayBuffer
or SharedArrayBuffer
(browser, Node.js)Buffer
(Node.js)See the examples site for more directions on how to use the library.
Some tags need to be parsed asynchronously. Currently this is the case for some
PNG tags, more specifically compressed tags in zTXt, iTXt, and iCCP chunks. To
enable this, either use the asynchronous API mentioned above or pass in async: true
in the options parameter:
1const tags = await ExifReader.load(file); 2// or 3const tags = await ExifReader.load(fileBuffer, {async: true});
For the compressed tags to work, the environment needs to support the Compression Streams API.
The reason for having an option to enable this is to not break backwards compatibility. This will probably be the default in the next major version.
By default, Exif, IPTC and XMP tags are grouped together. This means that if
e.g. Orientation
exists in both Exif and XMP, the first value (Exif) will be
overwritten by the second (XMP). If you need to separate between these values,
pass in an options object with the property expanded
set to true
:
1const tags = ExifReader.load(fileBuffer, {expanded: true});
When using for example Node.js or a web worker, there is no native
DOMParser
available for parsing the XML used in XMP. In this case – and if XMP support is
important to you – you can pass in a third-party parser to ExifReader. The
parser needs to have a parseFromString
method with the same API as the
parseFromString
from the DOMParser Web
API.
Two libraries have been tested,
xmldom
and
linkedom
, but more might work if
they follow the spec.
Here is an example using xmldom
:
1import {DOMParser, onErrorStopParsing} from '@xmldom/xmldom'; 2// ... 3const tags = ExifReader.load(fileBuffer, {domParser: new DOMParser({onError: onErrorStopParsing})});
The onError
option is needed to avoid a seemingly infinite loop for some
XMLs. Unfortunately linkedom
has
the same problem but does not have this option and will therefore get stuck on
these XMLs. If this happens to you, switch to xmldom
and pass in the onError
option. (NOTE: The native DOMParser
that a web browser uses does not seem to
have this issue.)
Import ExifReader like this:
1import ExifReader from './node_modules/exifreader/src/exif-reader.js';
Make sure to update the path to point to where your node_modules
is located.
For local files on the device you need to load the file yourself first, then pass in the buffer to ExifReader. Here is a template from user @hungdev:
1import RNFS from 'react-native-fs'; 2import {decode} from 'base64-arraybuffer'; 3import ExifReader from 'exifreader'; 4 5const b64Buffer = await RNFS.readFile('YOUR IMAGE URI', 'base64') // Where the URI looks like this: "file:///path/to/image/IMG_0123.HEIC" 6const fileBuffer = decode(b64Buffer) 7const tags = ExifReader.load(fileBuffer, {expanded: true});
If you're having trouble getting the GPS location, see this comment and thread and the GPS section below for more details.
If you only want to read part of the image file you can use the length
option:
1const tags = await ExifReader.load(filename, {length: 128 * 1024});
This will load only the first 128 KiB of the file. This could be useful if you know the metadata is located at the beginning of the file. Just be aware that it's common for the metadata to be spread out over a larger area so please try it out on your set of files to know if it's suitable for your situation.
Note that this option only works when ExifReader handles the loading of the
file. If e.g. a JavaScript File object from a form file field is passed into
ExifReader the whole file will already have been loaded into memory and it's too
late. More specifically the length option will work for 1. local files when
running through Node.js, and 2. remote files when passing a URL. For the latter,
if doing this through a web browser, make sure the remote server is either on
the same origin (domain) as your script or that the server is passing correct
CORS headers, specifically allowing the Range
header.
Tags that are unknown, either because they have been excluded by making a custom build or they are yet to be added into ExifReader, are by default not included in the output. If you need to see them there is an option that can be passed in:
1const tags = ExifReader.load(fileBuffer, {includeUnknown: true});
If you discover an unknown tag that should be handled by ExifReader, please reach out by filing an issue.
If expanded: true
is specified in the options, there will be a gps
group.
This group currently contains Latitude
, Longitude
, and Altitude
which will
be negative for values that are south of the equator, west of the IRM, or below
sealevel. These are often more convenient values for regular use. For some
elaboration or if you need the original values, see Notes below.
If you're having trouble getting the GPS values on Android (and possibly also
IOS) and are using a type="file"
input to upload the image, make sure you are
not setting accept="image/*"
on the input element. Apparently
setting the accept
attribute to this value will strip the GPS
values.
The thumbnail and its details will be accessible through tags['Thumbnail']
.
There is information about e.g. width and height, and the thumbnail image data
is stored in tags['Thumbnail'].image
.
How you use it is going to depend on your environment. For a web browser you can
either use the raw byte data in tags['Thumbnail'].image
and use it the way you
want, or you can use the helper property tags['Thumbnail'].base64
that is a
base64 representation of the image. It can be used for a data URI like this:
1const tags = ExifReader.load(fileBuffer); 2imageElement.src = 'data:image/jpg;base64,' + tags['Thumbnail'].base64;
If you're using node, you can store it as a new file like this:
1const fs = require('fs'); 2const tags = ExifReader.load(fileBuffer); 3fs.writeFileSync('/path/to/new/thumbnail.jpg', Buffer.from(tags['Thumbnail'].image));
See the examples site for more details.
The most important step will be to use a custom build so please do that.
If you are using Webpack 4 or lower and are only targeting web browsers, make
sure to add this to your Webpack config (probably the webpack.config.js
file):
1 node: { 2 Buffer: false 3 }
Buffer
is only used in Node.js but if Webpack sees a reference to it it will
include a Buffer
shim for browsers. This configuration will stop Webpack from
doing that. Webpack 5 does this automatically.
Configuring a custom build can reduce the bundle size significantly.
NOTE 1: This functionality is in beta but should work fine. Please file an issue if you're having problems or ideas on how to make it better.
NOTE 2: This only changes the built file (exifreader/dist/exif-reader.js
),
not the source code. That means it's not possible to use the ES module (from the
src
folder) or any tree shaking to get the benefit of a custom build. Tree
shaking will actually have close to no effect at all here so don't rely on it.
This is for npm and yarn users that use the built file. To specify what functionality you want you can either use include pattern (start with an empty set and include) or exclude pattern (start with full functionality and exclude). If an include pattern is set, excludes will not be used.
For Exif and IPTC it's also possible to specify which tags you're interested in. Those tag groups have huge dictionaries of tags and you may not be interested in all of them. (Note that it's not possible to specify tags to exclude.)
The configuration is added to your project's package.json
file.
Example 1: Only include JPEG files and Exif tags (this makes the bundle almost half the size of the full one (non-gzipped)):
1"exifreader": { 2 "include": { 3 "jpeg": true, 4 "exif": true 5 } 6}
Example 2: Only include TIFF files, and the Exif DateTime
tag and the GPS
tags (resulting bundle will be ~19 % of a gzipped full build):
1"exifreader": { 2 "include": { 3 "tiff": true, 4 "exif": [ 5 "DateTime", 6 "GPSLatitude", 7 "GPSLatitudeRef", 8 "GPSLongitude", 9 "GPSLongitudeRef", 10 "GPSAltitude", 11 "GPSAltitudeRef" 12 ] 13 } 14}
Example 3: Exclude XMP tags:
1"exifreader": { 2 "exclude": { 3 "xmp": true 4 } 5}
Then, if you didn't install ExifReader yet, run npm install exifreader
.
Otherwise you have to rebuild the library:
1npm rebuild exifreader
With yarn 2+:
From my experience, you need a node_modules
folder for the rebuild command to
work with yarn 2+. If you don't have it, run yarn config set nodeLinker node-modules
and then run yarn
. Then you can try to rebuild:
1yarn rebuild exifreader
With yarn 1:
1yarn add exifreader
After that the new bundle is here: node_modules/exifreader/dist/exif-reader.js
If you are using vite
, you will need to clear the dependency cache
after a rebuild.
If you're using the include pattern config, remember to include everything you
want to use. If you want xmp
and don't specify any file types, you will get
"Invalid image format", and if you specify jpeg
but don't mention any tag
types no tags will be found.
Possible modules to include or exclude:
Module | Description |
---|---|
jpeg | JPEG images. |
tiff | TIFF images. |
png | PNG images. |
heic | HEIC/HEIF images. |
webp | WebP images. |
gif | GIF images. |
file | JPEG file details: image width, height etc. |
jfif | JFIF details in JPEG files: resolution, thumbnail etc. |
png_file | PNG file details: image width, height etc. |
exif | Regular Exif tags. If excluded, will also exclude mpf , photoshop and thumbnail . For TIFF files, excluding this will also exclude IPTC, XMP, and ICC. |
iptc | IPTC tags. |
xmp | XMP tags. |
icc | ICC color profile tags. |
mpf | Multi-picture Format tags. |
photoshop | Photoshop tags. |
maker_notes | Proprietary camera maker tags. Needs exif . |
thumbnail | Thumbnail image. Needs exif . |
GPSLatitude
, GPSLongitude
) and the
reference value (GPSLatitudeRef
, GPSLongitudeRef
). Use the references to
know whether the coordinate is north/south and east/west. Often you will see
north and east represented as positive values, and south and west
represented as negative values (e.g. in Google Maps). This setup is also
used for the altitude using GPSAltitude
and GPSAltitudeRef
where the
latter specifies if it's above sea level (positive) or below sea level
(negative). If you don't want to calculate the final values yourself, see
the section on GPS for pre-calculated ones.Orientation
value of 3
will have Rotate 180
in the description
property. If you would like more XMP tags to have a processed description,
please file an issue or create a pull request.description
property of tags can change in a minor update. If you
want to process a tag's value somehow, use the value
property to be sure
nothing breaks between updates.The library makes use of the DataView API which is supported in Chrome 9+, Firefox 15+, Internet Explorer 10+, Edge, Safari 5.1+, Opera 12.1+. For Node.js at least version 10 is required if you want to parse XMP tags, otherwise earlier versions will also work.
Full HTML example pages and a Node.js example are located on the examples site.
length
option to only read
the beginning of the file. See above for more details on that.Questions, bug reports, suggestions, and pull requests are very much welcome. If you've been using another Exif package, you probably have some good insights on what's missing in this one. See CONTRIBUTING.md for more info.
This project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
ExifReader uses the Mozilla Public License 2.0 (MPL-2.0). In short that means you can use this library in your project (open- or closed-source) as long as you mention the use of ExifReader and make any changes to ExifReader code available if you would to distribute your project. But please read the full license text to make sure your specific case is covered.
A selection of notable changes.
async: true
in options
parameter to enable. Works in environments that support the
Compression Streams API.length
to only read the first length
bytes of the file.Regions
(see issue #129
for more details).value
on
rational tags). Rational values are now kept in their original
numerator/denominator pair instead of being calculated into a float.
In addition to .value
on rational tags some descriptions have also
changed into better ones, e.g. ExposureTime now looks like 1/200
instead of 0.005
.No vulnerabilities found.
Reason
30 commit(s) and 6 issue activity found in the last 90 days -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
2 existing vulnerabilities detected
Details
Reason
Found 1/7 approved changesets -- score normalized to 1
Reason
dependency not pinned by hash detected -- score normalized to 1
Details
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
Project has not signed or included provenance with any releases.
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More