Skip to main content
MediaWiki exposes a global mw object that provides APIs for interacting with the wiki from JavaScript. All extension JavaScript runs in ResourceLoader modules and has access to mw without any imports. This page covers the core mw.* APIs and common patterns for writing MediaWiki JavaScript.

The mw global object

The mw global is defined in mediawiki.base and bootstrapped by the startup module. It is available on all pages once mediawiki.base has loaded (which happens automatically before user scripts run). The mw.Map class backs both mw.config and mw.messages:
// mw.Map — collection of values by string keys
// Get one key:
var siteName = mw.config.get( 'wgSiteName' );

// Get multiple keys at once:
var conf = mw.config.get( [ 'wgServerName', 'wgUserName', 'wgPageName' ] );
console.log( conf.wgServerName ); // "example.org"

// Check whether a key exists:
if ( mw.config.exists( 'wgRelevantPageName' ) ) { /* ... */ }

// Check multiple keys (AND condition):
if ( mw.config.exists( [ 'wgFoo', 'wgBar' ] ) ) { /* ... */ }

mw.config: accessing wiki configuration

mw.config is a mw.Map pre-populated with configuration values from the server. Common keys:
KeyTypeDescription
wgPageNamestringCurrent page name (with underscores), e.g. "Main_Page"
wgTitlestringDisplay title of the current page
wgNamespaceNumbernumberNamespace ID of the current page
wgArticleIdnumberPage ID (0 for non-existent pages)
wgUserNamestring|nullLogged-in username, or null for anonymous users
wgUserGroupsstring[]User groups the current user belongs to
wgContentLanguagestringWiki content language code
wgUserLanguagestringUser interface language code
wgSiteNamestringWiki site name
wgVersionstringMediaWiki version string
wgActionstringCurrent action: "view", "edit", "history", etc.
wgIsArticlebooleanWhether the current page is a content page
wgIsProbablyEditablebooleanWhether the current user can edit the page
wgRevisionIdnumberRevision ID being viewed
wgFormattedNamespacesobjectMap of namespace IDs to localized names
// Check if the user is logged in
if ( mw.config.get( 'wgUserName' ) !== null ) {
    console.log( 'Logged in as', mw.config.get( 'wgUserName' ) );
}

// Get the current page's namespace
var ns = mw.config.get( 'wgNamespaceNumber' );
if ( ns === 0 ) {
    // Main namespace
}

mw.loader: loading modules on demand

mw.loader manages the module registry and state machine. It initiates network requests for loading modules, resolves dependencies, and executes source code.
// Load a module and run code after it's ready
mw.loader.using( 'mediawiki.api' ).then( function () {
    var api = new mw.Api();
    // ...
} );

// Load multiple modules
mw.loader.using( [ 'mediawiki.api', 'mediawiki.notification' ] ).then( function () {
    var api = new mw.Api();
    mw.notification.notify( 'Modules loaded!' );
} );

// Fire-and-forget loading
mw.loader.load( 'ext.myExtension.heavyFeature' );

// Check the state of a module
console.log( mw.loader.getState( 'mediawiki.api' ) );
// Returns: 'registered', 'loading', 'loaded', 'executing', 'ready', 'error', or 'missing'
If your module is already declared in extension.json with the correct dependencies, you normally do not need to call mw.loader.using() yourself — ResourceLoader ensures dependencies are loaded before your module executes.

mw.Api: making Action API calls

mw.Api is a client for the MediaWiki Action API. It handles CSRF tokens, error handling, and request formatting.
// Create an API instance
var api = new mw.Api();

// GET request
api.get( {
    action: 'query',
    meta: 'userinfo'
} ).then( function ( data ) {
    console.log( data.query.userinfo );
} );

// Since MW 1.25, multi-value parameters accept arrays:
api.get( {
    action: 'query',
    meta: [ 'userinfo', 'siteinfo' ]  // same as 'userinfo|siteinfo'
} ).then( function ( data ) {
    console.log( data );
} );
The API defaults are set from the source:
const defaultOptions = {
    parameters: {
        action: 'query',
        format: 'json'
    },
    ajax: {
        url: mw.util.wikiScript( 'api' ),
        timeout: 30 * 1000,  // 30 seconds
        dataType: 'json'
    }
};

Editing pages

mw.Api includes helper methods for common operations. From mediawiki.api/edit.js:
var api = new mw.Api();

// Create a new page
api.create(
    'Sandbox',
    { summary: 'Creating a test page' },
    'Hello, world!'
).then( function () {
    console.log( 'Page created' );
} );

// Edit an existing page
api.edit( 'Sandbox', function ( revision ) {
    return {
        text: revision.content + '\n\nAppended text.',
        summary: 'Appending text'
    };
} ).then( function () {
    console.log( 'Page saved' );
} );

// Get a CSRF edit token explicitly
api.getEditToken().then( function ( token ) {
    return api.postWithEditToken( {
        action: 'edit',
        title: 'Sandbox',
        text: 'New content',
        summary: 'Replacing content'
    } );
} );

REST API

For the REST API use mw.Rest:
var rest = new mw.Rest();
rest.get( '/v1/page/Main_Page' ).then( function ( data ) {
    console.log( data.source );
} );

mw.hook: the JavaScript hook system

