How to Prepare a Custom Template

Scope: landing

Who can execute the methods: to complete the entire scenario, the user needs the strictest permission listed below — permission to export websites

Choose a tool for developing with an AI agent:

  • use Alaio Vibecode to build an app for Bitrix24 from a task description without knowing any programming language. The agent writes the code and deploys the app to a server, with no manual hosting setup
  • use the MCP server to develop a REST API integration in your own project. The agent refers to the official REST documentation

A custom template is a ready-made blueprint for a website or page that can be added to the site creation wizard. The wizard is the screen where a Bitrix24 user selects a design when creating a new website or page. Your own template appears in this list once an application registers it.

The template is created based on an existing website or page from the Sites section. First, the website is exported — its structure is unloaded into a data set that can be saved and passed on. This data set is then registered using the landing.demos.* methods from the Bitrix24 application.

Verifiable result: the template is registered for the application, returned by landing.demos.getList, and displayed in the website or page creation wizard.

The scenario consists of three steps:

  1. Export an existing website using landing.site.fullExport
  2. Pass the export result to landing.demos.register
  3. Verify the registration using landing.demos.getList

The call order matters: landing.demos.register accepts the result object returned by landing.site.fullExport, and landing.demos.getList verifies the registration result.

When to Use a Custom Template

Use a custom template if you need to:

  • add your own template to the website creation wizard
  • distribute a ready-made website or page through the application
  • reuse the same set of pages, blocks, and settings

If the template only needs to be installed in one Bitrix24 without reuse, it is sufficient to create and configure the website or page in the usual way.

If the template is distributed as an application with a website, refer to the articles Installing Website Templates and Website Requirements Before Publishing.

How a Custom Template Works

A template is made up of three interconnected parts:

  • the source website or page — the basis for the template, prepared in the Sites section
  • the export — the website structure as a data set, created by the landing.site.fullExport method
  • the registered template — an entry that appears in the wizard after calling landing.demos.register

The section's methods handle the individual steps of working with a template:

  • landing.demos.register — registers the template in the website and page creation wizard
  • landing.demos.getList — returns the registered templates and lets you verify the registration result. If the method is called from an application, the response includes only that application's templates
  • landing.demos.getSiteList — returns the website templates available in the wizard for the selected site type. The list includes both built-in Bitrix24 templates and matching templates you have registered. For example, for the store type, the method returns online store templates
  • landing.demos.getPageList — the same, but for individual page templates
  • landing.demos.unregister — deletes a registered template

How to Prepare the Template

Before exporting, check the website itself:

  • pages are correctly linked to each other
  • the necessary blocks and themes are used
  • images and external resources are accessible via working URLs
  • title, description, and preview data are prepared for the template. Preview data is the preview images used to identify the template in the wizard's list

If the website is multi-page, use a single theme for all pages. This helps maintain a consistent appearance after the template is installed.

Prepare the Data

Before starting, prepare:

  • the website identifier that will serve as the template source
  • an external template code, for example myfirstsite2026
  • the URL of a published page for preview_url
  • an installed application with OAuth authorization and the landing permission
  • an installed and initialized SDK: B24JsSDK, B24PhpSDK, or B24PySDK

You can get the website identifier using landing.site.getList or from the result of landing.site.add. The external code must contain only lowercase Latin letters and digits without separators.

In the examples, replace 326, myfirstsite2026, and the preview URL with your values. Run the examples from the selected tab sequentially in the same script: the variable containing the export result is used in the next step.

An OAuth token grants access to Bitrix24. Store it in the application settings or environment variables, and do not add it to the source code.

1. Export the Website

Call landing.site.fullExport. Pass the website identifier in the id parameter and the external template code in params.code. The method returns the complete website structure in the result field.

How to Use Examples in Documentation

