# PAC file examples you can copy

Source: https://findproxyforurl.net/examples/ · updated 2026-10-09

Changed 2026-10-11: The SOCKS example now sends its zone to an HTTP proxy first and keeps plain SOCKS as the fallback, because Windows misreads SOCKS5 and .NET programs ignore SOCKS entries.

Each file below is a complete proxy.pac that works as it stands. Copy the one that is closest to your network, replace the example host names with your own, and test it before you roll it out.

Every example starts with a short note on when to use it, then shows the file, then explains what
to watch out for. All files are written in ES5, the JavaScript version that every PAC engine
understands, and none of them makes the browser wait for a DNS lookup. Each one scores A+ in the
[PAC file checker](https://findproxyforurl.net/check/).

The host names and networks are reserved example names: `corp.example` stands for your internal
zone, `proxy.corp.example:8080` for your proxy, and `198.51.100.0/24` for an address range of your
own. Replace them before you use a file.


## Send everything through one proxy

This is the smallest PAC file that works. Use it when every destination, including internal
servers, should go through the same proxy, for example on a guest network or in a lab.

```js
// proxy.pac example: one proxy for everything
// Synthetic example from https://findproxyforurl.net/examples/ - replace the proxy name and port.
function FindProxyForURL(url, host) {
  // Default route: every request goes through the corporate proxy
  return "PROXY proxy.corp.example:8080";
}
```

The `return` at the end is the *default route*: the answer for every request that no earlier
test matched. Here it is the only statement. With a single proxy and nothing else in the list,
browsers have nowhere to go when that proxy is down, so either point it at a highly available
address or use the failover example below.


## Keep local traffic direct and send the rest to the proxy

This is the most common PAC file in companies. Internal servers are reached directly, and
everything on the internet goes through the proxy. Start here if you are not sure which
example fits.

```js
// proxy.pac example: local destinations direct, everything else through the proxy
// Synthetic example from https://findproxyforurl.net/examples/ - replace the names and networks.
function FindProxyForURL(url, host) {
  // host names are case-insensitive, string comparisons are not
  host = host.toLowerCase();

  // plain host names (no dot) are on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // the internal DNS zone and all its hosts
  if (host == "corp.example" || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // IP-address URLs in private and loopback ranges; names are never resolved here
  if (/^\d+\.\d+\.\d+\.\d+$/.test(host) &&
      (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") ||
       isInNet(host, "127.0.0.0", "255.0.0.0"))) {
    return "DIRECT";
  }

  // Default route: everything else goes through the corporate proxy
  return "PROXY proxy.corp.example:8080";
}
```

The file lower-cases the host first, because the comparisons with `==` are case-sensitive.
Plain host names are names without a dot, such as `intranet`; `isPlainHostName()` is the
cheapest test, so it comes first. An internal zone needs two tests: `host == "corp.example"`
for the zone name itself and `dnsDomainIs(host, ".corp.example")` for every host in it.
Private address ranges are tested only when the URL contains an IP address, because
`isInNet()` on a name makes the browser wait for a DNS lookup
([why that hurts](https://findproxyforurl.net/rules/isinnet-on-hostname/)).


## Use a different proxy for some domains

Use it when some destinations need another route than the default: a partner network behind
its own gateway, a mirror in the DMZ that is reached directly, or a lab with its own proxy.

```js
// proxy.pac example: a different route per destination domain
// Synthetic example from https://findproxyforurl.net/examples/ - replace the names.
function FindProxyForURL(url, host) {
  // host names are case-insensitive, string comparisons are not
  host = host.toLowerCase();

  // plain host names and the internal zone stay on the local network
  if (isPlainHostName(host) || host == "corp.example" || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // partner systems are reached through the proxy at the partner VPN gateway
  if (host == "partner.example" || dnsDomainIs(host, ".partner.example")) {
    return "PROXY partner-gw.corp.example:3128";
  }

  // the software update mirror is in the DMZ and is reached without a proxy
  if (host == "updates.example.net") {
    return "DIRECT";
  }

  // the development lab has its own proxy, with the main proxy as fallback
  if (host == "lab.example" || dnsDomainIs(host, ".lab.example")) {
    return "PROXY labproxy.corp.example:8080; PROXY proxy.corp.example:8080";
  }

  // Default route: everything else goes through the corporate proxy
  return "PROXY proxy.corp.example:8080";
}
```

Each `if` block handles one destination group and ends in a `return`, so the first matching
block decides. Put the groups that match most requests first. Every entry that is a whole
domain uses the pair `host == "x"` and `dnsDomainIs(host, ".x")`; an entry for one host
uses `==` alone.


## Fail over to a second proxy when the first one does not answer

Use it whenever you have two proxies, for example one per data centre. The browser tries the
entries of the returned list from left to right and takes the next one when a proxy does not
answer.

```js
// proxy.pac example: two proxies, the second one takes over when the first does not answer
// Synthetic example from https://findproxyforurl.net/examples/ - replace the names.
function FindProxyForURL(url, host) {
  // host names are case-insensitive, string comparisons are not
  host = host.toLowerCase();

  // plain host names and the internal zone stay on the local network
  if (isPlainHostName(host) || host == "corp.example" || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // Default route, in failover order:
  //   1. proxy1 in data centre 1 (primary)
  //   2. proxy2 in data centre 2 (used when proxy1 does not answer)
  // No DIRECT at the end: when both proxies are down, requests fail instead of bypassing the proxy.
  return "PROXY proxy1.corp.example:8080; PROXY proxy2.corp.example:8080";
}
```

How long a browser skips a failed proxy before it tries it again differs between clients.
There is deliberately no `DIRECT` at the end of the list: with it, all traffic would bypass
the proxy as soon as both proxies are unreachable. If that is what you want, add it on
purpose ([the trade-off](https://findproxyforurl.net/rules/direct-fallback-in-proxy-list/)).


## Reach one zone through a SOCKS proxy

Use it when part of the network is reachable only through a gateway that offers SOCKS, for
example an isolated lab, while normal web traffic uses HTTP proxies.

```js
// proxy.pac example: one zone through a SOCKS proxy, everything else through an HTTP proxy
// Synthetic example from https://findproxyforurl.net/examples/ - replace the names.
function FindProxyForURL(url, host) {
  // host names are case-insensitive, string comparisons are not
  host = host.toLowerCase();

  // plain host names and the internal zone stay on the local network
  if (isPlainHostName(host) || host == "corp.example" || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // the isolated lab network is reachable only through its gateway, which offers an HTTP proxy
  // and SOCKS. HTTP first: Windows misreads SOCKS5 and .NET programs ignore SOCKS entries.
  // Plain SOCKS as the fallback, the one SOCKS keyword that every engine reads.
  if (host == "lab.example" || dnsDomainIs(host, ".lab.example")) {
    return "PROXY labgw.corp.example:3128; SOCKS labgw.corp.example:1080";
  }

  // Default route: everything else goes through the HTTP proxies, in failover order
  return "PROXY proxy1.corp.example:8080; PROXY proxy2.corp.example:8080";
}
```

The PAC format has only one `SOCKS` keyword and does not say which version of the SOCKS
protocol it means. Chromium treats plain `SOCKS` as version 4 and Firefox is reported to use
version 5. In the lab on Windows 11 (2026-10-11) Windows misread the explicit keywords
`SOCKS5` and `SOCKS4`, and .NET programs ignored SOCKS entries altogether. The file therefore
sends the zone to the gateway's HTTP proxy first and keeps plain `SOCKS` only as the
fallback. Test the file on every client you support
([details](https://findproxyforurl.net/rules/socks-version-keyword/)).


## Give each site its own proxy with one file per site

Use it when branch offices have their own proxies and each client should use the proxy of
the site it is in, with the head-office proxy as fallback.

```js
// proxy.pac example: the file for one branch office (here the Berlin site)
// Every site gets its own copy with its own proxy first; the site's DHCP scope or GPO hands out its URL.
// Synthetic example from https://findproxyforurl.net/examples/ - replace the names.
function FindProxyForURL(url, host) {
  // host names are case-insensitive, string comparisons are not
  host = host.toLowerCase();

  // plain host names and the internal zone stay on the local network
  if (isPlainHostName(host) || host == "corp.example" || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // Default route for this site, in failover order:
  //   1. the Berlin branch proxy
  //   2. the head-office proxy, reached over the WAN, when the branch proxy does not answer
  return "PROXY proxy.ber.corp.example:8080; PROXY proxy.hq.corp.example:8080";
}
```

The obvious way to do this in one file is to test the client's address with `myIpAddress()`.
That is unreliable: a laptop has several addresses (Wi-Fi, Ethernet, VPN, virtual adapters),
each browser picks "its" address in a different way, and the answer does not change when the
VPN connects until the browser runs the file again
([details](https://findproxyforurl.net/rules/myipaddress-usage/)). The reliable way is one small file per site, served
under a different URL, which the site's DHCP scope or a group policy for the site's computers
hands out. This example is the file for the Berlin site; the other sites get a copy with
their own proxy first.


## Files for security service edge (SSE) vendors

A security service edge (SSE) is a cloud service that inspects web traffic, such as Zscaler,
Netskope, Skyhigh Security, Cloudflare Gateway or Prisma Access. These files are the default output
of the site's [SSE builders](https://findproxyforurl.net/generate/sse/), which follow each vendor's documentation. The "Test
this file" link opens the checker with the vendor's rule pack selected, so the vendor-specific
checks run too.


### Zscaler Internet Access

A hosted PAC file for Zscaler Internet Access. The `${GATEWAY}` and `${SECONDARY_GATEWAY}`
variables are replaced by the Zscaler cloud when it serves the file, so the file must be
hosted there.

```js
// proxy.pac for Zscaler Internet Access, generated by findproxyforurl.net
// Host this file on the Zscaler cloud so that the ${...} variables are replaced.
function FindProxyForURL(url, host) {
  host = host.toLowerCase();

  // plain hostnames (no dot) stay on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // RFC 1918 and loopback addresses: literal IPs only, no DNS lookup for names
  if (/^\d+\.\d+\.\d+\.\d+$/.test(host) &&
      (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") ||
       isInNet(host, "127.0.0.0", "255.0.0.0"))) {
    return "DIRECT";
  }

  // internal domains and their subdomains go direct
  if (dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // the Zscaler service does not support native FTP
  if (url.substring(0, 4) == "ftp:") {
    return "DIRECT";
  }

  // default: everything else goes to the closest Public Service Edge, then to the secondary one
  return "PROXY ${GATEWAY}:80; PROXY ${SECONDARY_GATEWAY}:80";
}
```

Builder: https://findproxyforurl.net/generate/sse/zscaler/

### Netskope explicit proxy

A PAC file for the Netskope Cloud Explicit Proxy, which listens on port 8081. The identity
provider's sign-in hosts go direct.

```js
// proxy.pac for Netskope explicit proxy, generated by findproxyforurl.net
function FindProxyForURL(url, host) {
  host = host.toLowerCase();

  // plain hostnames (no dot) stay on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // RFC 1918 and loopback addresses: literal IPs only, no DNS lookup for names
  if (/^\d+\.\d+\.\d+\.\d+$/.test(host) &&
      (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") ||
       isInNet(host, "127.0.0.0", "255.0.0.0"))) {
    return "DIRECT";
  }

  // internal domains and their subdomains go direct
  if (dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // identity provider (Microsoft Entra ID) must not go through the explicit proxy
  if (host == "login.microsoftonline.com" || host == "aadcdn.msauth.net" || host == "aadcdn.msftauth.net") {
    return "DIRECT";
  }

  // the explicit proxy accepts HTTP and HTTPS only
  if (url.substring(0, 4) == "ftp:") {
    return "DIRECT";
  }

  // default: everything else goes to the Netskope Cloud Explicit Proxy (port 8081 is required)
  return "PROXY eproxy-exampletenant.goskope.com:8081";
}
```

Builder: https://findproxyforurl.net/generate/sse/netskope/

### Skyhigh Secure Web Gateway

A PAC file for the Skyhigh cloud proxy. Replace the customer ID in the host name with your
own.

```js
// proxy.pac for Skyhigh Secure Web Gateway, generated by findproxyforurl.net
function FindProxyForURL(url, host) {
  host = host.toLowerCase();

  // plain hostnames (no dot) stay on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // RFC 1918 and loopback addresses: literal IPs only, no DNS lookup for names
  if (/^\d+\.\d+\.\d+\.\d+$/.test(host) &&
      (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") ||
       isInNet(host, "127.0.0.0", "255.0.0.0"))) {
    return "DIRECT";
  }

  // internal domains and their subdomains go direct
  if (dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // default: everything else goes to the Skyhigh cloud proxy (port 80 or 8080)
  return "PROXY c1234567890.wgcs.skyhigh.cloud:8080";
}
```

Builder: https://findproxyforurl.net/generate/sse/skyhigh/

### Cloudflare Gateway proxy endpoint

A PAC file for a Cloudflare Gateway proxy endpoint. The endpoint expects TLS to the proxy,
which is why the file uses the `HTTPS` keyword on port 443.

```js
// proxy.pac for a Cloudflare Gateway proxy endpoint, generated by findproxyforurl.net
function FindProxyForURL(url, host) {
  host = host.toLowerCase();

  // identity provider (Microsoft Entra ID) is bypassed to prevent authentication loops
  if (host == "login.microsoftonline.com" || host == "aadcdn.msauth.net" || host == "aadcdn.msftauth.net") {
    return "DIRECT";
  }

  // plain hostnames (no dot) stay on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // RFC 1918 and loopback addresses: literal IPs only, no DNS lookup for names
  if (/^\d+\.\d+\.\d+\.\d+$/.test(host) &&
      (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") ||
       isInNet(host, "127.0.0.0", "255.0.0.0"))) {
    return "DIRECT";
  }

  // internal domains and their subdomains go direct
  if (dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // default: everything else goes to the Gateway proxy endpoint (TLS to the proxy, hence HTTPS)
  return "HTTPS abc123def0.proxy.cloudflare-gateway.com:443";
}
```

Builder: https://findproxyforurl.net/generate/sse/cloudflare/

### Prisma Access Explicit Proxy

A PAC file for Prisma Access Explicit Proxy on port 8080. The identity provider and the
Authentication Cache Service go direct, because SAML sign-in loops otherwise.

```js
// proxy.pac for Prisma Access Explicit Proxy, generated by findproxyforurl.net
function FindProxyForURL(url, host) {
  host = host.toLowerCase();

  // plain hostnames (no dot) stay on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // RFC 1918 and loopback addresses: literal IPs only, no DNS lookup for names
  if (/^\d+\.\d+\.\d+\.\d+$/.test(host) &&
      (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") ||
       isInNet(host, "127.0.0.0", "255.0.0.0"))) {
    return "DIRECT";
  }

  // internal domains and their subdomains go direct
  if (dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // Explicit Proxy supports HTTP and HTTPS only
  if (url.substring(0, 4) == "ftp:") {
    return "DIRECT";
  }

  // SAML identity provider (Okta) must go direct
  if (dnsDomainIs(host, ".okta.com") || dnsDomainIs(host, ".oktacdn.com")) {
    return "DIRECT";
  }

  // Authentication Cache Service must go direct, otherwise SAML authentication loops
  if (shExpMatch(host, "*.acs.prismaaccess.com")) {
    return "DIRECT";
  }

  // default: everything else goes to Prisma Access Explicit Proxy (port 8080)
  return "PROXY example.proxy.prismaaccess.com:8080";
}
```

Builder: https://findproxyforurl.net/generate/sse/prisma/

## The next step after copying a file

- Read the [annotated reference proxy.pac](https://findproxyforurl.net/examples/reference/) to see why each block is where it
  is.
- Build a file with your own proxies and exceptions in the [PAC file generator](https://findproxyforurl.net/generate/). It
  writes a comment next to every entry.
- Learn to write one yourself in [how to create a PAC file](https://findproxyforurl.net/articles/how-to-create-a-pac-file/).
- Check the [20 most dangerous PAC mistakes](https://findproxyforurl.net/top-20/) before you change a file by hand.


## Frequently asked questions

### Where can I find a simple proxy.pac example?

The first example on this page is the smallest PAC file that works. It sends every request to one proxy. The second one is the most common company file. It keeps internal names and private addresses direct and sends everything else to the proxy.

### Can I use these PAC files as a template?

Yes. All host names and addresses in them are reserved example names (corp.example, example.net, 198.51.100.0/24), so you must replace them with your own. Then test the result in the PAC file checker with the URLs that matter to you.

### What is the difference between these examples and the generator?

The examples are fixed files that show one pattern each. The generator builds a file from your own lists of proxies, hosts, domains and networks, and writes a comment next to every entry.

### Why do the examples not use myIpAddress() or dnsResolve()?

Both make routing depend on things the PAC file cannot control. dnsResolve() makes the browser wait for a DNS lookup, and myIpAddress() returns a different address depending on the browser and the active network adapter. The examples avoid both, which is also why they score A+.

### Do these files work as wpad.dat?

Yes. A wpad.dat is a PAC file under another name. Serve the same content as wpad.dat if your clients find it through WPAD auto-discovery.

