about_BrowserBookmarks

Where and how browser bookmarks are stored. This information is compiled partly from official sources, partly from Web resources, partly reverse-engineered.

If you’d rather not roll your own, grab my PSBrowserBookmarks module.

Internet Explorer

Internet Explorer stores its bookmarks, named ‘Favorites’, as separate files in a folder structure. The absolute path to the top folder is stored in the Favorites  value in the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders registry key. It can be a local or a network path (think folder redirection).

File structure

Each bookmark is a separate file with .url extension, the filename being the bookmark title displayed in the browser’s bookmarks menu. The inner structure of an .url file is that of an .ini file. The following parts are significant:

[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11

[InternetShortcut]
; for a web resource bookmark
IDList=
URL=https://msdn.microsoft.com/en-us/library/bb727085.aspx
IconFile=https://msdn.microsoft.com/favicon.ico
IconIndex=1
Roamed=-1

[MonitoredItem]
; for an RSS feed
FeedUrl=http://go.microsoft.com/fwlink/?LinkId=121315
IsLivePreview=true

[{5CBF2787-48CF-4208-B90E-EE5E5D420294}]
Prop21=31, <Description>

[{B9B4B3FC-2B51-4A42-B5D8-324146AFCF25}]
Prop5=31, <Notes>

[{64440492-4C8B-11D1-8B70-080036B11A03}]
Prop9=19,<star rating: 1 for *, 25 for **, 50 for ***, 75 for ****, 99 for *****>

The last three properties are taken from this support article. Any of the extended properties is not necessary for the Favorite functioning so the minimum contents of an .url file would be

[InternetShortcut]
URL=https://msdn.microsoft.com/en-us/library/bb727085.aspx

Besides .url files, which will open in any browser that is set as default, there is also the .website file extension which is specific to IE9+. The file structure is the same but there are some more complex (and cryptic) properties in it.

As of IE10 and Windows 10, editing a Favorite’s extended properties like star rating or notes doesn’t seem to be possible. Explorer will display those parameters correctly, however, if they have been set in the file.

Mozilla Firefox

Mozilla has been known to use file-based databases for a long time, starting with MORK back in the day and moving towards SQLite. In the current versions of Firefox, bookmarks and history are stored in the same SQLite database named places.sqlite. To locate this database, one needs to locate the Firefox profile first, then to consult the profile settings for the actual path to the file.

If no policies or settings have been configured, the default location of the places.sqlite is %APPDATA%\Mozila\Firefox\Profiles\<profile-id>\places.sqlite .

Database structure

There are three tables in the SQLite database that are immediately relevant to the bookmarks busines:

moz_bookmarks contains the entire bookmark tree. Whether we are looking at a bookmark, a folder or a separator line, is governed by the type field 1 being a bookmark, 2 a folder and 3 a separator. Each element contains the reference to its respective parent in the parent field and the order amongst its siblings in the position field which allows the browser to display them all as a tree. Further fields (besides title, obviously) that need to be set in this table are guid (has to be 12 characters long), dateAdded (Mozilla time, see below) and, in case of bookmarks, fk (foreign key) which is nothing less than the id field of the bookmark’s URI in the following table.

moz_places contains the actual bookmarked resources, i.e. URIs. The following fields need to be set in order to generate a valid bookmark: url (figures), rev_host (just the FQDN of the URI’s host in reversed character order), guid (a string 12 characters long) and origin_id (a reference to the following table). The description field is optional and usually contains the page’s abstract if you add a bookmark via the browser. Older (than 68) versions of Firefox do not support the description column.

moz_origins each entry contains an URL (protocol + host) that can be referenced by multiple URIs (bookmarks, history etc.). The URL’s prefix (“htps://”) and host (“www.metabpa.org”) are stored in separate fields. When adding a new origin entry, the frecency field (a metric combining frequency and recency of visits) must be set to some integer value, most likely zero. Older (than 68) versions of Firefox do not have the moz_origins table and the correspondig origin_id column in the moz_places table.

Dates and times

Firefox uses an int64 time format that is UNIX time in microseconds. In a typical places.sqlite all time values and in three zeroes so the times are basically in milliseconds. So, to convert a Firefox time value to a universal time, just divide by 1000 and add to 1970-01-01 00:00:00. Conversely, to calculate Firefox time, take the milliseconds passed since 1970-01-01 midnight and multiply by 1000.

Google Chrome

Chrome stores all bookmarks in a JSON file named Bookmarks (no extension). By default, this file is located in %LOCALAPPDATA%\Google\Chrome\User Data\Default\. If Roaming Profile support is enabled via Group Policy, the default location changes to %APPDATA%\Google\Chrome\User Data\Default\. Group Policy also allows to specify a precise location using multiple placeholders, as described in https://www.chromium.org/administrators/policy-list-3/user-data-directory-variables.

The favicon cache is stored in a SQLite dtabase named Favicons, also without extension, which is usually stored in the same folder as the Bookmarks file.

Dates and times

Chrome uses the usual FileTime, shortened by 1 tailing zero, i.e. to 17 digits.

Opera browser

Opera utilizes a similar approach to Chrome. However, the data structure stored in JSON is slightly more involved. Favicons go into a SQLite DB. Both files bear no extension, just like their Chrome counterparts.

Hashes and Checksums

Both Chrome and Mozilla use checksums to maintain data integrity: In Chrome, it is the checksum attribuite in JSON that is calculated over the entire file; in Firefox each URL entry in the moz_places table has an url_hash field. That hash function is not easy to calculate and impossible to do in PowerShell because it uses the wrapped arithmetic of unsigned integers which PowerShell does not.

Fortunately for us, neither browser actually requires the hash to match the respective content. While Chrome will not display the bookmarks if the checksum doesn’t match, it will heppily recalculate the checksum if you remove it from the JSON file altogether. Firefox, on the other hand, doesn’t seem to have any problem whatsoever with either missing or wrong hash values.