[javascript] What is JSONP, and why was it created?

I understand JSON, but not JSONP. Wikipedia's document on JSON is (was) the top search result for JSONP. It says this:

JSONP or "JSON with padding" is a JSON extension wherein a prefix is specified as an input argument of the call itself.

Huh? What call? That doesn't make any sense to me. JSON is a data format. There's no call.

The 2nd search result is from some guy named Remy, who writes this about JSONP:

JSONP is script tag injection, passing the response from the server in to a user specified function.

I can sort of understand that, but it's still not making any sense.


So what is JSONP? Why was it created (what problem does it solve)? And why would I use it?


Addendum: I've just created a new page for JSONP on Wikipedia; it now has a clear and thorough description of JSONP, based on jvenema's answer.

This question is related to javascript json jsonp terminology

The answer is


TL;DR

JSONP is an old trick invented to bypass the security restriction that forbids us to get JSON data that is in a different website (a different origin1) than the one we are navigating in.

The trick works by using a <script> tag that asks for the JSON from that place, e.g.: { "user":"Smith" }, but wrapped in a function, the actual JSONP ("JSON with Padding"):

peopleDataJSONP({"user":"Smith"})

Receiving it in this form enables us to use the data within our peopleDataJSONP function. JSONP is a bad practice and not needed anymore, don't use it (read below).


The problem

Say we want to use on ourweb.com some JSON data (or any raw data really) hosted at anotherweb.com. If we were to use GET request (think XMLHttpRequest, or fetch call, $.ajax, etc.), our browser would tell us it's not allowed with this ugly error:

Chrome CORS console error

How to get the data we want? Well, <script> tags are not subjected to this whole server (origin1) restriction! That's why we can load a library like jQuery or Google Maps from any server, such as a CDN, without any errors.

Here's the important point: if you think about it, those libraries are actual, runnable JS code (usually a massive function with all the logic inside). But raw data? JSON data is not code. There's nothing to run; it's just plain text.

Therefore, there's no way to handle or manipulate our precious data. The browser will download the data pointed at by our <script> tag and when processing it'll rightfully complain:

wtf is this {"user":"Smith"} crap we loaded? It's not code. I can't compute, syntax error!


The JSONP hack

The old/hacky way to utilize that data? If we could make plain text somehow runnable, we could grab it on runtime. So we need anotherweb.com to send it with some logic, so when it's loaded, your code in the browser will be able to use said data. We need two things: 1) to get the data in a way that it can be run, and 2) write some code in the client so that when the data runs, this code is called and we get to use the data.

For 1) we ask the foreign server to send us the JSON data inside a JS function. The data itself is set up as that function's input. It looks like this:

peopleDataJSONP({"user":"Smith"})

which makes it JS code our browser will parse and run without complaining! Exactly like it does with the jQuery library. To receive the data like that, the client "asks" the JSONP-friendly server for it, usually done like this:

<script src="https://anotherweb.com/api/data-from-people.json?myCallback=peopleDataJSONP"></script>

As per 2), since our browser will receive the JSONP with that function name, we need a function with the same name in our code, like this:

function peopleDataJSONP(data){
  alert(data.user); // "Smith"
}

The browser will download the JSONP and run it, which calls our function, where the argument data will be the JSON data from anotherweb.com. We can now do with our data whatever we want to.


Don't use JSONP, use CORS

JSONP is a cross-site hack with a few downsides:

  • We can only perform GET requests
  • Since it's a GET request triggered by a simple script tag, we don't get helpful errors or progress info
  • There are also some security concerns, like running in your client JS code that could be changed to a malicious payload
  • It only solves the problem with JSON data, but Same-Origin security policy applies to other data (WebFonts, images/video drawn with drawImage()...)
  • It's not very elegant nor readable.

The takeaway is that there's no need to use it nowadays.

You should read about CORS here, but the gist of it is:

Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own.



  1. origin is defined by 3 things: protocol, port, and host. So, for example, https://web.com is a different origin than http://web.com (different protocol) and https://web.com:8081 (different port) and obviously https://thatotherweb.net (different host)

JSONP stands for JSON with Padding.

Here is the site, with great examples, with the explanation from the simplest use of this technique to the most advanced in plane JavaScript:

w3schools.com / JSONP

One of my more favorite techniques described above is Dynamic JSON Result, which allow to send JSON to the PHP file in URL parameter, and let the PHP file also return a JSON object based on the information it gets.

Tools like jQuery also have facilities to use JSONP:

jQuery.ajax({
  url: "https://data.acgov.org/resource/k9se-aps6.json?city=Berkeley",
  jsonp: "callbackName",
  dataType: "jsonp"
}).done(
  response => console.log(response)
);

JSONP is really a simple trick to overcome the XMLHttpRequest same domain policy. (As you know one cannot send AJAX (XMLHttpRequest) request to a different domain.)

