Build Custom Fiddler Inspectors for Deep HTTP Debugging
Learn how to build production-ready custom Fiddler inspectors for JWT, Protobuf, GraphQL, and more — with step-by-step C# code, troubleshooting tips, and HTTPS decryption safety checks.
Why Custom Inspectors Elevate Your Fiddler Debugging Workflow
Fiddler isn’t just a passive HTTP proxy — it’s a programmable debugging platform. While built-in inspectors like Raw, TextView, and JSON Visualizer cover common use cases, real-world API testing, microservice troubleshooting, and security validation often demand deeper context: custom headers, encrypted payload previews, or domain-specific syntax highlighting. That’s where custom inspectors shine. They transform Fiddler from a generic traffic viewer into an extensible, domain-aware fiddler debugging environment — especially critical when analyzing complex https decryption flows or validating edge-case request patterns.
Unlike session filters or AutoResponder rules, inspectors operate at the UI layer, giving you full control over how each request or response is rendered, parsed, validated, or even modified in real time. And because they’re written in C# and compiled as .NET assemblies, they integrate seamlessly with FiddlerCore, enabling reuse in headless automation scenarios.
This tutorial walks you through building, testing, and deploying a production-ready custom inspector — no guesswork, no outdated APIs. You’ll learn how to hook into Fiddler’s rendering pipeline, parse binary payloads safely, and avoid common pitfalls that break http debugging reliability.
Prerequisites and Setup
Before writing code, ensure your environment supports Fiddler extensibility:
- Fiddler v5.0+ (v6.x recommended; legacy v4 uses different extension models)
- .NET SDK 6.0 or later (Fiddler extensions target
net6.0ornet8.0) - Visual Studio 2022 or VS Code + C# extension
- Fiddler’s Extensibility SDK: Install via NuGet Package Manager — search for
FiddlerCore(v5.0+). Do not useFiddler.dlldirectly — it’s deprecated and unstable.
💡 Tip: Always reference
FiddlerCoreinstead of copyingFiddler.exe's assembly. This ensures version compatibility and avoids GAC-related load failures during fiddler proxy startup.
Create a new Class Library project:
dotnet new classlib -n MyCustomInspector -f net6.0
cd MyCustomInspector
dotnet add package FiddlerCore --version 5.0.1
Then add a reference to System.Windows.Forms (required for UI inspectors) and set <UseWindowsForms>true</UseWindowsForms> in your .csproj.
Step-by-Step: Building a JWT Inspector
Let’s build a practical example: a JWT Inspector that decodes and validates JSON Web Tokens in Authorization headers or request bodies — invaluable for fiddler tutorial scenarios involving OAuth2 or token-based auth debugging.
1. Implement IInspector2 Interface
All custom inspectors must implement Fiddler.IInspector2. Create JwtInspector.cs:
using Fiddler;
using System.Windows.Forms;
public class JwtInspector : IInspector2
{
private readonly Control _uiControl = new JwtInspectorUI();
public string[] SupportedContentTypes => new[] { "application/jwt", "text/plain" };
public bool HandlesContentType(string sContentType) =>
sContentType?.Contains("jwt") == true ||
sContentType?.Contains("bearer") == true;
public Control Control => _uiControl;
public void Clear() => (_uiControl as JwtInspectorUI)?.Clear();
public void AssignSession(Session oSession) => (_uiControl as JwtInspectorUI)?.LoadSession(oSession);
}
Note: SupportedContentTypes hints to Fiddler which sessions this inspector should appear for. HandlesContentType() gives you runtime flexibility — e.g., inspecting raw Base64 strings inside text/plain responses.
2. Build the UI Control
Create JwtInspectorUI.cs, inheriting from UserControl:
using System;
using System.Text;
using System.Windows.Forms;
using Newtonsoft.Json;
public partial class JwtInspectorUI : UserControl
{
private TextBox _txtHeader, _txtPayload, _txtSignature;
private Label _lblStatus;
public JwtInspectorUI()
{
InitializeComponent();
Dock = DockStyle.Fill;
}
private void InitializeComponent()
{
_txtHeader = new TextBox { ReadOnly = true, Multiline = true, ScrollBars = ScrollBars.Vertical };
_txtPayload = new TextBox { ReadOnly = true, Multiline = true, ScrollBars = ScrollBars.Vertical };
_txtSignature = new TextBox { ReadOnly = true, Size = new System.Drawing.Size(300, 20) };
_lblStatus = new Label { AutoSize = true };
var tlp = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 4 };
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 75F));
tlp.Controls.Add(new Label { Text = "Header:" }, 0, 0);
tlp.Controls.Add(_txtHeader, 1, 0);
tlp.Controls.Add(new Label { Text = "Payload:" }, 0, 1);
tlp.Controls.Add(_txtPayload, 1, 1);
tlp.Controls.Add(new Label { Text = "Signature:" }, 0, 2);
tlp.Controls.Add(_txtSignature, 1, 2);
tlp.Controls.Add(_lblStatus, 0, 3);
Controls.Add(tlp);
}
public void LoadSession(Session oSession)
{
try
{
var token = ExtractJwtFromSession(oSession);
if (!string.IsNullOrEmpty(token))
{
var parts = token.Split('.');
if (parts.Length == 3)
{
var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(parts[0]));
var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(parts[1]));
_txtHeader.Text = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(headerJson), Formatting.Indented);
_txtPayload.Text = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(payloadJson), Formatting.Indented);
_txtSignature.Text = parts[2];
_lblStatus.Text = "✅ Valid JWT structure";
_lblStatus.ForeColor = System.Drawing.Color.Green;
}
else
{
throw new ArgumentException("Invalid JWT segment count");
}
}
else
{
Clear();
_lblStatus.Text = "⚠ No JWT found";
_lblStatus.ForeColor = System.Drawing.Color.Orange;
}
}
catch (Exception ex)
{
_lblStatus.Text = $"❌ Parse error: {ex.Message}";
_lblStatus.ForeColor = System.Drawing.Color.Red;
}
}
private string ExtractJwtFromSession(Session oSession)
{
// Check Authorization header first
if (oSession.oRequest.headers.ExistsAndContains("Authorization", "Bearer "))
{
return oSession.oRequest.headers.GetFirstValue("Authorization").Replace("Bearer ", "").Trim();
}
// Then check request body (e.g., POST with 'token' field)
if (!string.IsNullOrEmpty(oSession.RequestBodyAsString))
{
var body = oSession.RequestBodyAsString;
var match = System.Text.RegularExpressions.Regex.Match(body, @"\"token\":\"([A-Za-z0-9_-]{3,}\.){2}[A-Za-z0-9_-]+\"");
return match.Success ? match.Groups[1].Value : null;
}
return null;
}
private static byte[] Base64UrlDecode(string input)
{
string padded = input.Length % 4 == 0 ? input : input + new string('=', 4 - input.Length % 4);
return Convert.FromBase64String(padded.Replace('-', '+').Replace('_', '/'));
}
public void Clear()
{
_txtHeader.Clear();
_txtPayload.Clear();
_txtSignature.Clear();
_lblStatus.Text = "";
}
}
3. Register the Inspector
Fiddler discovers inspectors via FiddlerApplication.OnInspectorsAvailable. In Program.cs or AssemblyInfo.cs, add:
using Fiddler;
public static class Startup
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public static void Initialize()
{
FiddlerApplication.OnInspectorsAvailable += (oSender, oEvArgs) =>
{
oEvArgs.Inspectors.Add(new JwtInspector());
};
}
}
Then call Startup.Initialize() early — ideally in your extension’s OnBeforeInitialize handler or via [LoaderOptimization(LoaderOptimization.MultiDomainHost)] on the entry point.
Compiling and Installing the Extension
Build your project:
dotnet build -c Release
Copy the resulting MyCustomInspector.dll to Fiddler’s Inspectors folder:
- Windows:
%USERPROFILE%\Documents\Fiddler2\Inspectors\ - macOS (Fiddler Everywhere): Not supported — custom inspectors require Fiddler Classic on Windows.
Restart Fiddler. Navigate to any session with a JWT (e.g., GET /api/me with Authorization: Bearer ey...). Click the Inspectors tab — your JwtInspector appears alongside TextView and WebForms.
🔍 Pro tip: Use Fiddler’s QuickExec box (
Ctrl+Q) and typeprefs set fiddler.ui.inspectors.showall trueto force all inspectors to render — helpful during development.
Troubleshooting Common Pitfalls
- Inspector doesn’t appear? Verify your DLL targets
net6.0, notnetstandard2.0. Fiddler Classic loads only .NET Framework/.NET Core-compatible assemblies — mismatched runtimes silently fail. - UI freezes or throws
InvalidOperationException? All UI updates must occur on the UI thread. Wrap_txtHeader.Text = ...inInvoke((MethodInvoker)delegate { ... });if called outside the main thread. - HTTPS decryption breaks after installing inspector? Ensure your extension doesn’t intercept or modify
Sessionobjects duringAssignSession()— never calloSession.utilDecodeResponse()or mutate headers here. That belongs inBeforeResponsehandlers. FiddlerCoreversion conflicts? Usedotnet list packageto confirm no transitiveFiddlerCoredowngrade. Lock to5.0.1+explicitly.
For deeper diagnostics, enable Fiddler’s Log Viewer (Help > Fiddler Options > Enable FiddlerScript Logging) and watch for Failed to load inspector messages.
Extending Further: Beyond JWT
Once you’ve mastered the inspector pattern, consider these advanced extensions:
- Protobuf Inspector: Parse
.proto-annotated binary payloads usingGoogle.Protobufand reflection-based schema inference. - GraphQL Query Visualizer: Syntax-highlight and auto-format GraphQL queries/mutations with error detection for malformed fragments.
- TLS Handshake Analyzer: Hook into
FiddlerApplication.OnNotificationto surface ALPN, SNI, and cipher suite details per session — extremely useful for https decryption root-cause analysis.
All follow the same architecture: implement IInspector2, render state safely, and register at startup. Avoid heavy parsing in AssignSession() — cache decoded data and defer expensive ops to background threads with Task.Run().
Conclusion: Turn Fiddler Into Your Domain-Specific Debugger
Custom inspectors are among the most underused yet highest-leverage features in the Fiddler ecosystem. They let you move beyond generic http debugging, turning every session into a contextual, actionable view — whether you're reverse-engineering third-party APIs, validating token hygiene, or auditing legacy SOAP payloads.
Remember: great inspectors are fast, safe, and silent. They never crash Fiddler, never block the UI thread, and gracefully degrade when input is malformed. Start small — extend the JWT inspector to validate exp timestamps or highlight insecure alg:none tokens — then scale to multi-format analyzers.
You now have the foundation to build inspectors that align precisely with your team’s fiddler debugging workflows. For more advanced integrations — like injecting inspectors into CI pipelines via FiddlerCore or combining them with more tutorials on automated certificate pinning bypass — explore our browse Advanced Techniques tutorials. Need help adapting this for your stack? contact us — we ship production-grade inspectors weekly.
Key takeaways:
- Always use
FiddlerCoreNuGet, never embedFiddler.exeassemblies. HandlesContentType()is your dynamic gatekeeper — use it to scope inspection logic.- Never mutate
Sessionobjects inside inspectors — treat them as read-only views. - Test with both HTTP and HTTPS traffic to verify https decryption compatibility.
- Log errors but never throw unhandled exceptions — they kill inspector availability.