So how does JSONP really work?

JSONP is a way to fetch JSON data from a different domain, often in an asynchronous way, but without being restricted by the browser’s same-origin policy like you would be with XMLHttpRequest. But perhaps you only know it via a library like jQuery, which auto-magically handles JSONP URLs. Here’s a simple JSONP example and breakdown to show what’s really going on behind the scenes.


I was recently quizzed on JSONP and how it works, and my response was something like, mumble … mumble … callback … mumble … use other dudes’ JSON. Okay, maybe not as caveman-like as that, but it wasn’t a great answer.

My experience with JSONP until then had been exclusively through jQuery. jQuery.getJSON() magically switches to JSONP mode when you have a callback parameter in your JSON URL, so what did I care what it was doing under the covers? Something ajax-y and magical. Well, it’s time to learn more.

The simplest JSONP example EVAR

JSONP is actually really simple, so let’s just look at some code. Here’s a working example in six lines:

<script>
function processJSON (json) {
  // Do something with the JSON response
};
</script>

<script src='http://api.flickr.com/services/feeds/photos_public.gne?
jsoncallback=processJSON&tags=monkey&tagmode=any&format=json'></script>

First, we see processJSON() is a Javascript function that we’ve defined in our own code before the Flickr script is called.

Next, note the jsoncallback=processJSON query param in the Flickr API URL. This tells it to return its JSON “padded” inside a Javascript function call that corresponds to the name of our already-defined function. (The server needs to support this special query param, of course.)

Upon running this code, a request will be sent to Flickr, and the response will look like:

processJSON( {
    "title": "Recent Uploads tagged monkey",
    "link": "http://www.flickr.com/photos/tags/monkey/",
    "description": "",
    "modified": "2015-02-03T21:23:22Z",
    "generator": "http://www.flickr.com/",
    "items": [ 
        // ... Much more JSON here ...
    ]
} )

Finally, because Javascript called via the script tag isn’t subject to the browser’s same-origin policy, the response will simply be executed in the browser with our processJSON() function, with the JSON data passed as its argument.

At that point, you do whatever you need to do with the JSON in your function: parse it, filter it, ask it out on a date, etc. You might recognize this as a callback pattern, i.e. after the API request has finished, we tell it to “call us back” via processJSON() with the results.

Breaking it all down

The core elements of JSONP, then, are as such:

  1. callback function defined on your site.
  2. request to the remote API via <script> tag:
    • Includes a special param providing the name of your callback function
  3. The response:
    • Is just Javascript
    • That consists of:
      • A function call, the name of which you specified in the request
      • With the argument being the JSON data of interest
    • Gets executed immediately, as if it were called from your own domain

This callback arrangement between you and the server, combined with avoiding same-origin restrictions, is really the whole trick to JSONP. And as you may have guessed by now, the function padding around JSON data is why it’s called JSONP.

Fundamentally, that’s all that’s going on! Check out the working jsFiddle example.

Making it asynchronous

Now, you don’t absolutely need it to be, but asynchronicity is nice for the consumption of third-party data because it lets us execute code in a way that doesn’t block the page load. One way to do this:

<script>
function processJSON (json) {
  // Do something with the JSON response
};

// Create a new script element
var script_element = document.createElement('script');

// Set its source to the JSONP API
script_element.src = 'http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=processJSON&tags=monkey&tagmode=any&format=json';

// Stick the script element in the page <head>
document.getElementsByTagName('head')[0].appendChild(script_element);
</script>

Adding a script element to the page like this won’t block other components during download. In fact, behind the scenes of jQuery’s getJSON(), this is basically what’s happening; in the case of a JSONP call, XMLHttpRequest is never actually coming into play. jQuery just does some fudging to make it behave like any other true ajax request.

Of course, in practice, jQuery’s JSONP implementation is a little more complex than these examples. But now you have an understanding of the basics.

More reading

Related books you may find useful

  • Kyle

    Thanks for the “Back to Basics” example!
    I have run into some cases where my JQuery was being blocked by the host site and needed to track down a rawJS process.

  • David Land

    Nice article.

    One thing you might want to consider changing would be the statement “Note the jsoncallback=processJSON query param. This is really the whole trick to JSONP.” The callback is really just a convenience mechanism. JSONP could still work without it (maybe the server could put the result in a standardized variable that the browser code knows about). The real trick to JSONP, the thing that makes it valuable (as hacky as it is) would be the statement “Because Javascript called via the script tag isn’t subject to the browser’s same-origin policy, the above code will simply be evaluated and executed in the browser”. That’s really the majick ™ behind JSONP. The technique exploits a choice made early on in HTTP and Javascript that allows you to get around the same origin policy issues you get with regular XMLHttpRequest requests.

    Maybe I’m nitpicking. Like I said, good and helpful article overall.

  • Luciano

    Thanks, I have read a lot of articles to understand what happens with jsonp calls and your explanation is the best.

  • jasonschock

    Thanks for the feedback, David. I just got around to updating this post for better clarity and incorporated your suggestions. Let me know how it reads now.

  • Muhammad

    I read about 4 or 5 so called “basic” or “simple” examples on other sites including stackoverflow that only confused me more until I read yours. Elegantly and professionally explained. I understood it before even completing the article. Extraordinary. I guess I’m just saying a big thank you. Great job