Fiddler Logo Fiddler book image Get the NEW book!
RSS Icon download iconGet Fiddler! Addons Help & Documentation Developer Info Discuss Contact

FiddlerScript CookBook

You can add a lot of power to Fiddler by updating its JScript.NET CustomRules.js file.  To add rules to Fiddler, choose Customize Rules on Fiddler's Rules menu.  Enter code inside the suggested function and save the file.  Fiddler will automatically reload the rules.

Tips and Tricks

  • If you "break" your CustomRules.js file: delete the CustomRules.js file in your \Documents\Fiddler2\Scripts\ folder. The next time Fiddler starts, the default rules will be used to recreate your CustomRules.js file. Fiddler's default rules are stored in \Program Files\Fiddler2\Scripts\SampleRules.js.

  • You can change the JScript editor launched from the Rules menu.  Click Tools | Fiddler Options and edit the Editor string.  The Fiddler Script editor is a good choice.  Learn more...

  • You can use additional .NET assemblies in your script.  Click Tools | Fiddler Options and edit the References list on the Extensions tab.  You will also need to either register the assembly in the GAC or drop it in the Fiddler.exe folder.  Update the #import clause at the top of the JScript with the correct namespaces in order to use the new assembly's functions without fully-qualifying them.

Goal: Add custom columns to the UI

See UI Column Configuration.

Goal: Modify Request or Response
Goal Code Function to Update
Add a request header oSession.oRequest["NewHeaderName"] = "New header value"; OnBeforeRequest
Delete a response header oSession.oResponse.headers.Remove("Set-Cookie"); OnBeforeResponse
Change a request for one page to a different page on the same server if (oSession.PathAndQuery=="/version1.css") {
  oSession.PathAndQuery="/version2.css";
}
OnBeforeRequest
Point all requests for one server to the same port on a different server if (oSession.HostnameIs("www.bayden.com")) {
  oSession.hostname="test.bayden.com";
}
OnBeforeRequest
Point all requests for one port to a different port on a different server if (oSession.host=="www.bayden.com:8080") {
  oSession.host="test.bayden.com:9090";
}
OnBeforeRequest
Point all requests for one server to a different server, including HTTPS tunnels // Redirect traffic, including HTTPS tunnels
if
(oSession.HTTPMethodIs("CONNECT") && (oSession.PathAndQuery == "www.example.com:443")) {
    oSession
.PathAndQuery = "beta.example.com:443";
}

if
(oSession.HostnameIs("www.example.com")) oSession.hostname = "beta.example.com";  
OnBeforeRequest
Simulate the Windows HOSTS file, by pointing one Hostname to a different IP address. 

(Retargets without changing the request's Host header)

// All requests for subdomain.example.com should be directed to the development server at 128.123.133.123
if (oSession.HostnameIs("subdomain.example.com")){
oSession.bypassGateway = true;                   // Prevent this request from going through an upstream proxy
oSession["x-overrideHost"] = "128.123.133.123";  // DNS name or IP address of target server
}

OnBeforeRequest
Retarget requests for a single page to a different page, potentially on  a different server.

(Retargets by changing the request's Host header)
if (oSession.url=="www.example.com/live.js") {
  oSession.url = "dev.example.com/workinprogress.js";
}
OnBeforeRequest
Prevent upload of HTTP Cookies oSession.oRequest.headers.Remove("Cookie"); OnBeforeRequest
Decompress and unchunk a HTTP response, updating headers if needed // Remove any compression or chunking from the response in order to make it easier to manipulate
oSession.utilDecodeResponse();
OnBeforeResponse
Search and replace in HTML. if (oSession.HostnameIs("www.bayden.com") && oSession.oResponse.headers.ExistsAndContains("Content-Type","text/html")){
  oSession.utilDecodeResponse();
  oSession.utilReplaceInResponse('<b>','<u>');
}
OnBeforeResponse
Case insensitive Search of response HTML. if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "text/html") && oSession.utilFindInResponse("searchfor", false)>-1){
  oSession["ui-color"] = "red";
}
OnBeforeResponse
Remove all DIV tags (and content inside the DIV tag) // If content-type is HTML, then remove all DIV tags
if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "html")){
  // Remove any compression or chunking
  oSession.utilDecodeResponse
();

  var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);

  //
