PAC Files Guide: Proxy Auto-Configuration Explained

PAC Files Guide: Proxy Auto-Configuration Explained

A PAC (Proxy Auto-Configuration) file is a JavaScript file that tells browsers and applications which proxy server to use for each URL request. Instead of applying a single proxy to all traffic, PAC files enable intelligent routing — sending some requests through proxies while allowing others to connect directly. This is essential for corporate networks, development environments, and sophisticated proxy setups.

How PAC Files Work

When a browser is configured to use a PAC file, it calls the FindProxyForURL() function for every URL request. The function evaluates the URL and host, then returns instructions on which proxy to use (or whether to connect directly).

Browser Request Flow with PAC:

1. User navigates to https://example.com/page
2. Browser calls: FindProxyForURL("https://example.com/page", "example.com")
3. PAC function evaluates rules
4. Returns: "PROXY proxy.company.com:8080" or "DIRECT"
5. Browser routes traffic accordingly

PAC File Syntax

Basic Structure

function FindProxyForURL(url, host) {
    // url  = full URL being requested
    // host = hostname extracted from URL

    // Return values:
    // "DIRECT"                    — connect without proxy
    // "PROXY host:port"           — use HTTP proxy
    // "SOCKS host:port"           — use SOCKS proxy
    // "SOCKS5 host:port"          — use SOCKS5 proxy
    // Multiple: "PROXY a:8080; PROXY b:8080; DIRECT"
    //   → Try proxy a first, then b, then direct

    return "DIRECT";
}

Simple PAC File Examples

Route specific domains through proxy

function FindProxyForURL(url, host) {
    // Internal sites go direct
    if (dnsDomainIs(host, ".internal.company.com") ||
        dnsDomainIs(host, ".local")) {
        return "DIRECT";
    }

    // Specific sites through proxy
    if (dnsDomainIs(host, ".target-site.com") ||
        dnsDomainIs(host, ".another-site.com")) {
        return "PROXY scraping-proxy.example.com:8080";
    }

    // Everything else goes direct
    return "DIRECT";
}

Route all traffic except local through proxy

function FindProxyForURL(url, host) {
    // Local/internal traffic bypasses proxy
    if (isPlainHostName(host) ||
        shExpMatch(host, "*.local") ||
        isInNet(host, "10.0.0.0", "255.0.0.0") ||
        isInNet(host, "172.16.0.0", "255.240.0.0") ||
        isInNet(host, "192.168.0.0", "255.255.0.0") ||
        host === "localhost" ||
        host === "127.0.0.1") {
        return "DIRECT";
    }

    // All other traffic through proxy
    return "PROXY proxy.company.com:8080";
}

Advanced PAC Functions

PAC files have access to several built-in helper functions:

Host and Domain Matching

function FindProxyForURL(url, host) {
    // dnsDomainIs — check if host is in domain
    if (dnsDomainIs(host, ".google.com")) {
        // Matches: www.google.com, maps.google.com
        // Does NOT match: google.com (no leading dot)
    }

    // shExpMatch — shell expression matching (wildcards)
    if (shExpMatch(host, "*.amazon.*")) {
        // Matches: www.amazon.com, amazon.co.uk, api.amazon.de
    }

    // localHostOrDomainIs — exact or domain match
    if (localHostOrDomainIs(host, "www.example.com")) {
        // Matches: www.example.com, www
    }

    // isPlainHostName — no dots in hostname
    if (isPlainHostName(host)) {
        // Matches: "intranet", "server1"
        // Does NOT match: "www.example.com"
        return "DIRECT";
    }

    return "DIRECT";
}

Network-Based Routing

function FindProxyForURL(url, host) {
    // isInNet — check if IP is in subnet
    if (isInNet(dnsResolve(host), "198.51.100.0", "255.255.255.0")) {
        return "PROXY special-proxy.example.com:8080";
    }

    // myIpAddress — get client's IP
    var myIp = myIpAddress();
    if (isInNet(myIp, "10.1.0.0", "255.255.0.0")) {
        // Client is in office network
        return "PROXY office-proxy.company.com:8080";
    }

    // dnsDomainLevels — count dots in hostname
    if (dnsDomainLevels(host) > 2) {
        // More than 2 dots: sub.domain.example.com
    }

    return "DIRECT";
}

URL-Based Routing

function FindProxyForURL(url, host) {
    // Route based on protocol
    if (url.substring(0, 5) === "http:") {
        return "PROXY http-proxy.example.com:8080";
    }
    if (url.substring(0, 6) === "https:") {
        return "PROXY https-proxy.example.com:8443";
    }
    if (url.substring(0, 4) === "ftp:") {
        return "PROXY ftp-proxy.example.com:2121";
    }

    // Route based on URL path
    if (shExpMatch(url, "*/api/*")) {
        return "PROXY api-proxy.example.com:8080";
    }

    return "DIRECT";
}

Real-World PAC File Templates

Web Scraping Setup

function FindProxyForURL(url, host) {
    // Scraping targets → use rotating residential proxy
    var scrapingTargets = [
        "amazon.com", "ebay.com", "walmart.com",
        "google.com", "bing.com",
        "instagram.com", "tiktok.com", "facebook.com"
    ];

    for (var i = 0; i < scrapingTargets.length; i++) {
        if (dnsDomainIs(host, "." + scrapingTargets[i]) ||
            host === scrapingTargets[i]) {
            return "PROXY residential-gateway.provider.com:8080";
        }
    }

    // API endpoints → use datacenter proxy (faster)
    if (shExpMatch(url, "*api*") || shExpMatch(url, "*/v1/*") ||
        shExpMatch(url, "*/v2/*")) {
        return "PROXY datacenter-proxy.provider.com:8080";
    }

    // Everything else → direct connection
    return "DIRECT";
}