// $b24 is a previously initialized B24JsSDK instance
        const exportResponse = await $b24.actions.v2.call.make({
          method: 'landing.site.fullExport',
          params: {
            id: 326,
            params: {
              code: 'myfirstsite2026',
              name: 'Auto Repair Website',
              preview_url: 'https://example.com/previews/myfirstsite2026'
            }
          }
        })
        
        if (!exportResponse.isSuccess) {
          throw new Error(exportResponse.getErrorMessages().join('; '))
        }
        
        const exportData = exportResponse.getData().result
        
// $b24Service is a previously initialized B24PhpSDK instance
        $response = $b24Service->core->call(
            'landing.site.fullExport',
            [
                'id' => 326,
                'params' => [
                    'code' => 'myfirstsite2026',
                    'name' => 'Auto Repair Website',
                    'preview_url' => 'https://example.com/previews/myfirstsite2026',
                ],
            ]
        );
        
        $exportData = $response->getResponseData()->getResult();
        
from b24pysdk.errors import BitrixAPIError, BitrixSDKException
        
        try:
            bitrix_response = client.landing.site.full_export(
                bitrix_id=326,
                params={
                    "code": "myfirstsite2026",
                    "name": "Auto Repair Website",
                    "preview_url": "https://example.com/previews/myfirstsite2026",
                },
            ).response
            export_data = bitrix_response.result
            print(export_data)
        except BitrixAPIError as error:
            print(
                "Bitrix API error",
                f"error: {error.error}",
                f"error_description: {error.error_description}",
                sep="\n",
            )
        except BitrixSDKException as error:
            print(f"Bitrix SDK error: {error.message}")
        except Exception as error:
            print(f"Unexpected error: {error}")
        

Abbreviated response:

{
            "result": {
                "charset": "UTF-8",
                "code": "myfirstsite2026",
                "name": "Auto Repair Website",
                "type": "page",
                "version": 3,
                "items": {
                    "myfirstsite2026": {
                        "code": "myfirstsite2026",
                        "name": "Auto Repair Website",
                        "type": "page",
                        "version": 3,
                        "items": {}
                    }
                }
            }
        }
        

Save the entire result object, not individual fields. The exportData, $exportData, and export_data variables contain data for the next step.

2. Register the Template

Pass the saved export object in the data parameter of landing.demos.register. Do not rebuild the structure manually: it already contains the external code, the page map in items, fields, blocks, and website settings.

The examples continue the code from the first step.

const registerResponse = await $b24.actions.v2.call.make({
          method: 'landing.demos.register',
          params: {
            data: exportData
          }
        })
        
        if (!registerResponse.isSuccess) {
          throw new Error(registerResponse.getErrorMessages().join('; '))
        }
        
        const registeredTemplateIds = registerResponse.getData().result
        if (registeredTemplateIds.length === 0) {
          throw new Error('Template was not registered')
        }
        
$response = $b24Service->core->call(
            'landing.demos.register',
            [
                'data' => $exportData,
            ]
        );
        
        $registeredTemplateIds = $response->getResponseData()->getResult();
        if ($registeredTemplateIds === []) {
            throw new RuntimeException('Template was not registered');
        }
        
from b24pysdk.errors import BitrixAPIError, BitrixSDKException
        
        try:
            bitrix_response = client.landing.demos.register(
                data=export_data,
            ).response
            registered_template_ids = bitrix_response.result
            if not registered_template_ids:
                raise RuntimeError("Template was not registered")
            print(registered_template_ids)
        except BitrixAPIError as error:
            print(
                "Bitrix API error",
                f"error: {error.error}",
                f"error_description: {error.error_description}",
                sep="\n",
            )
        except BitrixSDKException as error:
            print(f"Bitrix SDK error: {error.message}")
        except Exception as error:
            print(f"Unexpected error: {error}")
        

A successful response contains the identifiers of the created or updated templates:

{
            "result": [5]
        }
        

Save the result array. If it is empty, do not proceed to the UI check; verify the request data first.

3. Verify the Registration

