Decoding Fiddler SAZ Files: Parse, Modify & Automate
Master Fiddler's SAZ file format: parse, modify, and automate HTTP(S) captures programmatically. Includes C#, Python, FiddlerCore, and HTTPS decryption tips.
Fiddler’s .saz file format is the de facto standard for saving and sharing HTTP(S) traffic captures — but few developers realize how deeply they can programmatically interact with it. Whether you're building custom test harnesses, automating regression checks for API behavior, or integrating Fiddler debugging into CI/CD pipelines, understanding SAZ internals unlocks powerful automation capabilities beyond manual inspection.
This guide walks through the SAZ format’s structure, demonstrates robust programmatic access using C# and Python, explains how to preserve HTTPS decryption context when reimporting sessions, and highlights common pitfalls that break replay fidelity. You’ll learn not just how to read a SAZ file — but how to treat it as a first-class data source in your toolchain.
What Is a SAZ File — Really?
A .saz file is a ZIP archive containing structured JSON and binary assets. Unlike raw PCAPs or HAR files, SAZ preserves Fiddler-specific metadata: request/response flags (e.g., X-Response-Body-Transformed), custom inspector state, breakpoints, and — critically — decrypted HTTPS response bodies if saved after decryption is enabled. This makes SAZ uniquely valuable for fiddler debugging and long-term HTTP debugging workflows.
Inside the archive, you’ll find:
SessionArchive.json: Top-level manifest listing all captured sessions with timestamps, URLs, statuses, and metadata.Raw/: Subfolders (000001,000002, etc.) containing individual session artifacts:request.txtandresponse.txt: Plain-text HTTP messages (headers + body)requestbody.txt/responsebody.txt: Raw body bytes (base64-encoded if binary)session.json: Per-session metadata (e.g.,ClientIP,ServerIP,IsHTTPS,X-ConnectionID)
CustomRules.cs: Optional — only present if saved with FiddlerScript modifications enabled.
💡 Note: SAZ files do not store private keys or certificate material. HTTPS decryption must be re-enabled in the target Fiddler instance before replaying encrypted sessions — otherwise, decrypted bodies will appear as encrypted blobs or fail to load.
Step-by-Step: Reading a SAZ File in C#
FiddlerCore includes SessionArchive APIs, but for standalone parsing (e.g., in build scripts or analysis tools), use System.IO.Compression.ZipFile + Newtonsoft.Json.
Prerequisites
- .NET 6+ SDK
- NuGet packages:
Newtonsoft.Json,System.IO.Compression.ZipFile
Code Example
using System;
using System.IO;
using System.IO.Compression;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class SazReader
{
public static List<Session> LoadSessions(string sazPath)
{
var sessions = new List<Session>();
using var archive = ZipFile.OpenRead(sazPath);
// Load manifest
var manifestEntry = archive.GetEntry("SessionArchive.json");
if (manifestEntry == null) throw new InvalidOperationException("Invalid SAZ: missing SessionArchive.json");
using var manifestStream = manifestEntry.Open();
using var reader = new StreamReader(manifestStream);
var manifest = JObject.Parse(reader.ReadToEnd());
foreach (JToken sessionToken in manifest["Sessions"])
{
var sessionId = sessionToken["Id"].ToString();
var sessionDir = $"Raw/{sessionId.PadLeft(6, '0')}/";
var session = new Session
{
Id = sessionId,
Url = sessionToken["Url"]?.ToString(),
StatusCode = (int?)sessionToken["StatusCode"] ?? 0,
IsHttps = sessionToken["IsHTTPS"]?.ToObject<bool>() == true
};
// Read request body
var reqBodyEntry = archive.GetEntry($"{sessionDir}requestbody.txt");
if (reqBodyEntry != null)
{
using var reqBodyStream = reqBodyEntry.Open();
using var reqBodyReader = new StreamReader(reqBodyStream);
session.RequestBody = reqBodyReader.ReadToEnd();
}
sessions.Add(session);
}
return sessions;
}
}
public class Session
{
public string Id { get; set; }
public string Url { get; set; }
public int StatusCode { get; set; }
public bool IsHttps { get; set; }
public string RequestBody { get; set; }
}
✅ Pro tip: Always validate IsHTTPS before assuming body content is plaintext — some HTTPS responses may still be base64-encoded if Fiddler couldn’t decrypt them (e.g., due to missing client cert or TLS version mismatch).
Parsing SAZ in Python (with Requests & zipfile)
Python offers lightweight alternatives for quick analysis or integration with pytest or Robot Framework. Use zipfile, json, and base64 — no external dependencies required beyond stdlib.
Minimal Working Script
import zipfile
import json
import base64
import os
def parse_saz(saz_path):
sessions = []
with zipfile.ZipFile(saz_path, 'r') as zf:
# Load manifest
with zf.open('SessionArchive.json') as f:
manifest = json.load(f)
for sess in manifest.get('Sessions', []):
sess_id = sess['Id']
raw_dir = f'Raw/{sess_id.zfill(6)}/'
# Try reading request body
req_body = b''
try:
with zf.open(f'{raw_dir}requestbody.txt') as f:
req_body = f.read()
# Decode if base64-encoded (common for binary)
if req_body.startswith(b'Base64:'):
req_body = base64.b64decode(req_body[7:])
except KeyError:
pass
sessions.append({
'id': sess_id,
'url': sess.get('Url', ''),
'status_code': sess.get('StatusCode', 0),
'is_https': sess.get('IsHTTPS', False),
'request_body': req_body.decode('utf-8', errors='replace'),
})
return sessions
# Usage
sessions = parse_saz('capture.saz')
for s in sessions[:3]:
print(f"[{s['status_code']}] {s['url']} → {len(s['request_body'])} chars")
⚠️ Troubleshooting: If requestbody.txt is missing, check request.txt — sometimes bodies are embedded inline. Also verify Fiddler was configured to save request bodies: under Tools > Options > HTTP, ensure “Decrypt HTTPS traffic” and “Capture HTTPS CONNECTs” are enabled before capture, and “Save request/response bodies” is checked under File > Save > All Sessions.
Modifying & Rebuilding SAZ Archives
You can inject modified requests, annotate sessions, or even simulate failure scenarios by editing request.txt and regenerating the archive.
Steps to Inject a Modified Request
- Extract the SAZ using
unzip capture.saz -d extracted/ - Edit
extracted/Raw/000001/request.txt(e.g., changeUser-Agentor addX-Test-Flag: true) - Update
extracted/Raw/000001/session.jsonto reflect changes (e.g., bumpX-Modifiedtimestamp) - Recompress:
zip -r modified.saz extracted/ - Open
modified.sazin Fiddler — it loads cleanly, and you can replay the edited request via Composer or AutoResponder.
🔧 Critical note on HTTPS decryption: If your original SAZ contained decrypted HTTPS responses, modifying request.txt won’t invalidate decryption — but replaying that session in a new Fiddler instance requires identical trust configuration. Ensure the target machine has Fiddler’s root certificate installed (Tools > Options > HTTPS > Actions > Export Root Certificate to Desktop) and “Decrypt HTTPS traffic” is enabled.
Automating SAZ Analysis with FiddlerCore
For deep integration — like filtering sessions by regex, calculating latency percentiles, or exporting to Prometheus metrics — use FiddlerCore’s native SessionArchive class.
Example: Filter and Export Failed HTTPS Sessions
var archive = SessionArchive.LoadFromFile(@"C:\temp\capture.saz");
var failedHttps = archive.Sessions
.Where(s => s.IsHTTPS && s.responseCode >= 400)
.Select(s => new {
s.fullUrl,
s.responseCode,
s.oFlags["X-ElapsedTime-ms"]?.ToString() ?? "0"
}).ToList();
File.WriteAllText(@"C:\temp\failed-https.json", JsonConvert.SerializeObject(failedHttps, Formatting.Indented));
This approach respects Fiddler’s internal parsing logic — including header normalization, charset detection, and response body decoding — making it more reliable than raw ZIP parsing for production tooling.
Common Pitfalls & How to Avoid Them
| Issue | Cause | Fix |
|---|---|---|
requestbody.txt missing |
“Save request bodies” disabled during capture | Re-capture with Tools > Options > HTTP > Save request/response bodies enabled |
| Decrypted bodies appear garbled | SAZ opened on machine without Fiddler root cert | Install cert via Tools > Options > HTTPS > Actions > Trust Root Certificate |
Replay fails with 400 Bad Request |
Modified request.txt lacks CRLF line endings |
Use \r\n, not \n, between headers and body |
| Session count mismatch | Corrupted SessionArchive.json or missing Raw/ entries |
Validate ZIP integrity: zip -T capture.saz |
Conclusion: Treat SAZ as Structured Data, Not Just Logs
The SAZ format is far more than a convenience archive — it’s a portable, extensible representation of full HTTP(S) transaction state. By mastering programmatic access, you shift from passive fiddler debugging to active pipeline integration: validating API contracts, detecting regressions in header behavior, stress-testing auth flows, or feeding network traces into ML-based anomaly detection.
Key takeaways:
- SAZ is a ZIP + JSON + text — parseable without Fiddler, but richer with FiddlerCore.
- HTTPS decryption context is not embedded — ensure target environments have certs and decryption enabled for accurate replay.
- Always verify line endings, encoding, and base64 wrapping when editing manually.
- Prefer
SessionArchive.LoadFromFile()over raw ZIP parsing when building tooling inside .NET ecosystems.
Ready to go deeper? Explore our more tutorials for advanced fiddler proxy configurations, or dive into TLS inspection patterns with our browse Advanced Techniques tutorials. For custom SAZ automation needs, contact us — we build integrations for QA teams and security researchers daily.
Fiddler debugging isn’t just about watching traffic — it’s about transforming it into insight, automation, and reliability. Your next HTTP debugging breakthrough starts with understanding what’s inside that .saz file.