Geo-Targeted Proxy Routing

function FindProxyForURL(url, host) {
    // US content → US proxy
    if (dnsDomainIs(host, ".com") && !dnsDomainIs(host, ".co.uk")) {
        return "PROXY us-proxy.provider.com:8080";
    }

    // UK content → UK proxy
    if (dnsDomainIs(host, ".co.uk") || dnsDomainIs(host, ".uk")) {
        return "PROXY uk-proxy.provider.com:8080";
    }

    // German content → DE proxy
    if (dnsDomainIs(host, ".de")) {
        return "PROXY de-proxy.provider.com:8080";
    }

    // Fallback
    return "PROXY default-proxy.provider.com:8080";
}

Failover Configuration

function FindProxyForURL(url, host) {
    // Primary proxy, fallback to secondary, then direct
    return "PROXY primary-proxy.example.com:8080; " +
           "PROXY backup-proxy.example.com:8080; " +
           "DIRECT";
}

Hosting and Configuring PAC Files

Hosting Options

PAC files must be served with MIME type: application/x-ns-proxy-autoconfig

Options:
1. Web server (Apache/Nginx)
2. Local file (file:///path/to/proxy.pac)
3. WPAD auto-discovery
4. Corporate Group Policy

Nginx Configuration

server {
    listen 80;
    server_name pac.company.com;

    location /proxy.pac {
        alias /etc/proxy/proxy.pac;
        types { }
        default_type application/x-ns-proxy-autoconfig;
    }
}

Browser Configuration

Chrome:
  Settings → System → Open proxy settings → Auto proxy configuration
  URL: http://pac.company.com/proxy.pac

Firefox:
  Settings → Network Settings → Automatic proxy configuration URL
  URL: http://pac.company.com/proxy.pac

macOS System:
  System Preferences → Network → Advanced → Proxies
  Check "Automatic Proxy Configuration"
  URL: http://pac.company.com/proxy.pac

Windows:
  Settings → Network & Internet → Proxy → Automatic proxy setup
  Use setup script: On
  Script address: http://pac.company.com/proxy.pac

WPAD (Web Proxy Auto-Discovery)

WPAD automatically discovers PAC files using DNS or DHCP:

WPAD Discovery Process:

1. Browser looks for DHCP option 252 (WPAD URL)
2. If not found, tries DNS: wpad.company.com
3. Fetches: http://wpad.company.com/wpad.dat
4. Uses PAC file from wpad.dat

DNS setup:
  wpad.company.com  A  10.0.1.100  (PAC file server)

Debugging PAC Files

Testing with Browser Console

// Chrome: chrome://net-internals/#proxy
// Shows PAC file status and per-URL proxy decisions

// Firefox: about:networking#dns
// Shows proxy resolution results

Testing PAC Logic

// Create a test harness for your PAC file
function testPAC() {
    var tests = [
        {url: "https://www.amazon.com/product", host: "www.amazon.com",
         expected: "PROXY residential-gateway.provider.com:8080"},
        {url: "https://api.internal.com/v1/data", host: "api.internal.com",
         expected: "DIRECT"},
        {url: "https://www.google.co.uk/search", host: "www.google.co.uk",
         expected: "PROXY uk-proxy.provider.com:8080"},
    ];

    for (var i = 0; i < tests.length; i++) {
        var result = FindProxyForURL(tests[i].url, tests[i].host);
        var status = (result === tests[i].expected) ? "PASS" : "FAIL";
        console.log(status + ": " + tests[i].url + " → " + result);
    }
}

Frequently Asked Questions

Are PAC files secure?

PAC files run JavaScript in a sandboxed environment with limited functionality. They cannot access the DOM, make network requests, or interact with the filesystem. However, the PAC file itself is downloaded over HTTP (usually), which means it could be modified in transit (man-in-the-middle). Host PAC files over HTTPS when possible.

What is the performance impact of PAC files?

PAC evaluation adds microseconds per request — negligible for browsing. However, dnsResolve() calls within PAC files can add significant latency (DNS lookup for every request). Avoid dnsResolve() and isInNet() with hostname arguments when possible; use domain-matching functions instead.

Can PAC files handle proxy authentication?

No. PAC files only determine which proxy to use for each URL. They cannot include authentication credentials. Authentication must be handled separately (browser prompt, proxy extension, or IP whitelisting). See our proxy authentication guide for details.

Do all browsers support PAC files?

All major browsers (Chrome, Firefox, Safari, Edge) support PAC files. However, some mobile browsers and embedded web views have limited or no PAC support. Programmatic HTTP clients (Python requests, Node.js axios) do not use PAC files by default — you must implement the routing logic in your code.

What is the difference between PAC and WPAD?

PAC (Proxy Auto-Configuration) is the JavaScript file format. WPAD (Web Proxy Auto-Discovery) is the protocol for automatically finding the PAC file on a network. WPAD uses DNS or DHCP to locate the PAC file URL without manual configuration. Think of WPAD as the delivery mechanism and PAC as the content.

Conclusion

PAC files provide intelligent, automated proxy routing that is more flexible than static proxy configuration. They are essential for environments where different destinations require different proxy handling — from corporate networks to advanced web scraping setups. Write PAC files using the built-in helper functions, avoid DNS-heavy operations for performance, and host them securely to prevent tampering.

For proxy configuration tools, see our guides on SwitchyOmega setup and FoxyProxy setup.


Related Reading

Scroll to Top