The ajaxComplete event fires when any qualifying jQuery Ajax request finishes — success or error. This tutorial covers binding on document with .on("ajaxComplete"), the handler signature (event, jqXHR, ajaxOptions), filtering by ajaxOptions.url, reading xhr.responseText, opting out with global: false, and comparing global events with per-request .always().
01
Global
AjaxEvent
02
document
Bind target
03
Always
Success + error
04
settings
Filter URL
05
global:false
Opt out
06
Since 1.7
.on() API
Fundamentals
Introduction
When your page loads data with $.ajax(), $.get(), $.post(), or .load(), jQuery broadcasts lifecycle events to listeners on document. The ajaxComplete event is your “always runs at the end” hook — it fires after every qualifying request completes, whether the server returned 200 or the call failed.
The official jQuery API distinguishes the ajaxCompleteevent (bound with .on("ajaxComplete") since 1.7) from the deprecated .ajaxComplete()method used in older code. Unlike ajaxSuccess or ajaxError, which fire only for one outcome, ajaxComplete runs in both cases — and all registered handlers execute for every completed request.
Concept
Understanding the ajaxComplete Event
ajaxComplete is classified as an AjaxEvent — a global event triggered by jQuery’s Ajax transport, not a DOM event on a specific element. Whenever an Ajax request completes, jQuery triggers ajaxComplete on document. Handlers receive three arguments: the native event object, the jqXHR object (same as the XMLHttpRequest wrapper returned by $.ajax()), and ajaxOptions — the plain settings object used to create that request.
The handler runs afterajaxSuccess (if the request succeeded) or ajaxError (if it failed). You can read the response body from the second argument: jqXHR.responseText (or xhr.responseText in the official docs). To react only to certain URLs, inspect ajaxOptions.url inside the handler.
💡
Beginner Tip
Bind once on $(document).on("ajaxComplete", fn) instead of adding a completion callback to every $.ajax() call. Use global: false on requests that should not notify global listeners — for example, background polling or third-party widgets.
Foundation
📝 Syntax
The modern jQuery API for the ajaxComplete global event:
1. Bind a handler — $(document).on("ajaxComplete" [, handler]) (since 1.7)
jQuery
$( document ).on( "ajaxComplete", handler )
handler — function invoked when any qualifying Ajax request completes: function( event, jqXHR, ajaxOptions ) { ... }.
event — the jQuery event object.
jqXHR — the jqXHR / XMLHttpRequest object; read jqXHR.responseText for the response body.
The old .ajaxComplete(handler) binding method still works but is deprecated. Migrate to $(document).on("ajaxComplete", handler) for consistency with other events and reliable unbinding via .off().
Return value
.on("ajaxComplete", handler) returns the jQuery object (document wrapped) for chaining.
Handler return values are ignored by jQuery’s global Ajax event system.
Cheat Sheet
⚡ Quick Reference
Goal
Code
Bind global complete handler
$(document).on("ajaxComplete", fn)
Handler signature
function(event, jqXHR, ajaxOptions)
Read response text
jqXHR.responseText
Filter by URL
if (ajaxOptions.url === "/api/x")
Opt out of global events
$.ajax({ url: "/x", global: false })
Per-request cleanup
$.ajax(...).always(fn)
Remove handlers
$(document).off("ajaxComplete")
Compare
📋 ajaxComplete vs .always() vs ajaxSuccess / ajaxError
Four ways to react when an Ajax request finishes — choose the scope and outcome that match your task.
ajaxComplete
global
Document event — runs for every qualifying request, success or error
.always()
per call
jqXHR callback — runs once for a single $.ajax() invocation
ajaxSuccess
2xx only
Global event — fires only when the request succeeds
ajaxError
fail only
Global event — fires only when the request fails
Global event order for each request: ajaxStart → ajaxSend → ajaxSuccess | ajaxError → ajaxComplete → ajaxStop. ajaxStart and ajaxStop bracket the set of active global requests — they fire when the first request begins and when the last one finishes.
Hands-On
Examples Gallery
Examples 1, 3, and 4 follow the official jQuery API documentation. Examples 2 and 5 extend those patterns with URL filtering and a comparison with .always(). Use the Try-it links to run each snippet in the browser.
📚 Official Patterns
Document-level handlers that observe every qualifying Ajax request.
Example 1 — Official Demo: Document Handler + .load() on Click
Attach ajaxComplete on document, then trigger an Ajax request with .load() when the user clicks .trigger.
User clicks .trigger → .load() runs Ajax request
When request completes → .log shows "Triggered ajaxComplete handler."
Works for $.ajax(), $.get(), $.post(), and .load()
How It Works
.load() is implemented with $.ajax() internally, so it triggers global Ajax events. The ajaxComplete handler on document runs after the HTML fragment is fetched — regardless of success or failure.
Example 2 — Filter by settings.url
All ajaxComplete handlers run for every request — use ajaxOptions.url to narrow the callback to one endpoint.
jQuery
$( document ).on( "ajaxComplete", function( event, xhr, settings ) {
if ( settings.url === "ajax/test.html" ) {
$( ".log" ).text( "Triggered ajaxComplete handler. The result is " +
xhr.responseText );
}
} );
Request to ajax/test.html completes → .log shows handler message + responseText
Request to other URLs → handler runs but if-block skipped
Use settings.type, settings.context, or custom keys to filter further
How It Works
jQuery passes the same settings object used in $.ajax(settings) as the third argument. Compare settings.url (or a custom property you add to settings) before updating the DOM or logging.
Example 3 — Official Demo: Append “Request Complete.” to #msg
Show a message in the page whenever any Ajax request completes.
Each qualifying Ajax request → #msg gains " Request Complete. "
Three parallel requests → three appended messages
Ideal for a simple activity log or status strip
How It Works
Because ajaxComplete fires for every global request, appending to #msg builds a running log. Pair with URL filtering if you only want messages for specific endpoints.
📈 Opt-Out & Per-Request Comparison
global: false and when to prefer .always() over global events.
Example 4 — global: false — Event Does Not Fire
Requests with global: false skip all global Ajax events, including ajaxComplete.
Click #global-btn → ajaxComplete fires → log updated
Click #private-btn → request completes but ajaxComplete does NOT fire
Per-request .always() on the private call still runs
How It Works
Setting global: false on an individual $.ajax() call (or via $.ajaxSetup({ global: false })) opts that request out of ajaxStart, ajaxSend, ajaxSuccess, ajaxError, ajaxComplete, and ajaxStop.
Example 5 — Compare Global ajaxComplete Counter vs Per-Request .always()
One global handler increments a page-wide counter; each $.ajax() call uses .always() for its own cleanup.
Click #run-two → two $.ajax() calls
globalComplete → +2 (one ajaxComplete per request)
perRequestAlways → +2 (one .always() per call)
Global = one listener, all requests; .always() = scoped to each jqXHR
How It Works
ajaxComplete centralizes cross-cutting concerns (spinners, analytics). .always() keeps cleanup next to the call site — hide a row-specific loader, re-enable one button, etc. Both run on success and failure.
Applications
🚀 Common Use Cases
Activity logging — append “Request complete” to a debug panel for every Ajax call during development.
Analytics hooks — send timing or URL data to monitoring when ajaxComplete fires, filtered by settings.url.
Shared cleanup — reset shared UI state after any request finishes, complementing ajaxStart / ajaxStop spinners.
Response inspection — read xhr.responseText in a global handler for logging (avoid parsing large bodies on every request in production).
Third-party isolation — set global: false on widget requests so they do not trigger your global ajaxComplete logic.
Testing — assert that a test harness saw the expected number of completed requests via a global counter.
🧠 Global Ajax Event Order
1
ajaxStart
First active global request begins — show a page-wide loading indicator.
ajaxStart
2
ajaxSend
Just before the request is sent — last chance to modify headers globally.
ajaxSend
3
ajaxSuccess or ajaxError
Outcome-specific global event — success handler or error handler runs.
success | error
4
ajaxComplete
Always runs after step 3 — all registered ajaxComplete handlers execute.
ajaxComplete
5
👉
ajaxStop
Last active global request finished — hide the loading indicator.
Important
📝 Notes
Bind with $(document).on("ajaxComplete", handler) since jQuery 1.7 — not the deprecated .ajaxComplete(handler) method.
Since jQuery 1.9, attach global Ajax handlers to document — not window.
ajaxComplete fires for success and error — after ajaxSuccess or ajaxError.
Every registered handler runs for every completed qualifying request.
Requests with global: false do not trigger ajaxComplete.
Read the response with jqXHR.responseText (official docs use parameter name xhr).
Differentiate requests with ajaxOptions.url, ajaxOptions.type, or custom settings properties.
For per-request cleanup, prefer $.ajax(...).always(fn) over a global handler with heavy filtering.
Compatibility
Browser Support
The ajaxComplete event is a jQuery global Ajax event — not a native DOM event. It works wherever jQuery’s Ajax transport runs: all browsers supported by your jQuery version. Bind with .on("ajaxComplete") since 1.7; attach handlers to document since 1.9.
✓ jQuery 1.7+
jQuery ajaxComplete event
Supported in jQuery 1.x, 2.x, and 3.x across all modern browsers and IE with supported jQuery builds. Requires jQuery Ajax — requests made with fetch() or axios do not trigger jQuery global events.
100%With jQuery Ajax
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
ajaxCompleteUniversal
Bottom line: Safe in any jQuery project using $.ajax(), $.get(), $.post(), or .load(). Prefer .on('ajaxComplete') over deprecated .ajaxComplete().
Wrap Up
Conclusion
The jQuery ajaxComplete event is the global “request finished” hook — it runs after every qualifying Ajax call, success or error. Bind handlers on document with .on("ajaxComplete", fn), inspect ajaxOptions to filter by URL, and read jqXHR.responseText when you need the raw response.
Remember the event order: ajaxSuccess or ajaxError first, then ajaxComplete, then ajaxStop when no global requests remain. Use global: false to opt out. For logic tied to one call, chain .always() on the jqXHR instead of growing a global handler.
Filter with ajaxOptions.url when the handler should not run for every request
Pair with ajaxStart / ajaxStop for loading indicators
Use global: false for silent background or third-party requests
Remove handlers with $(document).off("ajaxComplete") on SPA teardown
❌ Don’t
Attach global handlers to window — use document since jQuery 1.9
Use deprecated .ajaxComplete(handler) in new code
Assume ajaxComplete means success — check status or use ajaxSuccess
Parse large responseText in every global handler — hurts performance
Duplicate per-request .always() logic inside a global handler without filtering
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about ajaxComplete
Global, always, on document.
6
Core concepts
doc01
document
Bind here
Global
✓✗02
Always
Success + error
Behavior
url03
settings
Filter
ajaxOptions
txt04
responseText
Read body
jqXHR
off05
global:false
Opt out
Private
.on06
.on()
Not .ajaxComplete()
Modern
❓ Frequently Asked Questions
ajaxComplete is a global Ajax event (AjaxEvent) that fires whenever any qualifying jQuery Ajax request finishes — whether it succeeded or failed. Bind handlers with $(document).on('ajaxComplete', handler) since version 1.7. Every registered handler runs for every completed request.
Since jQuery 1.9, all global Ajax event handlers — including ajaxComplete — must be bound to document, not window or other elements. Use $(document).on('ajaxComplete', fn) and $(document).off('ajaxComplete', fn) to remove them.
Yes. ajaxComplete always runs after a request completes, regardless of HTTP status or transport errors. It fires after ajaxSuccess (on success) or ajaxError (on failure). Use those outcome-specific events when you only care about one result.
ajaxComplete is a global document event — one handler observes every qualifying request on the page. always() is per-request on the jqXHR returned by $.ajax() — it runs only for that single call. Use global events for site-wide UI; use always() for request-specific cleanup.
When $.ajax() or $.ajaxSetup() sets global: false, that request opts out of all global Ajax events. ajaxComplete will not fire for it. Per-request done(), fail(), and always() callbacks still run normally.
Inspect the handler arguments: function(event, jqXHR, ajaxOptions). The ajaxOptions object is the settings used to create the request — compare ajaxOptions.url, ajaxOptions.type, or a custom ajaxOptions.context to filter handlers to specific calls.
Did you know?
jQuery fires ajaxComplete for every registered handler — if three functions listen on document, all three run when one request finishes. That differs from ajaxSuccess and ajaxError, which are also global but outcome-specific. The deprecated .ajaxComplete(fn) method is equivalent to .on("ajaxComplete", fn); jQuery 1.7 unified binding under .on() alongside mouse and keyboard events.