Call landing.demos.getList and find the entry whose XML_ID matches myfirstsite2026. When called from an application, the method returns only that application's templates.

const listResponse = await $b24.actions.v2.call.make({
          method: 'landing.demos.getList',
          params: {
            params: {
              select: ['ID', 'XML_ID', 'TITLE', 'TYPE']
            }
          }
        })
        
        if (!listResponse.isSuccess) {
          throw new Error(listResponse.getErrorMessages().join('; '))
        }
        
        const template = listResponse
          .getData()
          .result
          .find((item) => item.XML_ID === 'myfirstsite2026')
        
        if (!template) {
          throw new Error('Template was not found')
        }
        
$response = $b24Service->core->call(
            'landing.demos.getList',
            [
                'params' => [
                    'select' => ['ID', 'XML_ID', 'TITLE', 'TYPE'],
                ],
            ]
        );
        
        $templates = $response->getResponseData()->getResult();
        $template = array_values(array_filter(
            $templates,
            static fn(array $item): bool => $item['XML_ID'] === 'myfirstsite2026'
        ))[0] ?? null;
        if ($template === null) {
            throw new RuntimeException('Template was not found');
        }
        
from b24pysdk.errors import BitrixAPIError, BitrixSDKException
        
        try:
            bitrix_response = client.landing.demos.get_list(
                params={
                    "select": ["ID", "XML_ID", "TITLE", "TYPE"],
                },
            ).response
            templates = bitrix_response.result
        
            template = next(
                (item for item in templates if item["XML_ID"] == "myfirstsite2026"),
                None,
            )
            if template is None:
                raise RuntimeError("Template was not found")
            print(template)
        except BitrixAPIError as error:
            print(
                "Bitrix API error",
                f"error: {error.error}",
                f"error_description: {error.error_description}",
                sep="\n",
            )
        except BitrixSDKException as error:
            print(f"Bitrix SDK error: {error.message}")
        except Exception as error:
            print(f"Unexpected error: {error}")
        

Abbreviated response:

{
            "result": [
                {
                    "ID": "5",
                    "XML_ID": "myfirstsite2026",
                    "TITLE": "Auto Repair Website",
                    "TYPE": "page"
                }
            ]
        }
        

Verify the Result

Check that:

  • landing.demos.register returned a non-empty array of identifiers
  • landing.demos.getList returned a template with the expected XML_ID, TITLE, and TYPE values
  • the template appeared in the website or page creation wizard and its preview opens

Errors and Troubleshooting

If a method returns an error or the scenario result does not match the expected result, check the request data and user permissions.

Error Code or Text

Cause and Action

BX_EMPTY_REQUIRED

A required field is missing at the second step. Check data.code and the code field of every page in data.items

REGISTER_ERROR_DATA

Invalid data was passed at the second step. Pass the complete result object from landing.site.fullExport in data

CONTENT_IS_BAD

The template content failed validation. Check it using landing.repo.checkcontent, then register the template again

AI_SITE_EXPORT_NOT_ALLOWED

Exporting AI websites is not supported. Select another website at the first step

ACCESS_DENIED

At the first step, check the user's permission to export websites; at the second and third steps, check the View permission in the Sites section

Template was not found

At the third step, check XML_ID, the application context, and the result of landing.demos.register, then repeat the third step

Preview does not open

Check that preview_url is available without authorization

Important Notes

  • For a multi-page website, pass the complete result of landing.site.fullExport in data, including the page map in items
  • The type field defines the template purpose, while tpl_type defines its location in the wizard: S for a website and P for a page
  • External images and preview_url must remain available after the template is registered
  • Pass OAuth tokens only through application settings or environment variables; do not add them to source code
  • To localize the title and description, pass the lang and lang_original parameters to landing.demos.register
  • To delete a template, retrieve its external code from the XML_ID field using landing.demos.getList, then pass the code to landing.demos.unregister

Continue Learning