Replace all instances of the DIV tag with an empty string
  var oRegEx = /<div[^>]*>(.*?)<\/div>/gi;
  oBody = oBody.replace(oRegEx, "");

  // Set the response body to the div-less string
  oSession.utilSetResponseBody(oBody);
}

onBeforeResponse
Pretend your browser is the GoogleBot webcrawler

oSession.oRequest["User-Agent"]="Googlebot/2.X (+http://www.googlebot.com/bot.html)";

OnBeforeRequest
Request Hebrew content oSession.oRequest["Accept-Language"]="he";

OnBeforeRequest

Deny .CSS requests if (oSession.uriContains(".css")){
 oSession["ui-color"]="orange"; 
 oSession["ui-bold"]="true";
 oSession.oRequest.FailSession(404, "Blocked", "Fiddler blocked CSS file");
}

OnBeforeRequest

Simulate HTTP Basic authentication  (Requires user to enter a password before displaying web content.) if ((oSession.HostnameIs("www.example.com")) &&
 !oSession.oRequest.headers.Exists("Authorization"))
{
// Prevent IE's "Friendly Errors Messages" from hiding the error message by making response body longer than 512 chars.
var oBody = "<html><body>[Fiddler] Authentication Required.<BR>".PadRight(512, ' ') + "</body></html>";
oSession.utilSetResponseBody(oBody);
// Build up the headers
oSession.oResponse.headers.HTTPResponseCode = 401;
oSession.oResponse.headers.HTTPResponseStatus = "401 Auth Required";
oSession.oResponse["WWW-Authenticate"] = "Basic realm=\"Fiddler (just hit Ok)\"";
oResponse.headers.Add("Content-Type", "text/html");
}

OnBeforeResponse

Respond to a request with a file loaded from the \Captures\Responses folder if (oSession.PathAndQuery=="/version1.css") {
  oSession["x-replywithfile"] ="version2.css";
}
OnBeforeRequest
or
OnBeforeResponse
Your rule here? Request or submit a new rule using the CONTACT link above Thanks!

Scenario: Performance-Testing
Simulate modem uploads // Delay sends by 300ms per KB uploaded.
oSession["request-trickle-delay"] = "300";
OnBeforeRequest
Simulate modem downloads // Delay receives by 150ms per KB downloaded.
oSession["response-trickle-delay"] = "150";
OnBeforeResponse
Flag content which isn't set to cache on the client. if (!(oSession.oResponse.headers.Exists("Expires")
|| (oSession.oResponse.headers.ExistsAndContains("Cache-Control", "age")))
|| (oSession.oResponse.headers.Exists("Vary"))){
{
oSession["ui-color"]="brown"; // Use C# color strings here.
oSession["ui-italic"]="true";
}
OnBeforeResponse
Display in the "Custom Column" the number of milliseconds from the moment of the request until the last byte was received. oSession["ui-customcolumn"] = oSession["X-TTLB"]; onBeforeResponse
Display the # of milliseconds until the First Byte was received from the server, followed by the # of ms until the Last Byte. oSession["ui-customcolumn"] = "FB: " + oSession["X-TTFB"] + "; LB: " + oSession["X-TTLB"]; onBeforeResponse
Add a CopyTimers context menu item to the Session List

public static ContextAction("CopyTimers")
function CopyTimers(oSessions: Fiddler.Session[]){
  if (null == oSessions){
    MessageBox.Show("Please select sessions to copy timers for.", "Nothing to Do");
    return;
  }

  var s: System.Text.StringBuilder = new System.Text.StringBuilder();

  for
(var x = 0; x < oSessions.Length; x++)  {
    s.AppendFormat("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}\r\n",
    oSessions[x].Timers.ClientConnected,
   
oSessions[x].Timers.ClientDoneRequest,
   
oSessions[x].Timers.ServerConnected,
   
oSessions[x].Timers.ServerGotRequest,
   
oSessions[x].Timers.ServerBeginResponse,
   
oSessions[x].Timers.ServerDoneResponse,
   
oSessions[x].Timers.ClientBeginResponse,
   
oSessions[x].Timers.ClientDoneResponse
   
);
  }
 
Utilities.CopyToClipboard(s.ToString());
  MessageBox.Show("Done.");
}

Global scope

Miscellaneous rules
Display in the "Custom Column" the time of the original request oSession["ui-customcolumn"] += DateTime.Now.ToString("h:mm:ss.ffff "); onBeforeRequest
Show any Set-Cookie headers in Custom column in Session list. oSession["ui-customcolumn"] = oSession.oResponse["Set-Cookie"]; OnBeforeResponse
Mark any requests which send cookies in red, and show the value in the Custom column.  Otherwise, mark request in green. if (oSession.oRequest.headers.Exists("Cookie"))
{
oSession["ui-color"]="red";
oSession["ui-customcolumn"] = oSession.oRequest["Cookie"];
}
else
oSession["ui-color"]="green";
OnBeforeRequest
Hide requests for .GIFs from the session list if (oSession.url.EndsWith(".gif")){
    oSession["ui-hide"]="hiding image requests";  //String value not important
}
OnBeforeRequest
Hide completed responses which returned images if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "image/")) {
    oSession["ui-hide"] = "hiding images"; // String value not important
}
OnBeforeResponse
Hide requests to domains except those I care about

