diff --git a/djblets/extensions/extension.py b/djblets/extensions/extension.py
index 20ea0724505ea67313aa1f316250125a21c6ed95..eea2eb80def01246f1792cce6758635d6255ec3b 100644
--- a/djblets/extensions/extension.py
+++ b/djblets/extensions/extension.py
@@ -41,6 +41,44 @@ if not hasattr(settings, "EXTENSIONS_STATIC_ROOT"):
         "settings.EXTENSIONS_STATIC_ROOT must be defined")
 
 
+class JSExtension(object):
+    """Base class for a JavaScript extension.
+
+    This can be subclassed to provide the information needed to initialize
+    a JavaScript extension.
+
+    The JSExtension subclass is expected to define a :py:attr:`model_class`
+    attribute naming its JavaScript counterpart. This would be the variable
+    name for the (uninitialized) model for the extension, defined in a
+    JavaScript bundle.
+
+    It may also define :py:attr:`apply_to`, which is a list of URL names that
+    the extension will be initialized on. If not provided, the extension will
+    be initialized on all pages.
+
+    To provide additional data to the model instance, the JSExtension subclass
+    can implement :py:meth:`get_model_data` and return a dictionary of data
+    to pass.
+    """
+    model_class = None
+    apply_to = None
+
+    def __init__(self, extension):
+        self.extension = extension
+
+    def applies_to(self, url_name):
+        """Returns whether this extension applies to the given URL name."""
+        return self.apply_to is None or url_name in self.apply_to
+
+    def get_model_data(self):
+        """Returns model data for the Extension model instance in JavaScript.
+
+        Subclasses can override this to return custom data to pass to
+        the extension.
+        """
+        return {}
+
+
 class Extension(object):
     """Base class for an extension.
 
@@ -111,13 +149,16 @@ class Extension(object):
     JavaScript extensions
     ---------------------
 
-    An Extension subclass can define a :py:attr:`js_model_class` attribute
-    naming its JavaScript counterpart. This would be the variable name for the
-    (uninitialized) model for the extension, usually defined in the "default"
-    JavaScript bundle.
+    An Extension subclass can define one or more JavaScript extension classes,
+    which may apply across all pages or only a subset of them.
+
+    Each is defined as a :py:class:`JSExtension` subclass, and listed in
+    Extension's :py:attr:`js_extensions` list. See the documentation on
+    JSExtension for more information.
 
     Any page using the ``init_js_extensions`` template tag will automatically
-    initialize these JavaScript extensions, passing the server-stored settings.
+    initialize any JavaScript extensions appropriate for that page, passing the
+    server-stored settings.
 
 
     Middleware
@@ -154,7 +195,7 @@ class Extension(object):
     css_bundles = {}
     js_bundles = {}
 
-    js_model_class = None
+    js_extensions = []
 
     def __init__(self, extension_manager):
         self.extension_manager = extension_manager
@@ -227,14 +268,6 @@ class Extension(object):
         """Returns the ID for a CSS or JavaScript bundle."""
         return '%s-%s' % (self.id, name)
 
-    def get_js_model_data(self):
-        """Returns model data for the Extension instance in JavaScript.
-
-        Subclasses can override this to return custom data to pass to
-        the extension.
-        """
-        return {}
-
 
 @python_2_unicode_compatible
 class ExtensionInfo(object):
diff --git a/djblets/extensions/templates/extensions/init_js_extensions.html b/djblets/extensions/templates/extensions/init_js_extensions.html
index a567a50250b94e84291da487d9dbedf4e2558d38..ca6509e1fb79662d205efddd71f58910e51dfa14 100644
--- a/djblets/extensions/templates/extensions/init_js_extensions.html
+++ b/djblets/extensions/templates/extensions/init_js_extensions.html
@@ -1,15 +1,16 @@
 {% load djblets_js %}
 
-{% if extensions %}
+{% if js_extensions %}
 <script>
-{%  for extension in extensions %}
-    new {{extension.js_model_class}}({
-{%   for key, value in extension.get_js_model_data.items %}
+{%  for js_extension in js_extensions %}
+    new {{js_extension.model_class}}({
+{%   for key, value in js_extension.get_model_data.items %}
         {{key|json_dumps}}: {{value|json_dumps}},
 {%   endfor %}
-        id: '{{extension.id}}',
-        name: {{extension.info.name|json_dumps}},
-        settings: {{extension.settings|json_dumps}}
+        id: '{{js_extension.extension.id}}',
+        name: '{{js_extension.extension.info.name|escapejs}}',
+        urlName: '{{url_name}}',
+        settings: {{js_extension.extension.settings|json_dumps}}
     });
 {%  endfor %}
 </script>
diff --git a/djblets/extensions/templatetags/djblets_extensions.py b/djblets/extensions/templatetags/djblets_extensions.py
index 911947d6d7e4e46007e18f9b5279811f6ac4abaa..8eaab45d1e4d5e4692b073b9dc3c98e7a82663c4 100644
--- a/djblets/extensions/templatetags/djblets_extensions.py
+++ b/djblets/extensions/templatetags/djblets_extensions.py
@@ -128,14 +128,22 @@ def init_js_extensions(context, extension_manager_key):
     Each extension's required JavaScript files will be loaded in the page,
     and their JavaScript-side Extension subclasses will be instantiated.
     """
+    url_name = context['request'].resolver_match.url_name
+
     for manager in get_extension_managers():
         if manager.key == extension_manager_key:
+            js_extensions = []
+
+            for extension in manager.get_enabled_extensions():
+                for js_extension_cls in extension.js_extensions:
+                    js_extension = js_extension_cls(extension)
+
+                    if js_extension.applies_to(url_name):
+                        js_extensions.append(js_extension)
+
             return {
-                'extensions': [
-                    extension
-                    for extension in manager.get_enabled_extensions()
-                    if extension.js_model_class
-                ],
+                'url_name': url_name,
+                'js_extensions': js_extensions,
             }
 
     return {}
