智能客服系统在实际运营中有个很现实的问题:用户发起会话后中途离开,客服端却一直显示对方在线,客服干等着回复,系统资源也被白白占用。浏览器提供的 Idle Detection API 恰好能解决这个问题,它可以告知页面当前用户是否处于空闲状态,比如锁屏、切走或长时间无操作。本文就以 jQuery 为基础,封装一套可直接落地的用户活跃度监测模块,让客服系统能够自动感知用户离开与回归。

Idle Detection API 的核心机制与权限流程
Idle Detection API 是 Chrome 系浏览器推出的实验性接口,核心入口是 IdleDetector 对象。它的工作原理并不复杂:浏览器持续监听用户的输入行为(鼠标移动、键盘敲击、触摸等)以及屏幕状态,当这些信号在指定时间内没有变化,且屏幕未锁定时,就判定用户处于空闲状态。开发者可以通过 start() 方法传入阈值,比如用户 60 秒无操作即判定为 idle。
出于隐私考虑,这个 API 不是随便就能调用的,它有严格的权限链路。首先页面必须是安全上下文(HTTPS 或 localhost),其次需要用户主动触发权限申请,最后还可以通过 Permissions-Policy 控制哪些 iframe 有权使用。整个流程可以概括为:检测浏览器支持、请求权限、启动监听、监听状态变化事件。下面是一个最小可运行的原生示例:
// 原生 Idle Detection 基本用法
async function initIdleDetection() {
// 判断浏览器是否支持
if (!('IdleDetector' in window)) {
console.warn('当前浏览器不支持 Idle Detection API');
return;
}
// 申请权限,必须由用户手势触发
const permissionState = await IdleDetector.requestPermission();
if (permissionState !== 'granted') {
console.warn('用户拒绝了空闲检测权限');
return;
}
const detector = new IdleDetector();
detector.addEventListener('change', () => {
console.log('用户状态:', detector.userState); // active 或 idle
console.log('屏幕状态:', detector.screenState); // locked 或 unlocked
});
await detector.start({
threshold: 60000 // 60秒无操作判定为空闲
});
}
这里有两个容易踩坑的点需要强调。第一,requestPermission() 必须在用户手势事件(如点击、按键)的调用栈中执行,否则会直接抛出异常,这一点和通知、定位等 API 的要求一致。第二,threshold 有最小值限制,浏览器通常不允许设置小于一分钟的阈值,即使你传了更小的数字,实际生效的也可能是一分钟,做业务设计时要按这个下限来规划交互节奏。
基于 jQuery 的通用封装设计
直接使用原生 API 会有几个不便:权限处理逻辑散落在各处、缺少降级方案、事件回调与业务耦合过紧。用 jQuery 封装一层,可以把这些复杂度收拢到一个独立模块里,对外只暴露简洁的事件订阅接口。封装的核心思路是:内部维护一个 IdleDetector 实例,对外通过 jQuery 自定义事件机制广播状态变化,这样客服模块、埋点模块、会话模块都可以独立订阅,互不干扰。
同时必须考虑兼容性。目前 Idle Detection API 只有 Chromium 内核浏览器支持,Firefox 和 Safari 完全不支持。所以封装里要内置一个降级策略:当原生 API 不可用时,改用传统的鼠标、键盘、滚动事件加定时器的方案模拟空闲检测。降级方案虽然检测不到锁屏状态,但覆盖了绝大多数真实场景,保底能力足够。
(function ($) {
'use strict';
var IdleWatcher = {
detector: null,
timer: null,
idle: false,
options: {
threshold: 60000, // 空闲判定阈值
fallbackEvents: 'mousemove keydown scroll touchstart click'
},
init: function (opts) {
this.options = $.extend({}, this.options, opts);
if ('IdleDetector' in window) {
this._initNative();
} else {
this._initFallback();
}
return this;
},
// 原生 API 方案
_initNative: function () {
var self = this;
$(document).one('click.idleWatcher', async function () {
try {
if (await IdleDetector.requestPermission() === 'granted') {
self.detector = new IdleDetector();
self.detector.addEventListener('change', function () {
self._notify(
self.detector.userState === 'idle' ? 'idle' : 'active'
);
});
await self.detector.start({ threshold: self.options.threshold });
}
} catch (e) {
self._initFallback();
}
});
},
// 降级方案:事件 + 定时器
_initFallback: function () {
var self = this;
var reset = function () {
if (self.idle) {
self.idle = false;
self._notify('active');
}
clearTimeout(self.timer);
self.timer = setTimeout(function () {
self.idle = true;
self._notify('idle');
}, self.options.threshold);
};
$(document).on(this.options.fallbackEvents, $.throttle
? $.proxy(reset, this)
: reset);
reset();
},
// 通过 jQuery 自定义事件广播状态
_notify: function (state) {
$(document).trigger('idleStateChange', [state]);
},
destroy: function () {
$(document).off('.idleWatcher');
clearTimeout(this.timer);
}
};
window.IdleWatcher = IdleWatcher;
})(jQuery);
这段封装的设计要点有几个值得说明。init 方法作为统一入口,内部自动判断走原生还是降级路径,调用方完全不感知差异。状态变化统一通过 idleStateChange 自定义事件广播,配合参数传递状态值,业务侧用一行 $(document).on('idleStateChange', handler) 就能接入。降级方案里通过一个布尔标记 idle 做去重,避免定时器和事件重置之间产生重复通知。
在智能客服系统中的落地实践
封装完成后,接入客服系统就非常直接了。典型场景是这样:用户在客服窗口发起咨询后,如果 60 秒没有任何操作,前端自动向客服端推送一条离开状态,客服看到后就知道不必干等;同时前端会暂停消息轮询频率,把每两秒一次的请求降为每三十秒一次,节省服务端资源。当用户重新活动时,状态切回 active,轮询立即恢复高频模式,并补拉离开期间错过的消息。
// 客服模块接入示例
IdleWatcher.init({ threshold: 60000 });
$(document).on('idleStateChange', function (e, state) {
if (state === 'idle') {
// 通知客服端用户已离开,并降低轮询频率
CustomerService.pushUserStatus('away');
CustomerService.setPollingInterval(30000);
$('#chat-panel').addClass('user-away');
} else {
// 用户回归,恢复轮询并补拉离线消息
CustomerService.pushUserStatus('online');
CustomerService.setPollingInterval(2000);
CustomerService.fetchMissedMessages();
$('#chat-panel').removeClass('user-away');
}
});
除了会话管理,活跃度数据本身也是宝贵的运营素材。可以在每次状态切换时记录时间戳,会话结束后把空闲时段汇总上报,运营侧就能统计出真实的有效会话时长、平均响应窗口等指标,用于优化客服排班和机器人接管策略。比如发现大量会话在提问后 30 秒内用户就离开,说明话术或引导页可能有问题,这是传统埋点很难捕捉到的信号。
最后补充几个工程化建议。一是权限申请的时机要放在用户明确交互的场景里,比如点击开始会话按钮时,不要页面一加载就弹权限,体验很差且容易被拒绝。二是降级方案的监听事件记得做节流处理,mousemove 触发频率极高,不节流会带来明显的性能开销。三是对于长时间空闲的用户,除了标记状态,最好配合自动结束会话的兜底逻辑,比如空闲超过 30 分钟自动关闭会话并保存聊天记录,避免僵尸会话无限累积。把这几个环节做扎实,整个活跃度监测体系才算真正闭环。
Idle Detection APIjQuery封装用户活跃度监测修改时间:2026-09-11 14:05:55