Troubleshooting

Start with BabelShield.diagnose() for a snapshot of your integration status. Most issues can be identified from this output alone.

Run Diagnostics First

Open your browser console and run:

BabelShield.diagnose();

This returns a diagnostic snapshot:

{
  "version": "2.2.0",
  "initialized": true,
  "adapter": {
    "name": "none",
    "confidence": 0,
    "version": null,
    "allDetections": []
  },
  "forms": {
    "total": 3,
    "protected": 2,
    "skipped": [
      "#search-form (data-babel-shield-ignore)"
    ]
  },
  "config": {
    "mode": "direct",
    "failOpen": true,
    "feedbackMode": "inline"
  },
  "environment": {
    "url": "https://example.com/contact",
    "hasJQuery": false,
    "hasCKEditor": false
  }
}

What Each Field Means

Field What to Check
version Library version. Include this in support requests.
initialized Should be true. If false, init failed or hasn't completed.
adapter.name Active framework adapter: drupal, wordpress, or none (vanilla HTML).
adapter.confidence Detection confidence (0-100). Low values suggest false detection.
forms.total Total forms found on the page (protected + skipped).
forms.protected Forms actively being moderated.
forms.skipped Forms excluded and why (listed by selector or reason).
config.mode direct (API calls from browser) or proxy (via backend).
config.failOpen If true, forms submit normally when the API is unavailable.
config.feedbackMode inline, modal, or silent.
environment.hasJQuery Relevant for Drupal/WordPress AJAX form handling.
environment.hasCKEditor If true, CKEditor content is extracted automatically.

Enable Debug Mode

For detailed logging of every request, cache hit, and moderation result:

BabelShield.init({
  apiToken: 'YOUR_API_TOKEN',
  debug: true
});

Or via data attribute:


<script src="https://cdn.babelshield.ai/v1/babel-shield.js"
        data-api-token="YOUR_API_TOKEN"
        data-debug="true"></script>

Debug output appears in the browser console with the [BabelShield] prefix.

Common Issues

Cache Key Generation Errors

Symptom:

Error: Cache key generation failed. Ensure your app is served over HTTPS or use http://localhost for development.

Cause: The Web Crypto API requires a secure context -- HTTPS in production, or http://localhost / http://127.0.0.1 in development. file:// URLs and non-localhost HTTP addresses do not work.

Solutions:

  1. Use http://localhost for local development
  2. Use HTTPS in production (most hosting platforms provide free SSL)
  3. As a last resort, disable caching:
const result = await BabelShield.moderate(content, {
  skipCache: true
});

Rate Limit Errors

Symptom:

RateLimitError: Client rate limit exceeded. Try again in 45s

Cause: Client-side rate limits exceeded -- 60 requests per minute or 1000 requests per hour. These limits reset on page reload.

Solutions:

  1. Batch content -- combine multiple fields into a single moderation request instead of moderating each field separately
  2. Use caching -- repeated calls with identical content use the cache (no API call)
  3. Check before sending:
if (BabelShield.isNearRateLimit()) {
  // Show user a message or queue the request
  return;
}
  1. Monitor usage:
const status = BabelShield.getRateLimitStatus();
console.log('Requests this minute:', status.used.minute);
console.log('Requests this hour:', status.used.hour);

Note: Server-side rate limits are separate and enforced by the API. For retry patterns with exponential backoff, see Error Handling.

CORS Errors

Direct API Mode

Symptom:

Access to fetch at 'https://api.babelshield.ai/...' from origin 'https://yoursite.com' has been blocked by CORS policy

Cause: Your domain is not authorized for the API token you're using.

Solutions:

  1. Check your Babel Shield dashboard -- ensure your domain is added to the token's allowed origins
  2. Verify the apiUrl includes the full path:
// Wrong
apiUrl: 'https://api.babelshield.ai'

// Correct
apiUrl: 'https://api.babelshield.ai/api/v1'

Proxy Mode

Cause: Your backend proxy endpoint needs CORS headers.

Solutions:

Add CORS headers to your proxy endpoint and handle preflight OPTIONS requests. For backend proxy configuration, see the API Reference.

Initialization Errors

"BabelShield is already initialized":

// Check before initializing
if (!BabelShield.isInitialized()) {
  await BabelShield.init({apiToken: 'YOUR_API_TOKEN'});
}

// Or destroy before reinitializing
BabelShield.destroy();
await BabelShield.init({apiToken: 'NEW_TOKEN'});

"API client not initialized":

Wait for init() to complete before calling moderate():

const result = await BabelShield.init({apiToken: 'YOUR_API_TOKEN'});
if (result.success) {
  await BabelShield.moderate(content);
}

"Invalid API token" or "Subscription required":

Verify your API token in the Babel Shield dashboard. Check that your subscription is active and the token hasn't been revoked.

Network and Timeout Errors

Timeout errors: Increase the timeout (maximum 60 seconds):

await BabelShield.init({
  apiToken: 'YOUR_API_TOKEN',
  timeout: 60000
});

The API client automatically retries on timeout, 429, 500, and 503 responses -- up to 2 retries with exponential backoff. Errors with status 400, 401, 403, and 422 are not retried.

Network errors: Check internet connectivity and verify the API is accessible.

Payload Validation Errors

"Payload cannot be null or undefined":

Validate content before calling moderate():

if (content != null && content !== '') {
  await BabelShield.moderate(content);
}

"Payload must be JSON serializable":

The payload contains non-serializable values like circular references or BigInt values. Remove them before sending:

// Remove circular references by round-tripping through JSON
const safePayload = JSON.parse(JSON.stringify(rawPayload));

// Convert BigInt values to strings (JSON cannot serialize BigInt)
safePayload.value = bigIntValue.toString();

"Payload exceeds maximum size":

The payload is larger than 20KB when serialized. Truncate content or moderate in chunks:

const serialized = JSON.stringify(payload);
if (serialized.length > 20 * 1024 && typeof payload.text === 'string') {
  payload.text = payload.text.substring(0, 10000);
}

Forms Not Being Protected

Symptom: Forms submit without moderation, no data-babel-shield-protected attribute added.

Solutions:

  1. Check initialization completed:
BabelShield.on('ready', () => {
  console.log('Form handler should be active');
});

console.log('Initialized:', BabelShield.isInitialized());
console.log('Ready:', BabelShield.isReady());
  1. Check form selector matches:
const forms = document.querySelectorAll('form');
console.log('All forms:', forms.length);

const config = BabelShield.getConfig();
console.log('Forms selector:', config.forms);
console.log('Exclude selector:', config.excludeForms);
  1. Check for ignore attribute -- remove data-babel-shield-ignore from forms that should be protected.

  2. Manually attach a form:

const formHandler = BabelShield.getModule('form-handler');
const form = document.getElementById('my-form');
formHandler.attachForm(form);

Dynamic Forms Not Detected

Symptom: Forms added after page load are not protected.

Babel Shield uses a MutationObserver with a 50ms debounce to detect new forms. If forms are still not detected:

// Force re-scan after major DOM changes
const formHandler = BabelShield.getModule('form-handler');
formHandler.refresh();

// Or manually attach a specific form
const newForm = document.getElementById('dynamic-form');
formHandler.attachForm(newForm);

Field Content Not Being Moderated

Symptom: Specific field content is not included in the moderation payload.

Check field type exclusions. These fields are excluded by default:

  • type="password", type="hidden", type="file" -- not user content
  • type="submit", type="button", type="reset", type="image" -- not content
  • Disabled or readonly fields

Check for ignore attribute:

<!-- This field is excluded -->
<input type="text"
       name="code"
       data-babel-shield-ignore>

Check contenteditable elements. They must have a name or data-name attribute:


<div contenteditable
     data-name="rich-content">...
</div>

Modal Not Closing

Symptom: Modal feedback dialog does not close on button click or Escape key.

Check the browser console for JavaScript errors preventing event handlers from firing. To close the modal manually:

const formHandler = BabelShield.getModule('form-handler');
formHandler.ValidationUI.hideModal();

The modal uses focus trapping -- Tab cycles through elements inside the modal, and Escape should close it.

Custom Colors Not Working

Symptom: Severity colors do not match configuration.

  1. Check color format -- values must be valid CSS colors (hex, named, or RGB):
feedback: {
  colors: {
    low: '#ffc107',
    medium: 'orange',
    high: 'rgb(220, 53, 69)',
    critical: '#721c24'
  }
}
  1. Check CSS overrides -- external CSS might override custom properties:
:root {
    --babel-shield-color-critical: red !important;
}
  1. Update colors at runtime:
const formHandler = BabelShield.getModule('form-handler');
formHandler.ValidationUI.setColors({
  critical: '#ff0000'
});

Accessibility Issues

Symptom: Screen readers do not announce feedback, or keyboard navigation is broken.

Check that these ARIA attributes are present:

  • Inline feedback should have role="status"
  • Modal should have role="dialog" and aria-modal="true"
  • Close button should be focusable
  • Tab should cycle through modal elements (focus trapping)
  • Escape should close the modal

Test with a screen reader (VoiceOver on Mac/iOS, NVDA or JAWS on Windows) to verify announcements.

Content Security Policy (CSP)

If your site uses a Content Security Policy, add the Babel Shield CDN and API domains:

Via meta tag:


<meta http-equiv="Content-Security-Policy"
      content="default-src 'self';
               script-src 'self' https://cdn.babelshield.ai;
               connect-src 'self' https://api.babelshield.ai;
               style-src 'self' 'unsafe-inline';">

Via HTTP header (preferred):

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.babelshield.ai; connect-src 'self' https://api.babelshield.ai;

unsafe-inline for style-src is needed because Babel Shield injects feedback styling. If your CSP blocks inline styles, feedback messages may not display correctly.

Getting Help

If you're still experiencing issues:

  1. Check the browser console for detailed error messages
  2. Enable debug mode for additional logging
  3. Run BabelShield.diagnose() and include the output in your support request
  4. Check API status at status.babelshield.com
  5. Contact support with:
    • Error message and stack trace
    • Browser and version
    • Babel Shield JS version (from diagnose() output)
    • Steps to reproduce the issue

Next Steps