if (!oSession.HostnameIs("domainIcareabout.com")){
    oSession["ui-hide"] = "hiding boring domains"; // String value not important
}

OnBeforeRequest
Unhide any response which returned a 404 if (oSession.responseCode == 404){
    oSession.oFlags.Remove("ui-hide");
}
OnBeforeResponse
Play a sound when a file is missing.  Note the name "Notify" is a standard Windows system sound entry.

if (oSession.responseCode == 404){
    FiddlerObject.playSound("Notify");
    oSession["uiikeout"]="true";
}

OnBeforeResponse
Show HTTP POST bodies in a messagebox

var oBodyString = System.Text.Encoding.UTF8.GetString(oSession.requestBodyBytes);

if (oBodyString.Length > 0) FiddlerObject.alert(oBodyString);

OnBeforeRequest
Flag all pages in which the server sends a cookie

if (oSession.oResponse.headers.Exists("Set-Cookie") ||
  oSession.utilDecodeResponse();
  oSession.utilFindInResponse("document.cookie", false)>-1 ||
  oSession.utilFindInResponse('HTTP-EQUIV="Set-Cookie"', false)>-1){
  oSession["ui-color"]="purple";
}

OnBeforeResponse
Pause all HTTP POSTs to allow hand-editing (the POST verb is often used for submitting forms) if (oSession.HTTPMethodIs("POST")){
  oSession["x-breakrequest"]="breaking for POST";
}
OnBeforeRequest
Pause all HTTP POSTs that contain thekeyword

if (oSession.HTTPMethodIs("POST") && (oSession.utilFindInRequest("thekeyword", true) > -1)){
oSession["x-breakrequest"] = "keyword";
}

OnBeforeRequest
Pause a request for an XML file to allow hand-editing if (oSession.url.toLowerCase().indexOf(".xml")>-1){
 oSession["x-breakrequest"]="reason_XML";
}
OnBeforeRequest
Pause a response containing JavaScript to allow hand-editing if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "javascript")){
 oSession["x-breakresponse"]="reason is JScript";
}
OnBeforeResponse
Crawl Sequential URLs

public static ToolsAction("Crawl Sequential URLs")
function doCrawl(){
  var sBase: String;
  var sInt: String;

  sBase
= FiddlerObject.prompt("Enter base URL with ## in place of the start integer", "http://www.example.com/img##.jpg");
  sInt = FiddlerObject.prompt("Start At", "1");
  var iFirst = int.Parse(sInt);
  sInt = FiddlerObject.prompt("End At", "12");
  var iLast = int.Parse(sInt);

 
for (var x=iFirst; x<=iLast; x++)
  {
    //Replace 's' with your HTTP Request. Note: \ is a special character in JScript
    //
If you want to represent a backslash in a string constant, double it like \\
    var s = "GET " + sBase.Replace("##", x.ToString()) + " HTTP/1.0\r\n\r\n";
    var b=false;
    while(!b){
    try{
      FiddlerObject.utilIssueRequest(s);
      b=true;
    }
    catch(e){
      var iT = Environment.TickCount + 10000;
      FiddlerObject.StatusText = "Waiting 10 sec because we have too many requests outstanding...";
      while (iT > Environment.TickCount){ Application.DoEvents(); }
      }

    }
  }
}

