CLI tool
tinytag/tinytag avatar
tinytag/tinytag

tinytag reads audio tags and deliberately refuses to write them

Python library for reading audio file metadata

841 stars104 forksPythonMIT

At a glance

What is it?
tinytag is a MIT licensed, dependency free Python library that reads tags and audio properties from MP3, MP4, WAV, OGG, FLAC, WMA and AIFF files behind a single API, plus a command line mode that prints JSON. The project is explicit that writing metadata is out of scope and points you at Mutagen or pytaglib for that.
Who is it for?
tinytag suits any Python code that needs to label, sort, deduplicate or index a music library without pulling in a binary dependency, especially in a serverless or embedded context where a C extension would be unwelcome. It is the wrong tool if you need to write tags, since the project states that support for changing or writing metadata will not be added and names Mutagen and pytaglib as the alternatives.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A read-only metadata reader, on purpose

The scoping decision is stated at the top of the README and it is the right way to think about this library. Support for changing or writing metadata will not be added, and the project tells you to use another library such as Mutagen or pytaglib for that. Everything else follows from the choice. tinytag provides only the minimum needed for reading metadata and presents it in a simple format, so it can determine track number, total tracks, title, artist, album, year, duration and more, and nothing more. The features list reinforces the design with pure Python and no dependencies, a small and portable library, high code coverage, and a single API across all formats. The user is a developer building a catalogue view, a media indexer, a tagging dashboard or a file organiser, who wants a library that installs cleanly in a container and does not need a compiler or a system library to read a file.

Ten container formats behind one interface

The format coverage is where the value sits. tinytag handles ID3 v1, v1.1, v2.2, v2.3 and v2.4 for MP3, plus MP3, MP2 and MP1 streams. It reads MP4 containers carrying MPEG-4 Audio, AAC and ALAC, and WAVE and WAV files. OGG is covered in four flavours, FLAC, Opus, Speex and Vorbis, alongside native FLAC. ASF for WMA is there, and AIFF and AIFF-C round out the list. The point of the same API for all formats claim is that the calling code does not branch on the file extension, which is exactly the problem you hit when you write your own parser, or when you stack a different library per container. A single TinyTag.get call and a set of attributes covers the whole matrix, and the supported formats are exposed programmatically through the SUPPORTED_FILE_EXTENSIONS constant and the is_supported check.

Two calls and a set of attributes

The library API is two lines to start with:

python
from tinytag import TinyTag
tag: TinyTag = TinyTag.get('/some/music.mp3')

print(f'This track is by {tag.artist}.')
print(f'It is {tag.duration:.2f} seconds long.')

The common attributes always contain a single value, which is what makes them convenient. The file and audio properties are filename, filesize, bitdepth, bitrate in kbps, channels, duration in seconds, is_lossless, mime_type and samplerate. Two of those were added in tinytag 2.3.0, is_lossless and mime_type, so if you are reading a file and need to know whether it is lossless or what its MIME type is, that is new ground rather than something available in 2.0. The metadata fields are album, albumartist, artist, comment, composer, disc, disc_total, genre, title, track, track_total and year. Note the type of each one, since it matters downstream: year is a string rather than an integer, because tags in the wild write dates in many shapes, and disc and track are integers while albumartist and composer are strings that may be absent.

The command line prints the same data as JSON

tinytag can also be used directly from the command line, and the output is a JSON document rather than a human formatted table, which makes it usable in a shell pipeline:

console
$ python3 -m tinytag /some/music.mp3
{
  "filename": "/some/music.mp3",
  "filesize": 3243226,
  "mime_type": "audio/mpeg",
  "is_lossless": false,
  "duration": 173.52,
  "channels": 2,
  "bitrate": 128,
  "samplerate": 44100,
  "artist": [
    "artist name"
  ],
  "album": [
    "album name"
  ],
  "title": [
    "track name"
  ]
}

The interesting detail in that output is the shape of the text fields. The CLI emits artist, album, title, track, genre, year and comment as lists rather than as single strings, which is how multi-value tags are represented, and the library exposes the same values in the same structure. The README points to python3 -m tinytag --help for the full set of options, for example other output formats. The obvious use is a quick look at a file, and the less obvious one is a batch job where you shell out rather than import, which works because the output is machine readable.

other is where uncommon fields end up, as raw strings