So - instead of using XMLHttpRequest we have to use script HTML tags, the ones you usually use to load js files, in order for js to get data from another domain. Sounds weird?

Thing is - turns out script tags can be used in a fashion similar to XMLHttpRequest! Check this out:

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data';

You will end up with a script segment that looks like this after it loads the data:

<script>
{['some string 1', 'some data', 'whatever data']}
</script>

However this is a bit inconvenient, because we have to fetch this array from script tag. So JSONP creators decided that this will work better(and it is):

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data?callback=my_callback';

Notice the my_callback function over there? So - when JSONP server receives your request and finds callback parameter - instead of returning plain js array it'll return this:

my_callback({['some string 1', 'some data', 'whatever data']});

See where the profit is: now we get automatic callback (my_callback) that'll be triggered once we get the data.
That's all there is to know about JSONP: it's a callback and script tags.

NOTE: these are simple examples of JSONP usage, these are not production ready scripts.

Basic JavaScript example (simple Twitter feed using JSONP)

<html>
    <head>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
        <script>
        function myCallback(dataWeGotViaJsonp){
            var text = '';
            var len = dataWeGotViaJsonp.length;
            for(var i=0;i<len;i++){
                twitterEntry = dataWeGotViaJsonp[i];
                text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
            }
            document.getElementById('twitterFeed').innerHTML = text;
        }
        </script>
        <script type="text/javascript" src="http://twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script>
    </body>
</html>

Basic jQuery example (simple Twitter feed using JSONP)

<html>
    <head>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script>
            $(document).ready(function(){
                $.ajax({
                    url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10',
                    dataType: 'jsonp',
                    success: function(dataWeGotViaJsonp){
                        var text = '';
                        var len = dataWeGotViaJsonp.length;
                        for(var i=0;i<len;i++){
                            twitterEntry = dataWeGotViaJsonp[i];
                            text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
                        }
                        $('#twitterFeed').html(text);
                    }
                });
            })
        </script>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
    </body>
</html>


JSONP stands for JSON with Padding. (very poorly named technique as it really has nothing to do with what most people would think of as “padding”.)


A simple example for the usage of JSONP.

client.html

    <html>
    <head>
   </head>
     body>


    <input type="button" id="001" onclick=gO("getCompany") value="Company"  />
    <input type="button" id="002" onclick=gO("getPosition") value="Position"/>
    <h3>
    <div id="101">

    </div>
    </h3>

    <script type="text/javascript">

    var elem=document.getElementById("101");

    function gO(callback){

    script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://localhost/test/server.php?callback='+callback;
    elem.appendChild(script);
    elem.removeChild(script);


    }

    function getCompany(data){

    var message="The company you work for is "+data.company +"<img src='"+data.image+"'/   >";
    elem.innerHTML=message;
}

    function getPosition(data){
    var message="The position you are offered is "+data.position;
    elem.innerHTML=message;
    }
    </script>
    </body>
    </html>

server.php

  <?php

    $callback=$_GET["callback"];
    echo $callback;

    if($callback=='getCompany')
    $response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";

    else
    $response="({\"position\":\"Development Intern\"})";
    echo $response;

    ?>    

JSONP is a great away to get around cross-domain scripting errors. You can consume a JSONP service purely with JS without having to implement a AJAX proxy on the server side.

You can use the b1t.co service to see how it works. This is a free JSONP service that alllows you to minify your URLs. Here is the url to use for the service:

http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack]&url=[escapedUrlToMinify]

For example the call, http://b1t.co/Site/api/External/MakeUrlWithGet?callback=whateverJavascriptName&url=google.com

would return

whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});

And thus when that get's loaded in your js as a src, it will automatically run whateverJavascriptName which you should implement as your callback function:

function minifyResultsCallBack(data)
{
    document.getElementById("results").innerHTML = JSON.stringify(data);
}

To actually make the JSONP call, you can do it about several ways (including using jQuery) but here is a pure JS example:

function minify(urlToMinify)
{
   url = escape(urlToMinify);
   var s = document.createElement('script');
   s.id = 'dynScript';
   s.type='text/javascript';
   s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
   document.getElementsByTagName('head')[0].appendChild(s);
}

A step by step example and a jsonp web service to practice on is available at: this post


Because you can ask the server to prepend a prefix to the returned JSON object. E.g

function_prefix(json_object);

in order for the browser to eval "inline" the JSON string as an expression. This trick makes it possible for the server to "inject" javascript code directly in the Client browser and this with bypassing the "same origin" restrictions.

In other words, you can achieve cross-domain data exchange.


Normally, XMLHttpRequest doesn't permit cross-domain data-exchange directly (one needs to go through a server in the same domain) whereas:

<script src="some_other_domain/some_data.js&prefix=function_prefix>` one can access data from a domain different than from the origin.