Global scope
Log sessions to a local database
Note: The following example relies upon OLEDB 4.0 which is not available for 64bit processes. You can either select another data provider (e.g. SQLServer) or you can force Fiddler to run in 32bit mode.

Add the following to the Rules file to create a new menu item.
// Log the currently selected sessions in the list to a database.
// Note: The DB must already exist and you must have permissions to write to it.
public static ToolsAction("Log Selected Sessions")
function DoLogSessions(oSessions: Fiddler.Session[]){
if (null == oSessions || oSessions.Length < 1){
  MessageBox.Show("Please select some sessions first!");
  return;
}
var strMDB = "C:\\log.mdb";
var cnn = null;
var sdr = null;
var cmd = null;
try
{
  cnn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strMDB);
  cnn.Open();
  cmd = new OleDbCommand();
  cmd.Connection = cnn;

  for (var x = 0; x < oSessions.Length; x++){
    var strSQL = "INSERT into tblSessions ([ResponseCode],[URL]) Values (" +
    oSessions[x].responseCode + ", '" + oSessions[x].url + "')";
    cmd.CommandText = strSQL;
    cmd.ExecuteNonQuery();
  }
}
catch (ex){
  MessageBox.Show(ex);
}
finally
{
  if (cnn != null ){
    cnn.Close();
  }
}
}

Note: To use the Database Objects in Fiddler 2.3.9 and below, you'll need to add system.data to the References list inside Tools | Fiddler Options | Extensions | Scripting. In 2.3.9.1 and later, this reference will occur automatically.

Then, list the new import at the top of your rules script:

 import System.Data.OleDb;
Global scope
Search for a target string on a series of successively named HTML pages (e.g. find first page containing "TargetString" from 1.htm, 2.htm, 3.htm, 4.htm, etc).
Add the following to the Rules file to create a new menu item.
public static ToolsAction("Find page containing search string")
function doGrab(){
  var s = "GET /gallery/image1.htm HTTP/1.1\r\nHost: www.example.com\r\nX-My-Num: 1\r\n\r\n";
  try{
    FiddlerObject.utilIssueRequest(s);
  }
  catch(e){
    MessageBox.Show("send failed" + e.ToString());
  }
}

Now, this will make the first request. The trick is that you really want to look at the ~result~ of that request. This is sorta tricky because the utilIssueRequest call is asynchronous, and so you don't get the response directly.

But, remember that Fiddler rules run on each response, so you can then put code in the OnBeforeResponse handler that looks like...

