← Back to JavaScript Course | Chapter 9: Async & Web APIs | Lesson 18 of 26

JS JSONP

Before CORS existed to explicitly permit cross-origin AJAX requests, developers used a clever workaround called JSONP (JSON with Padding) -- exploiting the fact that <script> tags can load content from any domain, unlike XMLHttpRequest at the time. It is now considered a legacy technique, largely replaced by CORS, but still appears in older code and some third-party APIs.

Why JSONP Exists

Before CORS, browsers strictly blocked JavaScript from making a cross-origin XMLHttpRequest to a different domain -- but a <script> tag has always been allowed to load a script from any domain, so JSONP exploits that loophole: the "response" is actually loaded as if it were a script file.

Note: Understand JSONP as a historical workaround for a limitation (no CORS) that no longer exists in modern browsers and APIs -- CORS is the correct modern solution for the same underlying problem.

Warning: JSONP predates the security-conscious CORS model, and its very technique (executing remote code) is exactly the kind of thing CORS was designed to prevent doing carelessly.

Example: Why JSONP Exists

javascript
<script src="https://api.example.com/data?callback=handleData"></script>
<script>
  function handleData(data) { console.log(data); }
</script>

How JSONP Works

The client defines a global callback function and requests a URL that includes that function's name as a query parameter -- the server wraps its JSON data in a call to that exact function name, so when the returned "script" loads and executes, it automatically calls your function with the data as an argument.

Note: Make sure your callback function is defined and globally accessible before the JSONP script tag attempts to load, or the call will fail with a "function not defined" error.

Warning: The callback function name in the request and the function name the server wraps the data in must match exactly, or nothing happens when the script loads.

Example: How JSONP Works

javascript
function handleData(data) {
  console.log("Received:", data);
}
// Server responds with: handleData({"name": "Sam"});
// which calls handleData automatically once the "script" loads

Dynamically Creating a JSONP Request

Rather than hardcoding a <script> tag in the HTML, JSONP requests are typically triggered dynamically -- creating a new <script> element with JavaScript, setting its src to the target URL, and appending it to the document, which starts the request immediately.

Note: Remove the dynamically created script tag after it finishes loading (in the callback, or via an onload handler) to keep the DOM clean if many JSONP requests will be made over time.

Warning: A dynamically created JSONP request has no built-in way to detect a failure the way fetch's .catch() does -- a failed or blocked script load can leave your callback simply never called, with no direct error signal.

Example: Dynamically Creating a JSONP Request

javascript
function handleData(data) { console.log(data); }
const script = document.createElement("script");
script.src = "https://api.example.com/data?callback=handleData";
document.body.appendChild(script);

JSONP's Limitations

JSONP only supports GET requests, since it relies on loading a URL as a script -- there is no equivalent for sending a POST body. It also offers no clean way to detect a failed request (no error callback is standard), and it executes the response as real, unrestricted JavaScript in your page.

Note: Never use JSONP for anything beyond a simple, read-only GET request, and only when the target API genuinely does not support CORS.

Warning: Because a JSONP response executes as arbitrary JavaScript in your page's context, only use it against APIs and domains you genuinely trust -- a malicious or compromised server could run harmful code through this channel.

Example: JSONP's Limitations

javascript
// JSONP limitations:
// - only supports GET (loading a URL as a script)
// - no built-in error callback if the request fails
// - executes the response as full, unrestricted JavaScript
console.log("Use CORS with fetch() instead when the API supports it.");

JSONP vs CORS: When to Use Which

For any API you control, or any modern third-party API, CORS is the correct, secure choice -- it lets the server explicitly declare which origins may access it, and works with the full range of HTTP methods and the safer fetch API. JSONP remains relevant only for old APIs that never added CORS support.

Note: Check first whether an API supports CORS before reaching for JSONP -- most modern public APIs do, making JSONP unnecessary.

Warning: Choosing JSONP for a new integration when CORS is available adds unnecessary security risk and GET-only limitations for no real benefit.

Example: JSONP vs CORS: When to Use Which

javascript
fetch("https://api.example.com/data").then(r => r.json()).then(data => console.log(data));
console.log("Prefer CORS/fetch whenever the server supports it.");
Common Mistakes
  1. Using JSONP for a new project today when the target API supports CORS -- JSONP has real security downsides and should only be used when CORS is genuinely unavailable.
  2. Forgetting that JSONP only supports GET requests, since it works by loading a script, and scripts cannot carry a POST body.
  3. Not recognizing that JSONP executes arbitrary code from the remote server directly in your page's context, which is a meaningful security consideration compared to a same-origin-protected JSON fetch.
Chapter Summary
  • JSONP works by dynamically inserting a <script> tag whose src points to the remote API, sidestepping the same-origin restriction that blocks a plain cross-origin XMLHttpRequest.
  • The remote server wraps its JSON data in a call to a callback function name the client specifies, which executes automatically once the script loads.
  • JSONP only supports GET requests and executes the remote server's response as actual JavaScript, a real security consideration.
Browser Support

JSONP relies only on basic <script> tag loading, supported in every browser since the earliest days of the web; it predates and is now largely superseded by CORS.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.