Anything that is not one of the common attributes lives in the other dictionary. The README is precise about how to treat it. For additional values of the same field type, uncommon metadata fields, or metadata specific to certain file formats, use other, which is an OtherFields dictionary. A long list of field names is standardised in tinytag and optionally present when files provide such metadata, including barcode, bpm, catalog_number, conductor, copyright, director, encoded_by, encoder_settings, grouping, initial_key, isrc, language, license, lyricist, lyrics, media, movement, movement_name, movement_total, publisher, set_subtitle, show_movement, url, work and xmp. Additional names not on that list may be present but are format-specific and may change or disappear in future releases. The values are always strings and are not guaranteed to be valid, so a bpm containing non-numeric characters comes back as-is and converting it to an integer is your problem, as the README says. If a field you need is missing, the project asks you to open a feature request for discussion rather than adding it silently.

MIME types follow the RFCs, with two formats improvising

The MIME reporting is more careful than most libraries manage. tinytag may return the audio MIME types documented in the README, and when available a codecs parameter as described in the RFC 6381 standard is included. For standard codec values it points at RFC 6381 for audio/mp4, RFC 5334 and RFC 7845 for audio/ogg, and RFC 2361 for audio/wav. For the two formats with no official standard, it says so. There is no official standard for codecs values for the application/vnd.ms-asf and audio/aiff MIME types, so the most appropriate value provided by the format is used, which in the ASF case is the WAVE format tag and in the AIFF case the AIFF-C compression type such as alaw. The container values are audio/flac for FLAC, audio/mpeg for MP3 and its relatives, and audio/ogg with a codecs parameter of flac, opus, speex or vorbis depending on what is inside. The practical value is that a media server or a browser-facing API can set a correct Content-Type without a lookup table of its own.

Pure Python, typed, and carrying its deprecations openly

The engineering details are modest and mostly in your favour. The project is pure Python with no dependencies, supports Python 3.7 or higher, and ships type annotations, with a Typing :: Typed classifier in the metadata. The package is built with flit_core, and the classifiers claim support for CPython versions from 3.7 through 3.15, including a free threading resilient classification, and the development status is recorded as Production/Stable. The licence is MIT, with an SPDX header naming the tinytag contributors and a LICENSES/ directory alongside the LICENSE file. The repository also carries a fuzz/ directory, which is how a pure Python parser handles hostile input, a data/ directory for test assets, a SECURITY.md, and a CONTRIBUTING.md. Deprecations are flagged rather than hidden. The ignore_errors parameter of TinyTag.get() is obsolete as of tinytag 2.0.0 and will be removed in the future, as is the tag.audio_offset attribute, and the other dictionary has replaced the extra dictionary, which will also be removed in a future release. The release list shows 2.3.0 on 2026-07-30, 2.3.1 on 2026-08-30 and 2.3.2 on 2026-09-07, with the last push to the repository on 2026-10-14.

Editorial conclusion

tinytag suits any Python code that needs to label, sort, deduplicate or index a music library without pulling in a binary dependency, especially in a serverless or embedded context where a C extension would be unwelcome. It is the wrong tool if you need to write tags, since the project states that support for changing or writing metadata will not be added and names Mutagen and pytaglib as the alternatives. Verify first that the fields you need are exposed, because uncommon values land in the other dictionary as strings that are not guaranteed to be valid, and check that the format specific metadata you rely on is in the standardised list rather than in the format specific remainder that may change between releases.

Frequently asked questions

How do I install tinytag?

Run python3 -m pip install tinytag. The package is pure Python with no dependencies and supports Python 3.7 or higher, and it is published on PyPI as tinytag.

Can tinytag write or change metadata?

No, and the project states that support for changing or writing metadata will not be added. It points to Mutagen or pytaglib for writing, which is a deliberate design boundary rather than a missing feature.

Which audio formats does tinytag support?

ID3 v1, v1.1, v2.2, v2.3 and v2.4 with MP3, MP2 and MP1, MP4 with MPEG-4 Audio, AAC and ALAC, WAVE and WAV, OGG with FLAC, Opus, Speex and Vorbis, native FLAC, ASF for WMA, and AIFF and AIFF-C. The same API covers all of them.

How do I check whether tinytag supports a file?

Use the TinyTag.SUPPORTED_FILE_EXTENSIONS constant for the tuple of supported extensions, or the TinyTag.is_supported check with a path to test a single file.

Where do uncommon tags end up in tinytag?

In the other dictionary, which holds additional values of the same field type, uncommon fields and format specific metadata. Its values are always strings and are not guaranteed to be valid, so parsing them is your responsibility.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. tinytag/tinytag on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tinytag-tinytag.svg)](https://hysenlabs.com/projects/tinytag-tinytag)

Was this useful?