ajaxComplete is a global AjaxEvent (since jQuery 1.0; .on() binding since 1.7). jQuery triggers it on document whenever any qualifying Ajax request finishes — success or error. All registered handlers run.
Remember
$(document).on("ajaxComplete", function (event, jqXHR, ajaxOptions) {
// runs after every qualifying Ajax request finishes
});
// Order (per request):
// ajaxSuccess | ajaxError → ajaxComplete → (ajaxStop when idle)
// Opt out for one call:
$.ajax({ url: "/x", global: false });
Bind once on document, then any jQuery Ajax call can notify that handler.
Attach the handler to document with .on("ajaxComplete", handler).
Make requests with $.ajax(), $.get(), $.post(), or .load().
Optionally filter with ajaxOptions.url (or other settings).
Read the body via jqXHR.responseText when needed.
Use global: false on requests that must stay silent.
Piece
Required?
Role
document
Yes (1.9+)
Only valid bind target for global Ajax events
handler
Yes
function(event, jqXHR, ajaxOptions)
ajaxOptions.url
Optional
Filter which requests you react to
global: false
Optional
Skip all global Ajax events for that call
Pseudocode
Pseudocode
bind ajaxComplete on document with handler(event, jqXHR, ajaxOptions)
when a jQuery Ajax request finishes:
if request.global === false:
do not fire ajaxComplete
return
if request succeeded:
fire ajaxSuccess first
else:
fire ajaxError first
fire ajaxComplete
for each registered handler:
call handler(event, jqXHR, ajaxOptions)
if no other global Ajax requests are active:
fire ajaxStop
Reference
Cheat Sheet
Keep these facts handy while wiring global Ajax cleanup.
Topic
Detail
Bind
$(document).on("ajaxComplete", handler)
Unbind
$(document).off("ajaxComplete" [, handler])
Signature
function(event, jqXHR, ajaxOptions)
When
Every finished request (success + error)
Since
Event 1.0 · .on() form 1.7 · document-only 1.9+
Response body
jqXHR.responseText
Filter
if (ajaxOptions.url === "...")
Opt out
global: false in $.ajax() / $.ajaxSetup()
Try it
Live Preview
Run a real $.get() and watch the global ajaxComplete handler update the log.
Live demo uses a public JSON API. Needs network access.
Result
Ready — pick an action and click Run.
Code
jQuery Examples
Short, copy-ready snippets. Open DevTools Console, or use Try It Yourself for a live editor.
Example 1 — Document Handler + .load()
Official pattern: log a message when any Ajax request completes after a click.
jQuery
$(document).on("ajaxComplete", function () {
$(".log").text("Triggered ajaxComplete handler.");
});
$(".trigger").on("click", function () {
$(".result").load("ajax/test.html");
});
Bind..on("ajaxComplete") on document listens globally.
Click..load() starts an Ajax request under the hood.
Complete. When the request finishes, every ajaxComplete handler runs.
Update. The log text confirms the global event fired.
Example 2 — Filter by settings.url
Handlers run for every request — narrow them with the settings object.
jQuery
$(document).on("ajaxComplete", function (event, xhr, settings) {
if (settings.url === "ajax/test.html") {
$(".log").text(
"Triggered ajaxComplete handler. The result is " +
xhr.responseText
);
}
});
Public $.get → ajaxComplete runs
Private $.ajax({ global: false }) → silent
(per-request .always() still works)
How It Works
Default. Ajax calls participate in global events.
Opt out.global: false skips ajaxComplete (and the other globals).
Local still works..done() / .fail() / .always() still run.
When. Use for silent prefetch, polling, or third-party widgets.
Example 5 — ajaxComplete vs .always()
Global event sees every request; .always() is tied to one call.
jQuery
var globalCount = 0;
var alwaysCount = 0;
$(document).on("ajaxComplete", function () {
globalCount++;
});
$.ajax("/a").always(function () { alwaysCount++; });
$.ajax("/b").always(function () { alwaysCount++; });
// After both finish:
// globalCount === 2, alwaysCount === 2
// but each .always() only saw its own request
Two $.ajax() calls finish
global ajaxComplete count → 2
per-request .always() count → 2
How It Works
Global. One ajaxComplete handler counts every finished request.
Local. Each .always() only increments for its own jqXHR.
Same totals. Counts can match, but the scope is different.
Choose. Site-wide UI → global event; one call’s cleanup → .always().
Edge Cases & Pitfalls
Check these before relying on global Ajax handlers in production.
target
Bind on document only (1.9+)
Handlers on window or other elements will not receive global Ajax events.
scope
Not success-only
ajaxComplete runs after failures too. Use ajaxSuccess / ajaxError or check status when outcome matters.
global
global: false stays silent
Those requests never trigger ajaxComplete. Per-request callbacks still work.
cost
Heavy work in every handler hurts
Parsing large responseText or updating lots of DOM on every request can slow busy pages — filter first.
Compatibility
Browser Support
ajaxComplete has been part of jQuery since 1.0. Prefer $(document).on("ajaxComplete", …) (1.7+). Since 1.9, handlers must attach to document.
✓ Stable · jQuery 1.0+
jQuery ajaxComplete
Works in every browser that runs your loaded jQuery version. Prefer a current jQuery 3.x build for modern projects.
100%jQuery Ajax event
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 for everyday apps. Bind on document, filter by URL when needed, and use global: false for silent background calls.
Analysis
Performance Notes
Approach
Cost
Best for
One filtered ajaxComplete
Cheap
Site-wide loading / logging
Per-request .always()
Cheap
Cleanup for a single call
Heavy DOM work every complete
Expensive
Avoid — filter or debounce
Global handlers are fine when they stay light. Filter by URL before touching the DOM, and prefer .always() for request-specific work.
Remember
Key Takeaways
Role: global “request finished” hook — success or error.
Bind:$(document).on("ajaxComplete", fn) — document only since 1.9.
Filter: inspect ajaxOptions.url; read body via jqXHR.responseText.
Local alternative: use .always() for one-request cleanup.
One line:ajaxComplete is jQuery’s global always-runs-at-the-end Ajax event — bind it on document.
Frequently Asked Questions
ajaxComplete is a global AjaxEvent that fires whenever any qualifying jQuery Ajax request finishes — success or failure. Bind it with $(document).on("ajaxComplete", handler) (since 1.7). Every registered handler runs for every completed request.
Since jQuery 1.9, all global Ajax event handlers must be bound to document — not window or other elements. Use $(document).on("ajaxComplete", fn) and remove with $(document).off("ajaxComplete", fn).
Yes. It always runs after a request completes. On success it follows ajaxSuccess; on failure it follows ajaxError. 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 from $.ajax() — it runs only for that 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() still run.
Three: function(event, jqXHR, ajaxOptions). event is the jQuery event; jqXHR is the request object (read responseText); ajaxOptions is the settings used to create the request (filter with ajaxOptions.url).
The shorthand method .ajaxComplete(handler) is deprecated as of jQuery 3.5. Prefer $(document).on("ajaxComplete", handler) — the event API this page teaches.