pytagger is a ID3 tag reader and writer implemented purely in Python. It supports all the current ID3 tag implementations including ID3v1, ID3v1.1, ID3v2.2, ID3v2.3 and ID3v2.4.

(Note: This project has now been renamed from pyid3v2 to pytagger to avoid conflict with existing projects.)


  • pytagger-0.5 (10 May 2006)

    • Fix APIC extraction alignment error for v2.2, v2.3, v2.4
    • Fix APIC insertion error for v2.2
    • Refactored APIC output and input.
    • Removed debugging print statement for ID3v2
  • pytagger-0.4 - (07 May 2005)

    • API!! Does not throw exception if unable to find ID3 tag. You should now check the output tag_exists() to determine whether it was able to find tags. This is done so that you can create new ID3 tags without requiring the old one to be there. Still throws exceptions if tags found is invalid or IOErrors occur.
    • Added BSD license to source files
    • Revamped ID3v1 to allow read and write
    • Removed mode parameter from ID3v1 and ID3v2 contructor. It now autodetects mode.
    • Added ability to write to new file rather than modify existing open file.
    • Many bugfixes.
    • Edited to use the new API.
  • pytagger-0.2 - (07 May 2004) Major Revision. Totally new API.

    • Renamed to pytagger to avoid confusion with pyid3.
    • totally refactored code
    • added epydoc and copious documentation
    • added some preliminary unit tests
    • run over with pylint to ensure correctness
    • changed to use proper encoding names
  • pyid3v2-0.1.1 - (03 Feb 2004) - Bugfix Release.

    • Fixed major problems with ID3v2.2 support, nicer handling of invalid tags, etc.
  • pyid3v2-0.1 - (14 Jan 2004) - Initial Release

Example Usage

As with most pieces of software, you'd probably want a sample script to show you how this works:

>>> from tagger import *
>>> mp3_tag = ID3v2('amazing.mp3')      
>>> mp3_tag.version

You can easily access the contents of frames:

>>> for frame in mp3_tag.frames:
...     print frame.fid 
>>> for frame in mp3_tag.frames:
...     if frame.fid == 'TT2':
...             print frame.strings
['Amazing', '']

You can add and remove frames from the ID3v2 tag:

>>> title_frame = mp3_tag.new_frame('TT2')
>>> title_frame.set_text('More Amazing') 
>>> title_frame.strings
['More Amazing']
>>> old_title_frame = [frame for frame in mp3_tag.frames if frame.fid == 'TT2'][0]
>>> mp3_tag.frames.remove(old_title_frame)
>>> mp3_tag.frames.append(title_frame)

You can commit your changes or discard them:

>>> mp3_tag.commit()
>>> mp3_tag.commit_to_file('newmusic.mp3')

And of course, you can also use it to read ID3v1 tags

>>> mp3_tag1 = ID3v1('amazing.mp3')
>>> print mp3_tag1.artist
'Alex Lloyd'

More complete documentation of the API can be found here.


I initially wanted to edit ID3 tags of MP3 files in python. The main reason being that there are alot of MP3s around with non-unicode (eg. Big5 or GB2312) tags floating around. Under Linux GNOME applications default to using UTF-8 and under Mac OS X, iTunes require you to use UTF-16 for non ASCII tags.

I attempted to build wrappers for libid3tag and id3lib. Both of them had pecularities that made it difficult to understand or wrap around with Python.

There are also other pure Python implementations for ID3v1 and ID3v2 but they are either read-only or only support particular version. So rather than learning someone else's code, I decided to have a go at writing my own parser.

The code you see now has gone through a number of refactoring cycles and is the easier to work with for text tags. There are other tags such as embedding objects, numbers and URLs. Those have been less aggressively tested.

pytagger is now the basis of a Mac OS X application I wrote called TagEncoder which allows you to drag and drop MP3s in order to convert their tags from one encoding to another.

However, there will definitely still be bugs left. Right now, it is still in beta state, so the API can change at any minute. If you are using this for any application, please let me know so we can discuss what sort of API is the most useful. I'm still inexperienced with designing APIs so I would appreciate any input.


  • Higher level wrapping of common tag manipulation functions such as changing artist, songname and album for ID3v2 tags so people don't need to remember what TIT and TIT2 is.
  • Regression testing
  • Better documentation.

You can reply to me about this on Twitter: