Drupal Installation
Add Babel Shield to Drupal 8, 9, or 10 with automatic AJAX form support, CKEditor integration, and Webform compatibility.
Before You Begin
- A Babel Shield account and API token -- see Getting Started
- Drupal 8.x, 9.x, or 10.x (the adapter also detects Drupal 7, but the Twig template and hook examples below target Drupal 8+)
Installation Methods
Theme Template (Recommended)
Add the script tag before the closing </body> in your theme's html.html.twig template. This is the simplest method
and loads Babel Shield on every page.
Edit themes/YOUR_THEME/templates/html.html.twig:
{# ... existing content ... #}
<script src="https://cdn.babelshield.ai/v1/babel-shield.js"
data-api-token="YOUR_API_TOKEN">
</script>
</body>
</html>
Asset Library
Define Babel Shield as an external library in your theme's asset files. This method integrates with Drupal's asset management, caching, and aggregation.
Add to YOUR_THEME.libraries.yml:
babel-shield:
js:
https://cdn.babelshield.ai/v1/babel-shield.js:
type: external
attributes:
data-api-token: 'YOUR_API_TOKEN'
Attach the library globally in YOUR_THEME.info.yml:
libraries:
- YOUR_THEME/babel-shield
Custom Module
Create a module that attaches the script via hook_page_attachments(). This gives you conditional loading -- skip admin
pages, specific routes, or specific content types.
// babel_shield.module
function babel_shield_page_attachments(array &$attachments) {
// Skip admin pages
if (\Drupal::service('router.admin_context')->isAdminRoute()) {
return;
}
$attachments['#attached']['html_head'][] = [
[
'#type' => 'html_tag',
'#tag' => 'script',
'#attributes' => [
'src' => 'https://cdn.babelshield.ai/v1/babel-shield.js',
'data-api-token' => 'YOUR_API_TOKEN',
],
],
'babel_shield',
];
}
Custom Block Plugin
Create a block plugin that outputs the script tag. Place it in your site's footer region via Block Layout. This method lets non-developers enable or disable Babel Shield through the Block Layout UI.
// modules/custom/babel_shield/src/Plugin/Block/BabelShieldBlock.php
namespace Drupal\babel_shield\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* @Block(
* id = "babel_shield",
* admin_label = @Translation("Babel Shield")
* )
*/
class BabelShieldBlock extends BlockBase {
public function build() {
return [
'#type' => 'html_tag',
'#tag' => 'script',
'#attributes' => [
'src' => 'https://cdn.babelshield.ai/v1/babel-shield.js',
'data-api-token' => 'YOUR_API_TOKEN',
],
];
}
}
Note: The block only loads on pages where its region is rendered. If your theme does not render the footer region on certain pages, Babel Shield will not load there.
Attaching to Specific Webforms
Use hook_webform_submission_form_alter() to attach Babel Shield only to specific Webform submission forms. This is
useful when you want to moderate a contact form but not every form on the site.
// babel_shield.module
use Drupal\Core\Form\FormStateInterface;
function babel_shield_webform_submission_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
// Only attach to the 'contact' webform
if ($form['#webform_id'] === 'contact') {
$form['#attached']['html_head'][] = [
[
'#type' => 'html_tag',
'#tag' => 'script',
'#attributes' => [
'src' => 'https://cdn.babelshield.ai/v1/babel-shield.js',
'data-api-token' => 'YOUR_API_TOKEN',
],
],
'babel_shield',
];
}
}
The adapter auto-detects forms matching .webform-submission-form and handles Webform AJAX submissions via the
webform:submit event.
What Gets Protected Automatically
Once loaded, Babel Shield detects Drupal and protects these form types:
- Webform submissions (
.webform-submission-form) - Contact forms (
contact-message-*) - Comment forms
- Node create/edit forms
- User registration forms
- AJAX-submitted forms (via
Drupal.behaviors) - CKEditor content (both CKEditor 4 and CKEditor 5)
What Gets Excluded Automatically
The adapter excludes forms that should not be moderated:
- Admin forms (
/admin/*) - Developer tools (
/devel/*) - Login forms (
.user-login-form) - Password reset forms (
.user-pass) - Search forms (
.search-form,.search-block-form) - Views exposed filters (
.views-exposed-form) - System configuration forms
Admin exclusion uses both URL path detection and form action URL checking for defense in depth.
AJAX Form Support
Babel Shield registers as Drupal.behaviors.babelShield to handle AJAX forms automatically. When Drupal rebuilds part
of the page via AJAX, the behavior re-attaches to new form elements.
For AJAX form submissions, Babel Shield intercepts the jQuery ajaxSend event, moderates the content, and re-triggers
approved submissions transparently via Drupal.ajax.
Note: In Drupal 10, jQuery is an optional library. If jQuery is not loaded on a page, AJAX interception falls back to standard submit event handling. Forms still work -- only the AJAX-specific interception path changes.
CKEditor Integration
CKEditor 4 (Drupal 8 and 9)
Content is extracted automatically from window.CKEDITOR.instances. No configuration needed -- the adapter iterates all
active editor instances and includes their content in the moderation payload.
CKEditor 5 (Drupal 10)
Content is extracted from Drupal.CKEditor5Instances, a Map keyed by element ID. The adapter reads the editor data
from each instance.
CKEditor 5 is the default editor in Drupal 10. The adapter handles both editor versions simultaneously, which is useful during a Drupal 9 to 10 migration when both editors may be present on the same site.
Version-Specific Notes
| Feature | Drupal 8 | Drupal 9 | Drupal 10 |
|---|---|---|---|
| Installation methods | All methods work | All methods work | All methods work |
| CKEditor | CKEditor 4 (core) | CKEditor 4 (deprecated in 9.3+) | CKEditor 5 (core) |
| jQuery | Always loaded | Always loaded | Optional -- may not be on every page |
| AJAX detection | Full (drupalSettings.ajax + jQuery) |
Full | Partial if jQuery absent |
Drupal.behaviors |
Full support | Full support | Full support |
Platform-Specific Troubleshooting
Forms Not Detected
Run BabelShield.diagnose() in the browser console. Check that adapter.name is drupal and adapter.confidence is
greater than 0.
If adapter.name is none, verify that Drupal's window.Drupal global is present on the page. The script must load
after the Drupal JavaScript framework initializes.
AJAX Forms Not Protected
Check the browser console for Drupal.behaviors.babelShield registration. If not present, the script may have loaded
before Drupal.behaviors was available.
On Drupal 10, verify jQuery is loaded on the page by checking window.jQuery in the console. Without jQuery, AJAX form
interception uses the standard submit event fallback.
CKEditor Content Not Extracted
- CKEditor 4: Check
window.CKEDITOR.instancesin the console. Each editor instance should appear as a property. - CKEditor 5: Check
Drupal.CKEditor5Instancesin the console. It should be aMapcontaining your editor instances. - Ensure the editor is fully initialized before form submission.
For API-level errors (rate limits, CORS, authentication), see Troubleshooting.
Next Steps
- Drupal Configuration -- Data attributes, PHP form alter exclusions, and Webform-specific settings
- Troubleshooting -- API errors, CORS, rate limits, and diagnostics