Also worth noting: even though the server should be considered as "trusted" before attempting that sort of "trick", the side-effects of possible change in object format etc. can be contained. If a function_prefix (i.e. a proper js function) is used to receive the JSON object, the said function can perform checks before accepting/further processing the returned data.


The great answers have already been given, I just need to give my piece in the form of code blocks in javascript (I will also include more modern and better solution for cross-origin requests: CORS with HTTP Headers):

JSONP:

1.client_jsonp.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/?callback=?",
    dataType: "jsonp",
    success: function(data) {
        console.log(data);    
    }
});??????????????????

2.server_jsonp.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {

    var callback = url.parse(req.url, true).query.callback || "myCallback";
    console.log(url.parse(req.url, true).query.callback);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    data = callback + '(' + JSON.stringify(data) + ');';

    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(data);
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);

CORS:

3.client_cors.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/",
    success: function(data) {
        console.log(data);    
    }
});?

4.server_cors.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {
    console.log(req.headers);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    res.writeHead(200, {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*'
    });

    res.end(JSON.stringify(data));
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);

Before understanding JSONP, you need to know JSON format and XML. Currently the most frequently used data format on the web is XML, but XML is very complicated. It makes users inconvenient to process embedded in Web pages.

To make JavaScript can easily exchange data, even as the data processing program, we use the wording according to JavaScript objects and developed a simple data exchange format, which is JSON. JSON can be used as data, or as a JavaScript program.

JSON can be directly embedded in JavaScript, using them you can directly execute certain JSON program, but due to security constraints, the browser Sandbox mechanism disables cross-domain JSON code execution.

To make JSON can be passed after the execution, we developed a JSONP. JSONP bypass the security limits of the browser with JavaScript Callback functionality and the < script > tag.

So in short it explains what JSONP is, what problem it solves (when to use it).


JSONP works by constructing a “script” element (either in HTML markup or inserted into the DOM via JavaScript), which requests to a remote data service location. The response is a javascript loaded on to your browser with name of the pre-defined function along with parameter being passed that is tht JSON data being requested. When the script executes, the function is called along with JSON data, allowing the requesting page to receive and process the data.

For Further Reading Visit: https://blogs.sap.com/2013/07/15/secret-behind-jsonp/

client side snippet of code

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <title>AvLabz - CORS : The Secrets Behind JSONP </title>
     <meta charset="UTF-8" />
    </head>
    <body>
      <input type="text" id="username" placeholder="Enter Your Name"/>
      <button type="submit" onclick="sendRequest()"> Send Request to Server </button>
    <script>
    "use strict";
    //Construct the script tag at Runtime
    function requestServerCall(url) {
      var head = document.head;
      var script = document.createElement("script");

      script.setAttribute("src", url);
      head.appendChild(script);
      head.removeChild(script);
    }

    //Predefined callback function    
    function jsonpCallback(data) {
      alert(data.message); // Response data from the server
    }

    //Reference to the input field
    var username = document.getElementById("username");

    //Send Request to Server
    function sendRequest() {
      // Edit with your Web Service URL
      requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+"");
    }    

  </script>
   </body>
   </html>

Server side piece of PHP code

<?php
    header("Content-Type: application/javascript");
    $callback = $_GET["callback"];
    $message = $_GET["message"]." you got a response from server yipeee!!!";
    $jsonResponse = "{\"message\":\"" . $message . "\"}";
    echo $callback . "(" . $jsonResponse . ")";
?>

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to json

Use NSInteger as array index Uncaught SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>) HTTP POST with Json on Body - Flutter/Dart Importing json file in TypeScript json.decoder.JSONDecodeError: Extra data: line 2 column 1 (char 190) Angular 5 Service to read local .json file How to import JSON File into a TypeScript file? Use Async/Await with Axios in React.js Uncaught SyntaxError: Unexpected token u in JSON at position 0 how to remove json object key and value.?

Examples related to jsonp

CORS header 'Access-Control-Allow-Origin' missing JSONP call showing "Uncaught SyntaxError: Unexpected token : " jquery.ajax Access-Control-Allow-Origin Parse JSON response using jQuery parsing JSONP $http.jsonp() response in angular.js How can JavaScript save to a local file? Javascript search inside a JSON object IE9 jQuery AJAX with CORS returns "Access is denied" jquery how to use multiple ajax calls one after the end of the other Callback function for JSONP with jQuery AJAX

Examples related to terminology

The differences between initialize, define, declare a variable What is the difference between a web API and a web service? What does "opt" mean (as in the "opt" directory)? Is it an abbreviation? What's the name for hyphen-separated case? What is Bit Masking? What is ADT? (Abstract Data Type) What exactly are iterator, iterable, and iteration? What is a web service endpoint? What is the difference between Cloud, Grid and Cluster? How to explain callbacks in plain english? How are they different from calling one function from another function?