jQuery ajaxComplete Event

Beginner
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Ajax events

What You’ll Learn

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

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 ajaxComplete event (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.

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 after ajaxSuccess (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.

📝 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.
  • ajaxOptions — settings passed to $.ajax() (url, type, data, context, etc.).

2. Official demo — document handler + .load() on click

jQuery
$( document ).on( "ajaxComplete", function() {
  $( ".log" ).text( "Triggered ajaxComplete handler." );
} );

$( ".trigger" ).on( "click", function() {
  $( ".result" ).load( "ajax/test.html" );
} );

3. Filter by URL — inspect ajaxOptions

jQuery
$( document ).on( "ajaxComplete", function( event, xhr, settings ) {
  if ( settings.url === "ajax/test.html" ) {
    $( ".log" ).text( "Triggered ajaxComplete handler. The result is " +
      xhr.responseText );
  }
} );

4. Unbind — $(document).off("ajaxComplete" [, handler])

jQuery
$( document ).off( "ajaxComplete" );              // remove all ajaxComplete handlers
$( document ).off( "ajaxComplete", myHandler );   // remove one handler

5. Deprecated method — .ajaxComplete(handler)

jQuery
// Deprecated — use .on("ajaxComplete") instead
$( document ).ajaxComplete( function( event, xhr, settings ) {
  console.log( "Request finished:", settings.url );
} );

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.

⚡ Quick Reference

GoalCode
Bind global complete handler$(document).on("ajaxComplete", fn)
Handler signaturefunction(event, jqXHR, ajaxOptions)
Read response textjqXHR.responseText
Filter by URLif (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")

📋 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: ajaxStartajaxSendajaxSuccess | ajaxErrorajaxCompleteajaxStop. ajaxStart and ajaxStop bracket the set of active global requests — they fire when the first request begins and when the last one finishes.

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.

jQuery
$( document ).on( "ajaxComplete", function() {
  $( ".log" ).text( "Triggered ajaxComplete handler." );
} );

$( ".trigger" ).on( "click", function() {
  $( ".result" ).load( "ajax/test.html" );
} );
Try It Yourself

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 );
  }
} );
Try It Yourself

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.

jQuery
$( document ).on( "ajaxComplete", function( event, request, settings ) {
  $( "#msg" ).append( " Request Complete. " );
} );
Try It Yourself

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.

jQuery
var globalCount = 0;

$( document ).on( "ajaxComplete", function() {
  globalCount++;
  $( "#log" ).append( " ajaxComplete (" + globalCount + ")" );
} );

$( "#global-btn" ).on( "click", function() {
  $.get( "/api/public" );
} );

$( "#private-btn" ).on( "click", function() {
  $.ajax( { url: "/api/private", global: false } );
} );
Try It Yourself

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.

jQuery
var globalComplete = 0;
var perRequestAlways = 0;

$( document ).on( "ajaxComplete", function() {
  globalComplete++;
  $( "#global-count" ).text( globalComplete );
} );

$( "#run-two" ).on( "click", function() {
  $.ajax( "/api/a" ).always( function() {
    perRequestAlways++;
    $( "#always-count" ).text( perRequestAlways );
  } );
  $.ajax( "/api/b" ).always( function() {
    perRequestAlways++;
    $( "#always-count" ).text( perRequestAlways );
  } );
} );
Try It Yourself

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.

🚀 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.

📝 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.

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 Chrome All versions · Desktop & Mobile
Full support
Mozilla Firefox All versions · Desktop & Mobile
Full support
Apple Safari All versions · macOS & iOS
Full support
Microsoft Edge All versions · Chromium & Legacy
Full support
Internet Explorer IE 6+ · Legacy environments
Full support
Opera All modern versions
Full support
ajaxComplete Universal

Bottom line: Safe in any jQuery project using $.ajax(), $.get(), $.post(), or .load(). Prefer .on('ajaxComplete') over deprecated .ajaxComplete().

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.

💡 Best Practices

✅ Do

  • Bind on $(document).on("ajaxComplete", 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

Key Takeaways

Knowledge Unlocked

Six things to remember about ajaxComplete

Global, always, on document.

6
Core concepts
✓✗ 02

Always

Success + error

Behavior
url 03

settings

Filter

ajaxOptions
txt 04

responseText

Read body

jqXHR
off 05

global:false

Opt out

Private
.on 06

.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.

Next: .ajaxComplete() Method

Learn the deprecated shorthand for binding global ajaxComplete handlers — and how to migrate to .on().

.ajaxComplete() method tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful