> For the complete documentation index, see [llms.txt](https://docs.iexexchanger.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.iexexchanger.com/help-center/administrirovanie/polzovatelskie-vstavki-html-css-i-javascript.md).

# Пользовательские вставки HTML, CSS и JavaScript

`ng-custom` — это специальный каталог основного сайта, через который можно подключать пользовательские HTML, CSS и JavaScript-вставки без изменения исходного Angular-кода и без пересборки основного frontend-приложения.

Этот механизм нужен для подключения внешних сервисов и дополнительных клиентских вставок, которые должны работать на публичной части сайта.

Через `ng-custom` можно подключать:

* онлайн-чаты;
* системы аналитики;
* рекламные пиксели;
* сторонние JavaScript-виджеты;
* HTML-коды внешних сервисов;
* verification meta-теги;
* JSON-LD-разметку;
* `noscript`-коды;
* собственные CSS-файлы;
* пользовательский JavaScript.

Публичный путь для файлов всегда один: `/ng-custom/`

Пример публичной ссылки:

```
https://example.com/ng-custom/client-scripts.js
```

***

## Главное правило

`ng-custom` работает только для основного сайта, то есть для Angular frontend.

Если проект разделён так:

```
example.com          — основной сайт / frontend / Angular
app.example.com      — backend / Laravel / админка / API
```

то `ng-custom` нужно создавать только в основном сайте:

```
public/ng-custom/
```

Не нужно создавать `ng-custom` в backend-папке, в админке или в API-проекте.

`ng-custom` не влияет на Laravel backend, API, админ-панель и backend-страницы. Он предназначен только для публичного frontend-сайта.

***

## Как устроена система

В проекте могут встречаться два типа каталогов `ng-custom`.

<table><thead><tr><th width="257.546875">/ng-custom/</th><th>Что означает</th></tr></thead><tbody><tr><td><code>public/ng-custom/</code></td><td>Основная runtime-папка для клиентских вставок на production</td></tr><tr><td><code>dist/.../ng-custom/</code></td><td>Папка внутри результата сборки Angular</td></tr></tbody></table>

Для ручной настройки на сервере используйте именно:

```
public/ng-custom/
```

Каталог `dist` — это результат сборки. Его не рекомендуется редактировать вручную, потому что при следующей сборке файлы могут быть перезаписаны.

Правильная логика такая:

```
public/ng-custom/     — редактируется клиентом на сервере
dist/                 — результат сборки, вручную не редактируется
```

***

### Структура каталога

Внутри `public/ng-custom/` создаются основные файлы:

```
client-scripts.js
client-snippets.html
ssr-head.html
ssr-body-start.html
ssr-body-end.html
```

Итоговая структура:

```
public/
└── ng-custom/
    ├── client-scripts.js
    ├── client-snippets.html
    ├── ssr-head.html
    ├── ssr-body-start.html
    └── ssr-body-end.html
```

Если нужны отдельные SSR-вставки для разных языков, можно добавить языковые папки:

```
public/
└── ng-custom/
    ├── ru/
    │   └── ssr-head.html
    ├── en/
    │   └── ssr-head.html
    ├── uk/
    │   └── ssr-head.html
    ├── client-scripts.js
    ├── client-snippets.html
    ├── ssr-head.html
    ├── ssr-body-start.html
    └── ssr-body-end.html
```

Если языкового файла нет, система использует общий файл из корня `public/ng-custom/`.

***

## Режимы работы

`ng-custom` поддерживает два режима работы:

<table><thead><tr><th width="176.4140625">Режим</th><th width="284.00390625">Что делает</th><th>Для чего использовать</th></tr></thead><tbody><tr><td>Browser Mode</td><td>Загружает код уже в браузере после открытия сайта</td><td>Онлайн-чаты, пиксели, виджеты, JS-коды</td></tr><tr><td>SSR Mode</td><td>Вставляет код сразу в исходный HTML, который отдаёт сервер</td><td>Meta-теги, JSON-LD, noscript, SEO-коды</td></tr></tbody></table>

Оба режима можно включить одновременно.

## Browser Mode

Browser Mode — это режим, при котором пользовательский код загружается уже в браузере после открытия страницы.

Этот режим подходит для сервисов, которым не обязательно быть в исходном HTML страницы.

Используйте Browser Mode для:

* онлайн-чатов;
* рекламных пикселей;
* аналитики;
* сторонних JavaScript-виджетов;
* pop-up сервисов;
* callback-виджетов;
* небольших пользовательских скриптов.

Файлы Browser Mode:

```
client-scripts.js
client-snippets.html
```

{% stepper %}
{% step %}

### client-scripts.js

`client-scripts.js` используется для JavaScript-кода.

Этот файл:

* выполняется только в браузере;
* не выполняется на SSR;
* не входит в Angular bundle;
* может изменяться отдельно от основного приложения.

Пример подключения внешнего виджета:

```js
window.IEX_CUSTOM_INIT = function (api) {
    api.onReady(function () {
        api.loadScript('https://example.com/widget.js', {
            id: 'example-widget',
            async: true,
            defer: true
        });
    });
};
```

{% endstep %}

{% step %}

### API внутри client-scripts.js

В `client-scripts.js` доступен объект `api`.

| Метод                           | Для чего нужен                                    |
| ------------------------------- | ------------------------------------------------- |
| `api.loadScript(src, options)`  | Подключает внешний JavaScript-файл                |
| `api.injectHtml(html, options)` | Вставляет HTML в страницу и выполняет script-теги |
| `api.onReady(callback)`         | Выполняет код после готовности DOM                |
| `api.safeRun(callback, label)`  | Выполняет код безопасно через try/catch           |

Пример безопасного выполнения кода:

```js
window.IEX_CUSTOM_INIT = function (api) {
    api.onReady(function () {
        api.safeRun(function () {
            console.log('Custom code loaded');
        }, 'custom-log');
    });
};
```

{% endstep %}

{% step %}

### client-snippets.html

`client-snippets.html` используется для готового HTML-кода от сторонних сервисов.

Например, если внешний сервис выдал готовый блок с `div` и `script`, его можно вставить в этот файл.

Пример:

```html
<div id="support-chat"></div>

<script>
    window.supportChatId = 'client-123';
</script>

<script src="https://example.com/chat.js"></script>
```

Система обработает файл автоматически:

<table><thead><tr><th width="270.0703125">Что находится в файле</th><th>Что сделает система</th></tr></thead><tbody><tr><td>Обычные HTML-элементы</td><td>Добавит в страницу</td></tr><tr><td><code>meta</code>, <code>link</code>, <code>style</code>, <code>title</code></td><td>Перенесёт в <code>head</code></td></tr><tr><td><code>script</code></td><td>Пересоздаст и выполнит</td></tr><tr><td><code>&#x3C;base></code></td><td>Проигнорирует, чтобы не сломать маршруты сайта</td></tr></tbody></table>
{% endstep %}
{% endstepper %}

## SSR Mode

SSR Mode — это режим, при котором содержимое файлов вставляется прямо в HTML, который отдаёт сервер.

Этот режим нужен, если внешний сервис требует, чтобы код был именно в исходном HTML страницы.

Используйте SSR Mode для:

* Google Site Verification;
* Yandex Verification;
* meta-тегов подтверждения домена;
* JSON-LD;
* Schema.org;
* SEO-разметки;
* `noscript`-кодов;
* сервисов, которые требуют вставку сразу после `<body>`.

Файлы SSR Mode:

```
ssr-head.html
ssr-body-start.html
ssr-body-end.html
```

{% stepper %}
{% step %}

### ssr-head.html

`ssr-head.html` вставляется перед закрывающим тегом:

```html
</head>
```

Используйте для кода, который должен находиться внутри `head`.

Подходит для:

* verification meta-тегов;
* JSON-LD;
* Schema.org;
* `preconnect`;
* `stylesheet`;
* дополнительных `link`-тегов.

Пример:

```html
<meta name="google-site-verification" content="token">

<link rel="preconnect" href="https://example.com">

<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Organization",
    "name": "Exchange"
}
</script>
```

{% endstep %}

{% step %}

### ssr-body-start.html

`ssr-body-start.html` вставляется сразу после открытия:

```html
<body>
```

Используйте для кодов, которые должны быть размещены в начале `body`.

Подходит для:

* `noscript`;
* Google Tag Manager fallback;
* сервисов, которые требуют вставку сразу после `<body>`.

Пример:

```html
<noscript>
    <iframe src="https://example.com/ns.html?id=demo"
            height="0"
            width="0"
            style="display:none;visibility:hidden"></iframe>
</noscript>
```

{% endstep %}

{% step %}

### ssr-body-end.html

`ssr-body-end.html` вставляется перед закрывающим тегом:

```html
</body>
```

Используйте для скриптов, которые должны быть в исходном HTML, но не должны блокировать загрузку страницы.

Пример:

```html
<script src="https://example.com/tracker.js" defer></script>
```

{% endstep %}
{% endstepper %}

***

## Создание папки на FastPanel

На сервере нужно создать каталог `public/ng-custom/` в основном frontend-сайте.

Перед выполнением команд замените:

```
имя_пользователя_frontend
```

на пользователя основного сайта в FastPanel.

Замените:

```
ваш_домен
```

на основной домен сайта.

Создайте папку:

```bash
mkdir -p /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom
```

Создайте основные файлы:

```bash
touch /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/client-scripts.js
touch /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/client-snippets.html
touch /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/ssr-head.html
touch /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/ssr-body-start.html
touch /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/ssr-body-end.html
```

Если нужны языковые папки:

```bash
mkdir -p /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/ru
mkdir -p /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/en
mkdir -p /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/uk
mkdir -p /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/ka
```

***

## Настройка ENV

В ENV основного frontend/SSR-сайта укажите путь к runtime-папке `ng-custom`.

Пример:

```dotenv
CLIENT_CUSTOM_DIR=/var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom
CLIENT_CUSTOM_SCRIPTS_ENABLED=true
CLIENT_CUSTOM_SSR_ENABLED=true
```

<table><thead><tr><th width="318.78125">Переменная</th><th>Что означает</th></tr></thead><tbody><tr><td><code>CLIENT_CUSTOM_DIR</code></td><td>Полный путь к папке <code>public/ng-custom</code></td></tr><tr><td><code>CLIENT_CUSTOM_SCRIPTS_ENABLED=true</code></td><td>Включает Browser Mode</td></tr><tr><td><code>CLIENT_CUSTOM_SSR_ENABLED=true</code></td><td>Включает SSR Mode</td></tr></tbody></table>

Если нужны только browser-вставки:

```env
CLIENT_CUSTOM_SCRIPTS_ENABLED=true
CLIENT_CUSTOM_SSR_ENABLED=false
```

Если нужны только SSR-вставки:

```env
CLIENT_CUSTOM_SCRIPTS_ENABLED=false
CLIENT_CUSTOM_SSR_ENABLED=true
```

После изменения ENV нужно перезапустить SSR-процесс сайта.

После изменения самих файлов внутри `public/ng-custom/` пересборка Angular обычно не нужна.

## Настройка Nginx

В nginx-конфиг основного frontend-домена добавьте отдельный блок:

```nginx
location ^~ /ng-custom/ {
    alias /var/www/имя_пользователя_frontend/data/www/ваш_домен/public/ng-custom/;
    try_files $uri =404;

    expires -1;
    add_header Cache-Control "no-store, no-cache, must-revalidate" always;
    access_log off;
}
```

Важно:

<table><thead><tr><th width="299.15234375">Правило</th><th>Почему важно</th></tr></thead><tbody><tr><td>Использовать <code>alias</code></td><td>Так Nginx отдаёт файлы из нужной папки</td></tr><tr><td><code>alias</code> должен заканчиваться <code>/</code></td><td>Это нужно для корректного сопоставления путей</td></tr><tr><td>Не ставить долгий кеш</td><td>Файлы могут часто меняться вручную</td></tr><tr><td>Указывать frontend-папку</td><td><code>ng-custom</code> относится к основному сайту, а не к backend</td></tr></tbody></table>

## Порядок поиска SSR-файлов

SSR-файлы могут быть общими или языковыми.

Допустим:

```
язык страницы: en
язык по умолчанию: ru
файл: ssr-head.html
```

Система ищет файл в таком порядке:

```
public/ng-custom/en/ssr-head.html
public/ng-custom/ru/ssr-head.html
public/ng-custom/ssr-head.html
dist/.../browser/en/ng-custom/ssr-head.html
dist/.../browser/ru/ng-custom/ssr-head.html
dist/.../browser/ng-custom/ssr-head.html
```

Основное место для настройки:

```
public/ng-custom/
```

`dist` используется как резервный слой после сборки, а не как основное место ручной настройки.

<details>

<summary>Как добавить код для всех языков</summary>

Если код одинаковый для всех языков, используйте общий файл:

```
public/ng-custom/ssr-head.html
```

Пример:

```html
<meta name="google-site-verification" content="token">
```

</details>

<details>

<summary>Как добавить код только для одного языка</summary>

Если код нужен только для английской версии, используйте:

```
public/ng-custom/en/ssr-head.html
```

Пример:

```html
<meta name="custom-language" content="en">
```

Если код нужен только для русской версии:

```
public/ng-custom/ru/ssr-head.html
```

</details>

## Важное отличие browser-файлов от SSR-файлов

Browser-файлы загружаются только из корня:

```
/ng-custom/client-scripts.js
/ng-custom/client-snippets.html
```

Они не загружаются автоматически из языковых папок:

```
/ng-custom/en/client-scripts.js
/ng-custom/ru/client-scripts.js
```

Если нужен разный browser-код по языкам, сделайте условие внутри общего `client-scripts.js`.

Пример:

```js
window.IEX_CUSTOM_INIT = function (api) {
    api.onReady(function () {
        const lang = window.location.pathname.split('/')[1] || 'ru';

        if (lang === 'en') {
            api.loadScript('https://example.com/en-widget.js', {
                id: 'en-widget',
            });
            return;
        }

        api.loadScript('https://example.com/default-widget.js', {
            id: 'default-widget',
        });
    });
};
```

## Подключение внешнего JavaScript

Если сервис дал код:

```html
<script src="https://example.com/widget.js"></script>
```

лучше подключить его через `client-scripts.js`.

Пример:

```js
window.IEX_CUSTOM_INIT = function (api) {
    api.onReady(function () {
        api.loadScript('https://example.com/widget.js', {
            id: 'example-widget',
            async: true,
            defer: true
        });
    });
};
```

`id` нужен, чтобы один и тот же скрипт не добавлялся повторно.

## Подключение готового HTML-кода

Если сервис дал готовый блок:

```html
<div id="support-chat"></div>
<script>
    window.supportChatId = 'client-123';
</script>
<script src="https://example.com/chat.js"></script>
```

добавьте его в:

```
client-snippets.html
```

Система сама вставит HTML в страницу и выполнит скрипты.

## Подключение собственного CSS

Создайте CSS-файл:

```
public/ng-custom/custom.css
```

Затем подключите его в `ssr-head.html`:

```html
<link rel="stylesheet" href="/ng-custom/custom.css">
```

После этого файл будет доступен по адресу:

```
/ng-custom/custom.css
```

***

## Проверка работы

Проверьте, что файл отдаётся через Nginx:

```bash
curl -I https://example.com/ng-custom/client-scripts.js
```

Ожидаемый результат:

```
HTTP/2 200
Cache-Control: no-store, no-cache, must-revalidate
```

Проверьте SSR-вставки:

```bash
curl -s https://example.com/ru/ | grep "iex-custom"
```

Если SSR-вставка работает, в HTML будут маркеры:

```html
<!--iex-custom:ssr-head:start-->
<!--iex-custom:ssr-head:end-->
```

Для `body-start`:

```html
<!--iex-custom:ssr-body-start:start-->
<!--iex-custom:ssr-body-start:end-->
```

Для `body-end`:

```html
<!--iex-custom:ssr-body-end:start-->
<!--iex-custom:ssr-body-end:end-->
```

***

## Почему код не отображается

Проверьте:

<table><thead><tr><th width="219.65234375">Что проверить</th><th>Что должно быть</th></tr></thead><tbody><tr><td>Папка</td><td>Создана <code>public/ng-custom/</code> в основном frontend-сайте</td></tr><tr><td>ENV</td><td>Указан правильный <code>CLIENT_CUSTOM_DIR</code></td></tr><tr><td>Browser Mode</td><td><code>CLIENT_CUSTOM_SCRIPTS_ENABLED=true</code></td></tr><tr><td>SSR Mode</td><td><code>CLIENT_CUSTOM_SSR_ENABLED=true</code></td></tr><tr><td>SSR-процесс</td><td>Перезапущен после изменения ENV</td></tr><tr><td>Nginx</td><td><code>alias</code> указывает на правильную папку</td></tr><tr><td>Файл</td><td>Файл не пустой и содержит рабочий код</td></tr><tr><td>Домен</td><td>Проверяется основной сайт, а не <code>app.</code> домен админки</td></tr></tbody></table>

## Что нельзя делать

Не редактируйте `dist` как основную папку настройки.

Не создавайте `ng-custom` в backend-проекте.

Не вставляйте полный HTML-документ:

```html
<html>
<head></head>
<body></body>
</html>
```

Вставляйте только нужные фрагменты.

Не используйте тег:

```html
<base>
```

Он может сломать ссылки и маршрутизацию сайта.

Не давайте доступ к папке `ng-custom` случайным пользователям, потому что JavaScript из этой папки выполняется на сайте.

## Рекомендуемые сценарии

<table><thead><tr><th width="280.6328125">Задача</th><th>Куда вставлять</th></tr></thead><tbody><tr><td>Онлайн-чат</td><td><code>client-scripts.js</code> или <code>client-snippets.html</code></td></tr><tr><td>Meta verification</td><td><code>ssr-head.html</code></td></tr><tr><td>JSON-LD</td><td><code>ssr-head.html</code></td></tr><tr><td>Noscript fallback</td><td><code>ssr-body-start.html</code></td></tr><tr><td>Внешний JS-файл</td><td><code>client-scripts.js</code></td></tr><tr><td>Готовый HTML-код сервиса</td><td><code>client-snippets.html</code></td></tr><tr><td>Собственный CSS</td><td><code>custom.css</code> + подключение в <code>ssr-head.html</code></td></tr><tr><td>Скрипт перед закрытием body</td><td><code>ssr-body-end.html</code></td></tr></tbody></table>

***

## Итоговая схема

Основной сайт:

```
example.com
```

Рабочая папка для вставок:

```
public/ng-custom/
```

Публичный URL:

```
/ng-custom/
```

ENV:

```env
CLIENT_CUSTOM_DIR=/полный/путь/к/public/ng-custom
CLIENT_CUSTOM_SCRIPTS_ENABLED=true
CLIENT_CUSTOM_SSR_ENABLED=true
```

Nginx:

```nginx
location ^~ /ng-custom/ {
    alias /полный/путь/к/public/ng-custom/;
    try_files $uri =404;

    expires -1;
    add_header Cache-Control "no-store, no-cache, must-revalidate" always;
    access_log off;
}
```

Проверка:

```bash
curl -I https://example.com/ng-custom/client-scripts.js
curl -s https://example.com/ru/ | grep "iex-custom"
```

***

## Коротко

`ng-custom` — это механизм для подключения пользовательских HTML, CSS и JavaScript-вставок на основном сайте iEXExchanger.

Он позволяет подключать сторонние сервисы, аналитику, онлайн-чаты, SEO-разметку и собственные скрипты без изменения исходного кода платформы и без пересборки Angular-приложения.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.iexexchanger.com/help-center/administrirovanie/polzovatelskie-vstavki-html-css-i-javascript.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