mw.hook provides a publish/subscribe event system. Hooks let different parts of the codebase communicate without direct coupling.
// Listen for a hook
mw.hook( 'wikipage.content' ).add( function ( $content ) {
    // Called when new page content is added to the DOM
    // $content is a jQuery object containing the new content
    $content.find( '.my-extension-widget' ).each( function () {
        // Initialize widgets
    } );
} );

// Fire a hook with data
mw.hook( 'ext.myExtension.saved' ).fire( { pageId: 42, title: 'Example' } );

// Listen only once
mw.hook( 'ext.myExtension.ready' ).add( function handler() {
    mw.hook( 'ext.myExtension.ready' ).remove( handler );
    // ... do something once
} );
Core hooks fired by MediaWiki:
HookWhen fired
wikipage.contentAfter page content is added or replaced in the DOM
wikipage.editformAfter the edit form is rendered
wikipage.diffAfter a diff is shown
mediawiki.page.readyWhen the DOM is ready and mediawiki.page.ready module has run

mw.notify: user notifications

mw.notification.notify() displays non-blocking notification banners. From notification.js:
// Simple text notification
mw.notification.notify( 'Your changes have been saved.' );

// Error notification
mw.notification.notify(
    mw.msg( 'myextension-save-error' ),
    { type: 'error' }
);

// Notification with a title
mw.notification.notify(
    $( '<p>' ).text( 'The operation completed.' ),
    {
        title: mw.msg( 'myextension-done-title' ),
        type: 'info',
        autoHide: true,
        autoHideSeconds: 5
    }
);

// Notification with a jQuery element and manual close
var notif = mw.notification.notify(
    $( '<span>' ).text( 'Processing...' ),
    { autoHide: false }
);
// Later:
notif.close();
Notification types: 'info' (default), 'warn', 'error', 'success'. Notifications announce to ARIA live regions for assistive technology. For notifications with complex widget content, pass options.ariaText with a plain-text description.

mw.message: i18n messages

// Get a message as a string
var str = mw.msg( 'myextension-hello', 'World' );
// → 'Hello, World!' (if the message is 'Hello, $1!')

// Get a message object for more control
var msgObj = mw.message( 'myextension-intro' );
console.log( msgObj.text() );     // plain text
console.log( msgObj.escaped() );  // HTML-escaped
console.log( msgObj.parse() );    // parsed HTML (requires mediawiki.jqueryMsg)

// Set messages (done automatically by ResourceLoader, but possible manually)
mw.messages.set( {
    'hello': 'Hello world',
    'hello-user': 'Hello, $1!'
} );

Using jQuery in MediaWiki

MediaWiki loads jQuery as the jquery module. In ResourceLoader modules, $ and jQuery are available globally:
// Standard jQuery usage
$( document ).ready( function () {
    $( '#my-button' ).on( 'click', function () {
        $( this ).addClass( 'active' );
    } );
} );

// With mw.hook — preferred over $(document).ready for content init
mw.hook( 'wikipage.content' ).add( function ( $content ) {
    $content.find( '.collapsible' ).each( function () {
        // Safe to initialize here even for content loaded via AJAX
    } );
} );
Prefer mw.hook( 'wikipage.content' ) over $( document ).ready() for initializing widgets in page content. The hook fires both on initial load and when content is dynamically replaced (for example, after a live preview).

Module patterns

IIFE (immediately invoked function expression)

Core modules that do not use packageFiles wrap their code in an IIFE to avoid leaking variables into the global scope:
( function () {
    'use strict';

    // Private state
    var initialized = false;

    function init() {
        if ( initialized ) {
            return;
        }
        initialized = true;
        // ...
    }

    // Attach to a hook so the module activates when content loads
    mw.hook( 'wikipage.content' ).add( init );

}() );

Package module pattern

For complex modules with multiple files, use packageFiles in extension.json and CommonJS-style require():
// resources/index.js
'use strict';

var Api = require( './api.js' );
var Ui  = require( './ui.js' );

// Initialize on content load
mw.hook( 'wikipage.content' ).add( function ( $content ) {
    var api = new Api();
    var ui  = new Ui( $content, api );
    ui.init();
} );
// resources/api.js
'use strict';

function MyExtensionApi() {
    this.mwApi = new mw.Api();
}

MyExtensionApi.prototype.fetchData = function ( pageId ) {
    return this.mwApi.get( {
        action: 'query',
        pageids: pageId,
        prop: 'revisions',
        rvprop: 'content'
    } );
};

module.exports = MyExtensionApi;
// resources/ui.js
'use strict';

function MyExtensionUi( $content, api ) {
    this.$content = $content;
    this.api = api;
}

MyExtensionUi.prototype.init = function () {
    var self = this;
    this.$content.find( '.myextension-load-btn' ).on( 'click', function () {
        var pageId = mw.config.get( 'wgArticleId' );
        self.api.fetchData( pageId ).then( function ( data ) {
            mw.notification.notify( 'Loaded!' );
        } );
    } );
};

module.exports = MyExtensionUi;

Accessing user info

// Check if the user is logged in
var isLoggedIn = mw.config.get( 'wgUserName' ) !== null;

// Get user groups
var groups = mw.config.get( 'wgUserGroups' );
var isSysop = groups.indexOf( 'sysop' ) !== -1;

// Get page and revision info
var pageInfo = mw.config.get( [
    'wgArticleId',
    'wgRevisionId',
    'wgPageName',
    'wgNamespaceNumber'
] );

Build docs developers (and LLMs) love