diff --git a/docs/how_tos/embedding-custom-scripts.rst b/docs/how_tos/embedding-custom-scripts.rst
new file mode 100644
index 000000000..26ad26886
--- /dev/null
+++ b/docs/how_tos/embedding-custom-scripts.rst
@@ -0,0 +1,66 @@
+##########################
+Embedding Custom Scripts
+##########################
+
+.. contents:: Table of Contents
+
+Introduction
+************
+
+In modern web applications, there is a need to embed external scripts to expand the functionality of the application or integrate third-party services (analytics tools, widgets, etc.).
+This tutorial explains how to add custom scripts through Django site configurations.
+
+Configuration Overview
+=======================
+
+Configuration for embedding custom scripts can be done through the global `MFE_CONFIG` and the `MFE_CONFIG_OVERRIDES`. These configurations allow specifying scripts to be inserted into different parts of the HTML document, such as the `
` section or various positions within the ``.
+
+Configuring External Scripts
+=============================
+
+External scripts can be specified in the `MFE_CONFIG` or `MFE_CONFIG_OVERRIDES` JSON objects. Each script can be inserted into one of the following locations:
+- `head`: Inserts the script into the `` section.
+- `body.top`: Inserts the script at the beginning of the `` section.
+- `body.bottom`: Inserts the script at the end of the `` section.
+
+Scripts can be provided either as a URL (`src`) or as inline script content.
+
+Example Configuration
+=====================
+
+Example 1: Using `MFE_CONFIG_OVERRIDES`
+---------------------------------------
+
+```json
+{
+ "MFE_CONFIG_OVERRIDES": {
+ "": {
+ "EXTERNAL_SCRIPTS": [
+ {
+ "head": "",
+ "body": {
+ "top": "",
+ "bottom": ""
+ }
+ }
+ ]
+ }
+ }
+}
+
+Example 1: Using `MFE_CONFIG`
+---------------------------------------
+```json
+{
+ "MFE_CONFIG": {
+ "EXTERNAL_SCRIPTS": [
+ {
+ "head": "",
+ "body": {
+ "top": "",
+ "bottom": ""
+ }
+ }
+ ]
+ }
+}
diff --git a/docs/template/edx/publish.js b/docs/template/edx/publish.js
index 4c390f56c..1444de9d5 100644
--- a/docs/template/edx/publish.js
+++ b/docs/template/edx/publish.js
@@ -653,7 +653,7 @@ exports.publish = (memberData, opts, tutorials) => {
const myNamespaces = members.namespaces.filter(obj => obj.longname === longname);
const trimModuleName = (moduleName) => {
- if (moduleName.includes('module:')) {
+ if (moduleName?.includes('module:')) {
return moduleName.split(':')[1];
}
return moduleName;
diff --git a/src/initialize.js b/src/initialize.js
index 2c7223595..438836585 100644
--- a/src/initialize.js
+++ b/src/initialize.js
@@ -68,7 +68,7 @@ import {
import {
configure as configureAnalytics, SegmentAnalyticsService, identifyAnonymousUser, identifyAuthenticatedUser,
} from './analytics';
-import { GoogleAnalyticsLoader } from './scripts';
+import { GoogleAnalyticsLoader, ScriptInserter } from './scripts';
import {
getAuthenticatedHttpClient,
configure as configureAuth,
@@ -290,7 +290,7 @@ export async function initialize({
analyticsService = SegmentAnalyticsService,
authService = AxiosJwtAuthService,
authMiddleware = [],
- externalScripts = [GoogleAnalyticsLoader],
+ externalScripts = [GoogleAnalyticsLoader, ScriptInserter],
requireAuthenticatedUser: requireUser = false,
hydrateAuthenticatedUser: hydrateUser = false,
messages,
diff --git a/src/scripts/ScriptInserter.js b/src/scripts/ScriptInserter.js
new file mode 100644
index 000000000..6c340842d
--- /dev/null
+++ b/src/scripts/ScriptInserter.js
@@ -0,0 +1,97 @@
+/**
+ * Class representing a Script Inserter.
+ */
+class ScriptInserter {
+ /**
+ * Create a Script Inserter.
+ * @param {Array