Ajax Listener module in the Tealeaf Web SDK
The Ajax Listener module captures XMLHttpRequest (XHR) and Fetch API network traffic in user sessions, allowing you to view API calls in Tealeaf replay.
Key features:
- Logs XHR and Fetch requests/responses
- Filters for selective logging
- Privacy controls via blocklists
- Cooperative chaining with other monitoring tools
- PerformanceObserver fallback for compatibility
Browser compatibility
- Supported: Modern browsers with native XHR and Fetch APIs
- Not recommended: Polyfilled implementations
Installation
Option 1: Inline installation
- Copy the module code ajaxListener.min.js into your Web SDK JavaScript file.
- Place the code after the SDK core and before the configuration/initialization section.
File structure:
- Pako (gzip encoder)
- SDK Core (library without optional modules or config section)
- Ajax Listener
- Configuration
- Initialization (command to initialize the SDK and apply its configuration)
Option 2: CDN loading
<script src="https://cdn.goacoustic.com/connect/latest/acoconnect.min.js"></script>
<script>
(function () {
function configureSDK() {
const config = window.TLT.getDefaultConfig();
config.core.modules.ajaxListener.enabled = true;
config.modules.ajaxListener = {
cooperativeChaining: true,
filters: [{
log: {
requestHeaders: true,
responseData: true
}
}]
};
return config;
}
TLT.initLibAdv({
appKey: "APP_KEY",
postUrl: "COLLECTOR_URL",
newConfig: configureSDK(),
addAjaxListener: true
});
}());
</script>
Configuration
Core settings
Enable/disable capture
ajaxListener: {
xhrEnabled: true, // Enable XHR monitoring (default: true)
fetchEnabled: true, // Enable Fetch monitoring (default: true)
cooperativeChaining: false // Work with other tools (default: false)
}
URL blocking
Block specific URLs from being logged:
urlBlocklist: [
{ regex: "analytics\\.com", flags: "i" },
{ regex: "tracking" }
]
Field privacy
Mask sensitive fields in request/response data:
fieldBlocklist: [
"password",
"ssn",
{ regex: ".*token.*", flags: "i" }
]
Response Filtering
blockNonJSONResponse: false // Block non-JSON responses from logging
Filtering rules
Basic filter structure
filters: [{
url: { regex: "/api/", flags: "i" },
method: { regex: "POST", flags: "i" },
status: { regex: "200" },
log: {
requestHeaders: true,
requestData: true,
responseHeaders: true,
responseData: true
}
}]
Tip
When specifying multiple filters, place more restrictive rules before generic ones. The module uses the first matching filter.
Common patterns
Log all request headers:
{
log: { requestHeaders: true }
}
Log GET response data only:
{
method: { regex: "GET", flags: "i" },
log: { responseData: true }
}
Log errors (4xx status):
{
status: { regex: "^4\\d\\d$" },
log: {
requestHeaders: true,
requestData: true
}
}
Log specific endpoint:
{
url: { regex: "\\/api\\/getAccountDetails" },
log: {
requestHeaders: true,
requestData: true,
responseHeaders: true,
responseData: true
}
}
Log with query parameter:
{
url: { regex: "debug=on(&|$)" },
log: {
requestHeaders: true,
requestData: true,
responseHeaders: true,
responseData: true
}
}
Data logged by default
Every XHR/Fetch call logs these fields automatically:
requestURL- Request URL host and pathmethod- HTTP method (GET, POST, etc.)status- HTTP response status codestatusText- HTTP response status textasync- Boolean for async requestajaxResponseTime- Milliseconds from send to completelocationHref- Document location when request sent
Advanced features
Version 1.4.0+ features
Cooperative chaining
Allows Ajax Listener to work alongside other monitoring tools without conflicts.
ajaxListener: {
cooperativeChaining: true,
monitorHookHealth: true,
hookHealthCheckInterval: 5000, // Check every 5 seconds
debugLog: true
}
How it works:
- Detects if another tool wrapped XHR/Fetch
- Preserves and chains with existing wrappers
- Monitors hook health at runtime
- Auto-enables fallback if hooks fail
PerformanceObserver Fallback
Non-invasive monitoring when hooks fail or conflicts occur.
ajaxListener: {
preferPerformanceObserver: true, // Use as primary method
enablePerformanceObserverFallback: true // Use as backup
}
Limitations:
- Cannot capture request/response headers
- Cannot capture request/response body
- Limited method detection
- Status code may not be available in all browsers
Debug Logging
Enable diagnostic messages for troubleshooting:
debugLog: true // Shows hook chaining, fallback info, errors
URL Filtering (v1.4.0+)
Filters now match full absolute URLs including protocol, host, and path.
Examples:
// Match specific domain
{ regex: "https://api\\.example\\.com/" }
// Match any domain with /api/ path
{ regex: "/api/" }
// Match localhost on any port
{ regex: "http://localhost:\\d+/" }
// Match specific protocol
{ regex: "^https://" }
Benefits:
- More precise filtering by domain
- Distinguish between same-path different-domain requests
- Support for cross-domain API monitoring
- Better control over external APIs
Troubleshooting
Issue: AJAX calls not logging
Symptoms: AJAX calls not appearing in logs
Solutions:
- Enable debug logging:
debugLog: true
- Check if native APIs are wrapped:
console.log(window.XMLHttpRequest.toString())
console.log(window.fetch.toString())
// Should contain "[native code]"
- Try enabling fallback:
enablePerformanceObserverFallback: true
- Use PerformanceObserver as primary:
preferPerformanceObserver: true
Issue: conflicts with other tools
Symptoms: Other monitoring tools stop working
Solutions:
- Ensure Ajax Listener loads early in page lifecycle.
- Check if other tools support cooperative chaining.
- Enable cooperative chaining:
cooperativeChaining: true
- Consider using PerformanceObserver mode:
preferPerformanceObserver: true
Issue: Missing headers/body data
Symptoms: Missing request/response data in logs
Possible causes:
- PerformanceObserver mode active (check logs)
- Hooks were overwritten (check console warnings)
- Log configuration incomplete:
log: {
requestHeaders: true,
requestData: true,
responseHeaders: true,
responseData: true
}
Issue: limited data in logs
Check:
- Is PerformanceObserver mode active?
- Were hooks overwritten?
- Is the
logconfiguration complete?
Example output
Logged XHR data
{
"type": 5,
"offset": 9182,
"customEvent": {
"name": "ajaxListener",
"data": {
"requestURL": "www.acoustic.com/api/getAccountDetails",
"method": "GET",
"status": 200,
"statusText": "OK",
"async": true,
"ajaxResponseTime": 285,
"locationHref": "https://www.acoustic.com/support/login",
"requestHeaders": {
"X-Requested-With": "XMLHttpRequest",
"X-CustomerId": "D295024"
},
"responseHeaders": {
"date": "Thu, 22 Feb 2020 01:38:07 GMT",
"content-type": "application/json"
},
"response": {
"accountDetails": {
"id": "D295024",
"memberSince": "15 July 2012"
}
}
}
}
}
Ajax Listener Version History
v1.4.0 (current)
New features:
- ✨ Filter URL matching uses full absolute URLs (protocol + host + path)
- ✨ ES6/ES2015 compatibility (removed ES2020 features)
- ✨ Cooperative chaining pattern for XHR and Fetch
- ✨ PerformanceObserver fallback mechanism
- ✨ Runtime hook health monitoring
- ✨ Query string capture in
queryParamsobject - ✨ Domain inclusion in URL filters
Improvements:
- 🔧 Better compatibility with other monitoring tools
- 🔧 Better cross-domain API monitoring support
- 🔧 Debug logging configuration option
Bug fixes:
- 🐛 Handle empty responses gracefully
- 🐛 Handle URL objects in fetch calls (CA-102138)
Migration notes:
- URL Filters: Pathname-only patterns (e.g.,
/api/) still work but now match against full URLs - cooperativeChaining: Default is
false(strict behavior). Set totrueto enable - ES6 Requirement: Ensure target browsers support ES6/ES2015
v1.3.4 (previous)
- Basic XHR and Fetch interception
- Simple safety checks
- Native code detection
Best practices
✅ DO
- Start with default settings and adjust as needed
- Enable
debugLogduring development for diagnostics - Use selective filters - don't log everything
- Configure
fieldBlocklistfor sensitive data (passwords, tokens, SSN) - Test thoroughly before production deployment
- Monitor hook health - keep default monitoring enabled
- Consider PerformanceObserver for production - non-invasive and reliable
- Always test your application and validate captured data before deploying to production.
❌ DON'T
- Don't log everything - be selective to reduce data volume
- Don't ignore privacy - always configure field blocklists
- Don't use with polyfills - not recommended
- Don't forget to test - validate captured data before production
Configuration examples
Example 1: standard configuration (recommended)
{
"ajaxListener": {
"xhrEnabled": true,
"fetchEnabled": true,
"cooperativeChaining": true,
"monitorHookHealth": true,
"debugLog": true,
"filters": [{
"url": { "regex": "/api/" },
"log": {
"requestHeaders": true,
"requestData": true,
"responseHeaders": true,
"responseData": true
}
}]
}
}
Example 2: high compatibility mode
{
"ajaxListener": {
"preferPerformanceObserver": true,
"debugLog": true,
"filters": [{
"url": { "regex": ".*" },
"log": {
"responseData": true
}
}]
}
}
Example 3: domain-specific filtering
{
"ajaxListener": {
"filters": [
{
"url": {
"regex": "^https://api\\.example\\.com/",
"flags": "i"
},
"log": {
"requestData": true,
"responseData": true
}
},
{
"url": {
"regex": "^https://internal\\.company\\.com/api/"
},
"log": {
"requestHeaders": true,
"requestData": true,
"responseHeaders": true,
"responseData": true
}
}
]
}
}
Example 4: error monitoring
{
"ajaxListener": {
"filters": [{
"status": { "regex": "[45]\\d\\d" },
"log": {
"requestHeaders": true,
"requestData": false,
"responseHeaders": true,
"responseData": true
}
}]
}
}
Additional resources
Updated 21 days ago
