The ajaxStop event fires when the last qualifying jQuery Ajax request completes — and only when no other global requests remain active. This tutorial covers binding on document with .on("ajaxStop"), pairing with ajaxStart for loading indicators, opting out with global: false, and comparing ajaxStop with per-request events like ajaxComplete.
01
Global
AjaxEvent
02
document
Bind target
03
Last only
Not every call
04
ajaxStart
Pair for UI
05
global:false
Opt out
06
Since 1.7
.on() API
Fundamentals
Introduction
When your page loads data with $.ajax(), $.get(), or .load(), jQuery broadcasts lifecycle events to listeners on document. The ajaxStop event is your “all activity finished” hook — it fires once when the last active global Ajax request completes, giving you a single place to hide a loading spinner or re-enable navigation.
jQuery tracks how many global Ajax calls are in progress. When the count drops to zero, jQuery triggers ajaxStop. That pairing with ajaxStart — which fires when the count goes from 0 to 1 — makes ajaxStop ideal for page-wide loading UI without counting individual requests yourself. If the last outstanding request is cancelled via beforeSend returning false, ajaxStop still fires when no requests remain active.
Concept
Understanding the ajaxStop Event
ajaxStop is classified as an AjaxEvent — a global event triggered by jQuery’s Ajax transport, not a DOM event on a specific element. Whenever the last active global Ajax request finishes and no others remain, jQuery triggers ajaxStop on document. Handlers are simple callbacks with no extra arguments — unlike ajaxComplete, you do not receive jqXHR or settings.
The handler runs at the very end of global Ajax activity — after ajaxComplete on the last request, and after any success or error handlers. For per-request logging or response inspection, use ajaxComplete instead. For hiding the spinner when all requests finish, bind ajaxStop alongside ajaxStart.
💡
Beginner Tip
Bind once: $(document).on("ajaxStart", showSpinner) and $(document).on("ajaxStop", hideSpinner). Three parallel $.get() calls trigger ajaxStart once and ajaxStop once — not three times each.
Foundation
📝 Syntax
The modern jQuery API for the ajaxStop global event:
1. Bind a handler — $(document).on("ajaxStop" [, handler]) (since 1.7)
jQuery
$( document ).on( "ajaxStop", handler )
handler — function invoked when the last global Ajax request completes: function() { ... } — no jqXHR or settings arguments.
Fires only when no global requests remain in progress.
Must attach to document since jQuery 1.9.
2. Official demo — document handler + .load() on click
The old .ajaxStop(handler) binding method still works but is deprecated since jQuery 3.5. Migrate to $(document).on("ajaxStop", handler). This page covers the ajaxStop event — not the deprecated shorthand method.
Return value
.on("ajaxStop", 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 stop handler
$(document).on("ajaxStop", fn)
Handler signature
function() — no extra arguments
When it fires
Last global request completes (none remain active)
Show spinner when activity begins
$(document).on("ajaxStart", fn)
Per-request hook
$(document).on("ajaxComplete", fn)
Opt out of global events
$.ajax({ url: "/x", global: false })
Remove handlers
$(document).off("ajaxStop")
Compare
📋 ajaxStop vs ajaxComplete vs ajaxStart
Three global events at different points in the lifecycle — choose the scope that matches your task.
ajaxStop
last only
Fires once when the last active global request finishes — hide page-wide loading UI
ajaxComplete
every call
Fires after each request finishes — success or error — with jqXHR and settings
ajaxStart
first only
Fires once when the first global request begins — show loading UI
ajaxSend
every call
Fires before each individual request is sent — receives jqXHR and settings
Global event order: ajaxStart → ajaxSend → ajaxSuccess | ajaxError → ajaxComplete → ajaxStop. ajaxStart and ajaxStop bracket the batch; ajaxSend and ajaxComplete fire per request.
Hands-On
Examples Gallery
Examples 1 and 2 follow the official jQuery API documentation. Examples 3–5 extend those patterns with parallel requests, global: false, and an ajaxStart + ajaxStop loading pair with ajaxStop as the focus. Use the Try-it links to run each snippet in the browser.
📚 Official Patterns
Document-level handlers that observe when global Ajax activity ends.
Example 1 — Official Demo: Document Handler + .load() on Click
Attach ajaxStop on document, then trigger an Ajax request with .load() when the user clicks .trigger.
Last Ajax request completes → #loading becomes hidden
Pair with ajaxStart to show when activity begins
Ideal for a page-wide spinner or "Loading..." banner
How It Works
ajaxStop is designed for this use case — one handler hides UI when global activity ends. Without ajaxStart, you need another way to show the indicator when requests begin.
Example 3 — Parallel Requests: ajaxStop Fires Once
Launch two $.get() calls at once — ajaxStop runs only when the last one finishes, not twice.
Click #run-two → two parallel $.get() calls
stopCount increments by 1 (not 2)
ajaxComplete would fire twice — ajaxStop fires once per batch
How It Works
jQuery tracks active global requests internally. The second parallel call keeps the count above zero until it also finishes, so ajaxStop fires once when both are done. Use ajaxComplete if you need a hook for every individual finished request.
📈 Opt-Out & ajaxStart Pairing
global: false and the complete loading-indicator pattern with ajaxStart.
Example 4 — global: false — Event Does Not Fire
Requests with global: false skip all global Ajax events, including ajaxStop.
Click #global-btn → ajaxStop fires → log updated
Click #private-btn → request runs but ajaxStop does NOT fire
Private requests do not count toward active global batch
How It Works
Setting global: false opts that request out of ajaxStart, ajaxSend, ajaxComplete, and ajaxStop. Use it for background polling or third-party widgets that should not affect your page-wide loading UI.
Example 5 — Pair ajaxStart + ajaxStop for Loading UI
Show a spinner when global activity begins and hide it when the last request finishes — the canonical loading-indicator pattern with ajaxStop as the hide hook.
ajaxStart and ajaxStop are designed as a pair. You do not need to count requests — jQuery tracks active global calls and fires ajaxStop only when the count returns to zero. This example highlights ajaxStop as the hide hook.
Applications
🚀 Common Use Cases
Loading spinners — hide a page-wide indicator when the last Ajax request completes; show it on ajaxStart.
Re-enable navigation — unlock buttons or allow form submission when global Ajax activity ends.
Activity badges — clear a “Loading…” status flag once per batch instead of per request.
Analytics — record when a page-wide Ajax session ended (pair with ajaxStart for duration).
Third-party isolation — set global: false on widget requests so they do not delay your ajaxStop UI.
Testing — assert that a test harness left the “loading” state exactly once per batch.
🧠 Global Ajax Event Order
1
ajaxStart
First active global request begins — show loading UI. Fires once per batch, not per request.
ajaxStart
2
ajaxSend
Before each individual request is sent — all registered handlers execute with jqXHR and settings.
ajaxSend
3
ajaxSuccess or ajaxError
Outcome-specific global event — success handler or error handler runs per request.
success | error
4
ajaxComplete
Always runs after step 3 for each request — finished, success or error.
ajaxComplete
5
👉
ajaxStop
Last active global request finished — hide loading UI. Fires once when the batch completes.
Important
📝 Notes
Bind with $(document).on("ajaxStop", handler) since jQuery 1.7 — not the deprecated .ajaxStop(handler) method.
Since jQuery 1.9, attach global Ajax handlers to document — not window.
Fires only when no global requests remain in progress — not for every individual call.
Handler receives no extra arguments — use ajaxComplete for jqXHR and settings.
Always pair with ajaxStart when showing loading UI — otherwise nothing shows the indicator at the start.
Requests with global: false do not trigger ajaxStop and do not count as active global requests.
Multiple parallel requests share one ajaxStart / ajaxStop pair.
If the last outstanding request is cancelled via beforeSend returning false, ajaxStop still fires when no requests remain active.
Compatibility
Browser Support
The ajaxStop 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("ajaxStop") since 1.7; attach handlers to document since 1.9.
✓ jQuery 1.7+
jQuery ajaxStop 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
ajaxStopUniversal
Bottom line: Safe in any jQuery project using $.ajax(), $.get(), $.post(), or .load(). Prefer .on('ajaxStop') over deprecated .ajaxStop().
Wrap Up
Conclusion
The jQuery ajaxStop event is the global “last request finished” hook — it runs once when the final qualifying Ajax call completes and no others are active. Bind handlers on document with .on("ajaxStop", fn), pair with ajaxStart for loading UI, and remember the handler receives no jqXHR or settings.
Use ajaxComplete when you need per-request details after each call finishes. Use global: false to opt out. Continue with the .ajaxStop() method tutorial for the deprecated shorthand API you will see in legacy code.
Pair with ajaxStart to show loading UI when activity begins
Use for page-wide spinners — not per-request logging
Use global: false for silent background or third-party requests
Remove handlers with $(document).off("ajaxStop") on SPA teardown
❌ Don’t
Attach global handlers to window — use document since jQuery 1.9
Use deprecated .ajaxStop(handler) in new code
Expect jqXHR or settings in the handler — use ajaxComplete instead
Hide loading UI on ajaxComplete during parallel batches — use ajaxStop
Assume ajaxStop fires for every request — it fires once per batch
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about ajaxStop
Last request, global batch, pair ajaxStart.
6
Core concepts
doc01
document
Bind here
Global
1×02
Last only
Per batch
Timing
start03
ajaxStart
Show UI
Pair
done04
ajaxComplete
Per request
Details
off05
global:false
Opt out
Private
.on06
.on()
Not .ajaxStop()
Modern
❓ Frequently Asked Questions
ajaxStop is a global Ajax event (AjaxEvent) that fires when all qualifying jQuery Ajax requests have completed — when no global Ajax requests remain active. Bind handlers with $(document).on('ajaxStop', handler) since version 1.7.
Since jQuery 1.9, all global Ajax event handlers — including ajaxStop — must be bound to document, not window or other elements. Use $(document).on('ajaxStop', fn) and $(document).off('ajaxStop', fn) to remove them.
ajaxComplete fires after every individual qualifying request finishes — success or error — with jqXHR and settings. ajaxStop fires once when the last active global request completes and the active count returns to zero. For three parallel calls: ajaxComplete runs three times; ajaxStop runs once.
No. ajaxStop fires only when no global Ajax requests remain in progress. If you launch three parallel $.ajax() calls, ajaxStop runs once after the last one finishes. Pair it with ajaxStart, which fires once when the first request begins.
When $.ajax() or $.ajaxSetup() sets global: false, that request opts out of all global Ajax events. ajaxStop will not fire for it, and it does not count toward active global requests for ajaxStart/ajaxStop pairing.
The handler is a simple function with no jQuery-specific arguments — function() { ... }. Unlike ajaxComplete or ajaxSend, you do not receive jqXHR or settings. Use ajaxComplete when you need per-request details.
Did you know?
jQuery maintains an internal counter of active global Ajax requests. ajaxStop fires when that counter returns to 0 — after the last qualifying request completes or is cancelled via beforeSend returning false. That is why three parallel $.get() calls produce one spinner hide — not three. The deprecated .ajaxStop(fn) method is equivalent to .on("ajaxStop", fn) on document.