Firefox quietly saves your open tabs to disk every few seconds. If you’ve ever lost a session after a crash, force-quit, or botched update — those tabs are very likely still sitting in a backup file. This post shows you how to read them with a small Python script and get your tabs back.
Where Firefox stores session backups
Firefox keeps session files in your profile folder:
Linux:
~/.mozilla/firefox/<profile-id>/sessionstore-backups/
macOS:
~/Library/Application Support/Firefox/Profiles/<profile-id>/sessionstore-backups/
Windows:
%APPDATA%\Mozilla\Firefox\Profiles\<profile-id>\sessionstore-backups\
Inside you’ll find files like:
| File | Contents |
|---|---|
recovery.jsonlz4 | The most recent session (updated live) |
previous.jsonlz4 | The session before the current one |
recovery.baklz4 | A rolling backup of recovery |
upgrade.jsonlz4-<date> | Snapshots taken before Firefox updates |
The .jsonlz4 extension is Mozilla’s custom format: a small 8-byte magic header (mozLz40\0) followed by LZ4 block-compressed JSON.
The script
Install the dependency first:
pip install lz4
Then save this as session_viewer.py inside your sessionstore-backups/ folder (or anywhere you like):
#!/usr/bin/env python3
"""Firefox session backup viewer — lists tabs from .jsonlz4 files."""
import json
import sys
import os
import struct
import lz4.block
def decode_session(path):
with open(path, "rb") as f:
data = f.read()
if data[:8] != b"mozLz40\0":
raise ValueError("Not a valid Firefox session file")
payload = data[8:]
# Mozilla stores the uncompressed size as the first 4 bytes after the magic
stored_size = struct.unpack_from("<I", payload, 0)[0]
for size in (stored_size, 256 * 1024 * 1024):
try:
return json.loads(lz4.block.decompress(payload[4:], uncompressed_size=size))
except Exception:
pass
# Last resort: skip the size prefix entirely
return json.loads(lz4.block.decompress(payload, uncompressed_size=256 * 1024 * 1024))
def list_tabs(session):
for wi, window in enumerate(session.get("windows", []), 1):
tabs = window.get("tabs", [])
print(f"\n── Window {wi} ({len(tabs)} tabs) ──")
for tab in tabs:
entries = tab.get("entries", [])
if entries:
e = entries[-1]
title = e.get("title", "").strip() or "(no title)"
url = e.get("url", "")
print(f" {title}")
print(f" {url}")
def list_backups(folder):
files = sorted(
f for f in os.listdir(folder)
if f.endswith(".jsonlz4") or f.endswith(".baklz4") or ".jsonlz4-" in f
)
return [os.path.join(folder, f) for f in files]
def main():
here = os.path.dirname(os.path.abspath(__file__))
if len(sys.argv) > 1:
targets = sys.argv[1:]
else:
targets = list_backups(here)
if not targets:
print("No session files found.")
sys.exit(1)
print("Available session backups:\n")
for i, p in enumerate(targets):
print(f" [{i}] {os.path.basename(p)}")
print()
choice = input("Enter number to view (or press Enter for most recent): ").strip()
targets = [targets[int(choice)] if choice else targets[-1]]
for path in targets:
print(f"\n{'='*60}")
print(f"File: {os.path.basename(path)}")
print("=" * 60)
try:
session = decode_session(path)
list_tabs(session)
except Exception as e:
print(f" Error reading file: {e}")
if __name__ == "__main__":
main()
Usage
Interactive mode — run without arguments to get a menu of all backup files:
python3 session_viewer.py
Available session backups:
[0] previous.jsonlz4
[1] recovery.baklz4
[2] recovery.jsonlz4
[3] upgrade.jsonlz4-20260403140140
[4] upgrade.jsonlz4-20260415192539
[5] upgrade.jsonlz4-20260427013024
Enter number to view (or press Enter for most recent):
Press Enter to view the most recent, or type a number.
Direct mode — pass a filename as an argument:
python3 session_viewer.py recovery.jsonlz4
python3 session_viewer.py upgrade.jsonlz4-20260415192539
Example output:
============================================================
File: recovery.jsonlz4
============================================================
── Window 1 (8 tabs) ──
"Software Fundamentals Matter More Than Ever" — Matt Pocock - YouTube
https://www.youtube.com/watch?v=v4F1gFy-hqg
Stop Using JSON Web Tokens (JWTs) for Authorization! - YouTube
Deep Agents overview - Docs by LangChain
https://docs.langchain.com/oss/python/deepagents/overview
How to restore a session
Once you’ve identified which backup has the tabs you want, restoring is a one-liner.
Close Firefox completely before doing this.
# Replace recovery.jsonlz4 with the backup you want to restore
cp upgrade.jsonlz4-20260415192539 recovery.jsonlz4
Reopen Firefox. It will detect the session file and offer to restore it. Accept — and your tabs are back.
How the format works
The mozLz4 format is straightforward:
[8 bytes magic: "mozLz40\0"] [4 bytes: uncompressed size (LE uint32)] [lz4 block data...]
The JSON inside is the full session state — windows, tabs, tab history (back/forward stack), scroll positions, form data, and more. The entries array inside each tab contains the navigation history; the last entry is the currently visible page.
# The key paths in the JSON:
session["windows"] # list of open windows
window["tabs"] # list of tabs in a window
tab["entries"][-1]["url"] # URL of the active page in a tab
tab["entries"][-1]["title"] # page title
Automating it (grep for a URL)
You can pipe the output and grep for specific domains:
python3 session_viewer.py upgrade.jsonlz4-20260427013024 | grep github.com
Or extract just the URLs:
python3 session_viewer.py recovery.jsonlz4 | grep "https://"
Requirements
- Python 3.6+
lz4(pip install lz4)
That’s it. No Firefox extensions, no third-party apps.
If the opening do not work you can aways import them one by one with
firefox --new-tab https://docs.ollama.com/integrations/hermes