if (oSession.oRequest.headers.Exists("X-My-Num")){
  // This is a response to my Grab code...
  if (oSession.utilFindInResponse("targetstring", false) > -1){
   // If the index of the target string is >-1, we found the search string... 
   MessageBox.Show("Found target string!");
  }
  else
  {
  //didn't find the target string.  increment the number.
  var n = int.parse(oSession.oRequest["X-My-Num"]);
  n++;
  var s = "GET /gallery/image" + n.ToString() + ".htm HTTP/1.1\r\nHost: http://www.example.com\r\nX-My-Num: "+ n.ToString() + "\r\n\r\n";
  try{
    // Make a recursive HTTP request for the next item.
    FiddlerObject.utilIssueRequest(s);
  }
  catch(e){
     MessageBox.Show("send failed" + e.ToString());
  }
  }
}
Global scope & onBeforeResponse
Save selected response files to disk in the Fiddler Captures folder (useful for copying online photo albums. public static ContextAction("Dump Files")
function DoDumpFiles(oSessions: Fiddler.Session[]){
  if (null == oSessions){
    MessageBox.Show("Please select sessions to dump.", "Nothing to Do");
    return;
  }

  for (var x = 0; x < oSessions.Length; x++){
    oSessions[x].SaveResponseBody();
  }
MessageBox.Show("Done.");
}
Global scope
Search all text responses for a list of strings.

oSession.utilDecodeResponse();

// Create a array of strings we're looking for.
var oFindStrings = new Array( "XMLHttp", "onreadystatechange", "readyState", "responseBody", "responseText", "responseXML", "statusText", "abort", "getAllResponseHeaders", "getResponseHeader", "setRequestHeader");

// For each target string, check the response to see if it's present.
var iEach=0;

oSession["ui-customcolumn"]=String.Empty;

for (iEach; iEach<oFindStrings.length; iEach++){
    if (oSession.utilFindInResponse(oFindStrings[iEach], false)>0) {
      oSession["ui-color"]="purple";
      oSession
["ui-customcolumn"] += oFindStrings[iEach]+"; ";

    }
}

OnBeforeRequest
Bypass the upstream proxy for all requests to a certain domain (E.g. Emulate the IE Proxy bypass list) if (oSession.HostnameIs("www.example.com")){
oSession.bypassGateway = true;
}
OnBeforeRequest
Show redirection target Location in Session List

if ((oSession.responseCode > 299) && (oSession.responseCode < 308)){
    oSession["ui-customcolumn"] = oSession.oResponse["Location"];
}

OnBeforeResponse
Add image size information in a column.
Note: you must add System.drawing.dll inside Tools > Fiddler Options > Extensions > References

      
public static BindUIColumn("ImageSize", 60)
function FillImageSizeColumn(oS: Session){
 if ((oS.oResponse != null) && (oS.oResponse.headers != null))
 {
   try{
      if (!oS.oResponse.headers.ExistsAndContains("Content-Type", "image/")) return "NotAnImage";

      var
oMS: System.IO.MemoryStream = new System.IO.MemoryStream(oS.responseBodyBytes);
      var i:System.Drawing.Bitmap = new System.Drawing.Bitmap(oMS);
      return (i.Width + " x " + i.Height);
      }
      catch(e) { return "err"; }
   }
 return String.Empty;
}

Global Scope

Scenario: Working with menus
Add context-menu item to open currently selected URLs using Firefox public static ContextAction("Open in Firefox")
function DoOpenInIE(oSessions: Fiddler.Session[]){
  if (null == oSessions){
    MessageBox.Show("Please choose at least 1 session."); return;
  }

  for (var x = 0; x < oSessions.Length; x++){
    System.Diagnostics.Process.Start("firefox.exe", oSessions[x].url);
  }
}
Global scope
Add a submenu to the Rules menu and create an option in it public static RulesOption("Non-Exclusive-Test", "User-Agent")
var m_UANONRad: boolean = true;
 
Global scope
To build submenus with mutually exclusive radio options  public static RulesOption("Spoof Netscape &3.0", "User-Agent", true)
var m_NS3: boolean = false;

public static RulesOption("Spoof IE &6.0", "User-Agent", true)
var m_IE6: boolean = false;

public static RulesOption("Spoof nothing", "User-Agent", true)
var m_UANONE: boolean = true;
Global scope
To build a submenu with mutually exclusive radio options, that control a single string variable.

Offers a more compact syntax than the previous alternative.

RulesString("&SubMenuName", true)
RulesStringValue(0,"Option1Name", "Option1Value")
RulesStringValue(1,"Option2Name", "Option2Value")
RulesStringValue(2,"&Custom...", "%CUSTOM%")
public static var sTheOptionValue: String = null;

Global scope
Same as previous, but with a default option pre-selected. RulesString("&SubMenuName", true)
RulesStringValue(0,"Option1Name", "Option1Value")
RulesStringValue(1,"Option2NameDEFAULT", "DefaultVal", true)
RulesStringValue(2,"&Custom...", "%CUSTOM%")
public static var sTheOptionValue: String = null;
Global scope
Add a Tools menu option that resets the script // Force a manual reload of the script file. Resets all
// RulesOption variables to their defaults.

public static ToolsAction("Reset Script")
function DoManualReload(){
    FiddlerObject.ReloadScript();
}
 
Global scope
Add a Tools menu option that clears
all WinINET/IE cookies and cache files
public static ToolsAction("Reset IE"){
  FiddlerObject.UI.actClearWinINETCache();
  FiddlerObject.UI.actClearWinINETCookies();
}
Global scope