Was this page helpful?

Extensions with the CLI

Extensions are built and managed within a Contentful space through the Content Management APIs extension endpoint. To make it more convenient, the Contentful CLI supports managing the extensions.

Create a new UI Extension

To get started, install the Contentful CLI.

npm install -g contentful-cli

Following is the step by step procedure to build a UI Extension (Vanilla HTML5 UI Extension template) from scratch.

1. Authentication

To authenticate, following are required:

  1. ID of the space, where the extensions are used.

  2. A valid CMA token (obtaining a token).

2. Building an Extension

  • Start with building the index.html file.

Ensure that the index.html file includes:

  • The UI Extensions SDK.

  • Default Contentful styles and any other dependencies.

Following is the example of the index.html file:

<!DOCTYPE html>
  <meta charset="utf-8">
  <!-- UI Extensions CSS -->
  <link rel="stylesheet" href="https://contentful.github.io/ui-extensions-sdk/cf-extension.css">
  <!-- UI Extensions SDK -->
  <script src="https://unpkg.com/contentful-ui-extensions-sdk@3"></script>
  <!-- Custom markup of the UI Extension -->
  <div class="cf-form-field">
    <input type="text" class="cf-form-input">
    <div class="cf-form-hint">I am a UI Extension.</div>
    <div class="cf-form-hint">Instance params: <span class="instance-param-value"></span></div>
    <div class="cf-form-hint">Installation params: <span class="installation-param-value"></span></div>

  <!-- Custom logic of the UI Extension -->
    'use strict';

    // When UI Extensions SDK is loaded the callback will be executed.

    function initExtension (extensionsApi) {
      // "extensionsApi" is providing an interface documented here:
      // https://github.com/contentful/ui-extensions-sdk/blob/master/docs/ui-extensions-sdk-frontend.md

      // Automatically adjust UI Extension size in the Web App.

      var inputEl = document.querySelector('.cf-form-input');

      //  The field this UI Extension is assigned to.
      var field = extensionsApi.field;


      // Callback for changes of the field value.
      var detachValueChangeHandler = field.onValueChanged(valueChangeHandler);
      // Handle keyboard input.
      inputEl.addEventListener('input', keyboardInputHandler);
      // Handle DOM "onbeforeunload" event.
      window.addEventListener('onbeforeunload', unloadHandler);

      // Handler for external field value changes (e.g. when multiple authors are working on the same entry).
      function valueChangeHandler (value) {
        inputEl.value = value || '';

      // Event handler for keyboard input.
      function keyboardInputHandler () {
        var value = inputEl.value;
        if (typeof value !== 'string' || value === '') {
        } else {

      // Event handler for window unload.
      function unloadHandler () {
        window.removeEventListener('onbeforeunload', unloadHandler);
        inputEl.removeEventListener('input', keyboardInputHandler);

The index.html file is now ready to use. Refer to Vanilla HTML5 UI Extension template to understand more about how the code is organized.

3. Uploading an Extension to Contentful

Hosting Options

  • Internally hosted: The extension's source code is uploaded to Contentful as a bundled string where all local dependencies need to be inlined into one single file. Internal extensions are uploaded by using the srcdoc property and have a limit of 200kb. Use internal hosting if you don't want to host anything on your own and can accept the drawbacks (need for a non-standard build, file size limitation).
    Note: Internal hosting is not supported on Internet Explorer and Microsoft Edge.

For example,

  "id": "foo-extension",
  "fieldTypes": ["Symbol", "Text"],
  "name": "My wonderful foo extension",
  "sidebar": false,
  "srcdoc": "./dist/bundle.html"
  • Third party hosted The extension's source code is uploaded to a third party server by using the src property. Relative links in the root HTML are supported as expected. Any platform (such as S3, Heroku, personal corporate server, etc) is supported, provided it supports CORS policy and is available through HTTPS.

Use third party hosting when you want to be as flexible as possible with your development and deployment process.

For example,

  "id": "foo-extension",
  "fieldTypes": ["Symbol", "Text"],
  "name": "My wonderful foo extension",
  "sidebar": false,
  "src": "https://foo.com/extension"

Descriptor Files

The properties of an extension can be stored in a descriptor JSON file. The descriptor file can be passed to the CLI so the properties don't have to be provided individually.

Following is an example of a descriptor file:

  "id": "extn",
  "name": "Vanilla HTML5 UI Extension template",
  "src": "./index.html",
  "fieldTypes": ["Text"]

To make Contentful aware of the extension, navigate to the folder with the extension code and register the extension with the Contentful CLI:

$ contentful extension create --space-id $SPACE

If the extension is modified, use the update sub-command to push the changes to Contentful:

contentful extension update --space-id $SPACE --force

4. Testing from a Local Development Environment

Testing the extension on a local environment provides a preview to the changes without deploying it.

To test the extension on the local environment:

  • Run the extension on a local server as follows:

    python -m SimpleHTTPServer 3000
  • The extension is available at http://localhost:3000/.

  • Update the extension again by overriding its src via the following command:

    contentful extension update --space-id $SPACE --force \
    --src http://localhost:3000/

Note: As Contentful runs in an HTTPS environment, temporarily disable the security checks in the browser. For example, "Load unsafe scripts" in Chrome.

Post debugging, redeploy the extension without the src argument override to let it run from Contentful’s servers or any other external hosting solution.

5. Configuring a field to use an extension

Refer the section Assigning UI Extensions to a Field to assign the extension to the particular field where it needs to be used.

Managing UI Extensions

contentful extension is composed of the following five subcommands that are used to manage extensions:

  • Create - Creates an extension for the first time.

contentful extension create [options]

  • Update - Modifies an existing extension.

contentful extension update [options]

  • Delete - Permanently deletes an extension.

contentful extension delete [options]

  • Read - Reads the extension payload from Contentful.

contentful extension read [options]

  • List - Lists all the extensions created for the given space.

contentful extension list [options]

To learn how these commands work in CLI, refer the CLI documentation or use inline help of the CLI:

contentful extension --help

Version Locking

Contentful uses optimistic locking to avoid accidental non-idempotent operations such as update or delete.

While using the update and delete subcommands, it is mandatory to specify the version of the extension using the --version option. Alternatively, the --force option can be used that instructs the CLI to use the latest version of the extension.

Note: Using `--force` option might lead to accidental overwrites if multiple users are working on the same.

Programmatic Usage

To manage an extension programmatically, refer the Content Management SDKs.

Next steps

Not what you’re looking for? Try our FAQ.