If you try to access data in a different domain from a client-side app, you’ll often get an error about CORS (cross-origin resource sharing). I’ve dealt with this topic before in Cross Origin Resource sharing (CORS), where there is some code that does that from a client. However, this only works if the server you are talking to supports CORS.

What’s it all about

Before CORS was widely implemented, JSONP was pretty much the only way you could get data stored on a different domain into your client-side APP, unless you happened to have a server to use, but that relied on the app you were querying supporting JSONP. For those that didn’t, there are many examples of PHP proxy scripts, including on this site, to be able to take data from one site, wrap it in JSONP and send it to the client requestor. Nowadays it’s less common to have a handy server, as we use more cloud-based solutions.

Apps Script as a proxy

Since Apps Script runs on a server, sites are generally quite happy to serve up JSON data to it, so this means that you can get away from needing PHP and a server as a proxy, since you can just use Apps Script. Here’s a simple script you can publish as a webapp to do this for you. It’s also on github.
function doGet(e) {

  var result = work (e);
  var s = JSON.stringify(result);

  // publish result
  return ContentService
    .createTextOutput(result.proxy.params.callback ? result.proxy.params.callback + "(" + s + ")" : s )
    .setMimeType(result.proxy.params.callback ? ContentService.MimeType.JAVASCRIPT : ContentService.MimeType.JSON); 
 * do the work
 * @param {object} e the doget object
 * @param {string} e.parameter.url the url
 * @param {string} e.parameter.options any options
 * @param {string} e.parameter.callback the callback
 * @return {object} the result 
function work (e) {
  // for testing
  var result = {
      params:e ? e.parameter : null
  if (!e || !e.parameter || !e.parameter.url) {
    result.proxy.error = "no url specified";
  else {
    var options = e.parameter.options ? JSON.parse(e.parameter.options) : {method:"GET"}
    var response;
    options.muteHttpExceptions = true;
    try {
      response = UrlFetchApp.fetch(result.proxy.params.url, options);
      result.result = response.getContentText();
      result.responseCode = response.getResponseCode();
    catch (err) {
      result.proxy.error = err;

  return result;

To use

Once your webapp is published, you can invoke it with this url from your client app.

webappPublishedUrl?url=encodeURIComponent (yourUrl)&callback=yourcallback

if jQuery, then you can use

webappPublishedUrl?url=encodeURIComponent (yourUrl)&callback=?

The response

Your callback will return this object

  proxy: {
     params: { the params you sent over}
     error: if present then there was a failure
  result: the text result from accessing your target url
  reponseCode: the http response code from accessing your target url

And that’s it.

Since I moved off my own server to Cloud Storage, I’ve had to migrate from the PHP proxy I was using before. An example of it can be seen in Flight data from Fusion which takes a whole heap of data from Google Fusion, Google Sheets and a few other places to create a visualization of flights and airline on-time performance using d3.js

For more like this, see Google Apps Scripts Snippets

Why not join our forum, follow the blog or follow me on Twitter to ensure you get updates when they are available.