Skip to content
This repository


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

A simple polyfill for cross-origin ajax requests.

branch: master

Fetching latest commit…


Cannot retrieve the latest commit at this time

Octocat-spinner-32 test
Octocat-spinner-32 ppx.jquery.js
Octocat-spinner-32 ppx.js

PostMessage Proxied XMLHttpRequest (PPX) is a simple polyfill that allows browsers without support for cross-origin XMLHttpRequests to do so via postMessage.

The code has no dependencies and does not require JSON, which makes it about 2KB minified and gzipped.

A simple jQuery plugin that allows jQuery-based ajax requests to transparently use the polyfill is also available.


Suppose you have a website at which exposes a cross-origin REST API that you'd like to access from

Create a file at and put the following code in it:

<!DOCTYPE html>
<meta charset="utf-8">
<title>PPX Server Frame</title>
<script src="ppx.js"></script>

This is the host iframe which will proxy requests for you.

Basic Use

From a page on, you can access like so:

<script src=""></script>
  var FooXHR = PPX.buildClientConstructor("");
  var req = new FooXHR();"GET", "");
  req.onreadystatechange = function() {
    if (req.readyState == 4 && req.status == 200)
      alert("the response is " + req.responseText);

As you can probably guess, PPX.buildClientConstructor() returns an object much like window.XMLHttpRequest. This can then be used as-is, or given to another third-party library to make cross-origin communication as familiar as a normal ajax request.

Using PPX with jQuery

The above example can be made simpler using the PPX jQuery plugin:

<script src=""></script>
<script src=""></script>
<script src=""></script>
  jQuery.get("", function(data) {
    alert("the response is " + data);

The call jQuery.proxyAjaxThroughPostMessage() sets up an ajax prefilter which will automatically proxy requests to if the host browser doesn't already support CORS.

Using PPX with jQuery and yepnope.js

You can use PPX with yepnope.js and jQuery, too:

<script src=""></script>
<script src="yepnope.js"></script>
    nope: ["", ""],
    complete: function() {
      if (!
      jQuery.get("", function(data) {
        alert("the response is " + data);

This will only load PPX's JS code if CORS support isn't detected in the host browser.


After cloning the git repository and entering its directory, you can start the development server by running:


This will start two local web servers on ports 9000 and 9001. The functional tests make CORS requests from one to the other to ensure that everything works as expected.

To start the tests, browse to http://localhost:9000/test/.


Currently, the following features of the XMLHttpRequest API are unsupported:

  • username and password arguments to open()
  • getResponseHeader() (though getAllResponseHeaders() is supported)
  • responseXML

Several features of the massive CORS Specification are unsupported:

  • Only simple requests can be sent; anything requiring a preflighted request will be rejected for security purposes.

  • Response headers aren't automatically culled down to the simple response header list as prescribed by the spec.

  • Because the Origin header can't be set by the same-origin proxied request, PPX sets an X-Original-Origin header with the origin of the window making the request. This may be used by servers in place of Origin, e.g. to set the appropriate value for Access-Control-Allow-Origin in the response.

  • Because the same-origin proxied request can't control whether or not a cookie is transmitted during its request, all cross-origin requests sent should be assumed to have them. Note that we don't currently check the value of Access-Control-Allow-Credentials before returning responses, either, so be very careful if your site uses cookies.

Similar Projects

pmxdr provides similar functionality but doesn't provide an XMLHttpRequest API, so it can't necessarily be used as a drop-in replacement. It's also larger than PPX, but supports more features out-of-the-box.

Something went wrong with that request. Please try again.