Yandex DataLens HTML
Use this skill to build or fix a standalone HTML page or report in DataLens. DataLens takes a whole self contained HTML document — often an AI generated report with tables, charts, and a CSV/download button — and renders it in a sandboxed, CSP locked iframe, so normal web code silently breaks. Reach for it when generating such a page from scratch, and when one already in DataLens misbehaves: images, fonts, scripts, or CDN libraries blocked or throwing Content Security Policy errors; fetch/XHR/localStorage failing; charts blank; a download or Export button doing nothing; an upload rejected as too large or the wrong encoding; or the page needing to match the user's DataLens theme (light/dark) and language (ru/en). Also covers which CDNs and hosts are allowed and making the page fully self contained. Not for DataLens chart cells or HTML markup table columns.
- Скачивания
- 0
- В избранном
- 0
- Комментарии
- 0
- Просмотры
- 2
Установить скилл
Добавьте инструмент одной командой или скачайте проверенный архив версии.
npx skills add datalens-tech/datalens-skills --skill datalens-html-pages- Версия
- 1.0.0+22efc751ded1
- Автор
- Владимир Ломтев
- Репозиторий
- datalens-tech/datalens-skills
Как установить
- 1Скопируйте команду из блока установки.
- 2Запустите её в терминале из каталога проекта.
Документация
DataLens HTML pages
DataLens serves standalone HTML pages — whole documents, usually AI-generated reports — by
storing them in a private bucket and rendering them in a locked-down sandboxed iframe from a
short-TTL presigned URL, with a Content-Security-Policy injected as a <meta> tag at
upload. You author a complete <!DOCTYPE html> page; scripts run, but only from an allowlist of
CDNs, and most browser APIs are blocked.
Not this skill: HTML inside a chart — markup functions, HTML-markup table cells,
ChartEditor.generateHtml. That is a different feature with a strict tag/attribute allowlist and no scripts at all. This skill is only for standalone HTML pages.
The runtime in one picture
- Sandboxed iframe:
sandbox="allow-scripts",allow="",referrerpolicy="no-referrer", and crucially noallow-same-origin— the page runs in an opaque origin (parent also sendsCross-Origin-Opener-Policy: same-origin). Same-origin isolation depends on this; never assume same-origin access. - Injected CSP (you do not write it — the platform prepends it, idempotently):
default-src 'none'with a small allowlist forscript/style/font/img/media, andconnect-src,form-action,frame-src,object-src,worker-src,base-uriall'none'. Full policy in references/csp-and-sandbox.md. - Served from a presigned GET that expires in 10–30 seconds, after a server-side permission check. Theme/language ride along as signed query params.
The net effect: make the page fully self-contained. Inline your own CSS/JS (the CSP allows
'unsafe-inline'/'unsafe-eval'), pull libraries only from allowlisted CDNs, and never rely on
network, storage, or the parent page.
Authoring rules
Allowed external resources (everything else is blocked by the CSP):
| Resource | Allowed from |
|---|---|
| Scripts | cdn.jsdelivr.net, cdnjs.cloudflare.com, cdn.tailwindcss.com, yastatic.net (+ inline) |
| Styles | the above + fonts.googleapis.com (+ inline) |
| Fonts | cdn.jsdelivr.net, cdnjs.cloudflare.com, fonts.gstatic.com, data: |
| Images | yastatic.net, data:, blob: |
| Media | data:, blob: only |
Load Google Fonts the standard way (<link> CSS from fonts.googleapis.com, font files from
fonts.gstatic.com). Mirror off-allowlist libraries (unpkg, plot.ly, d3js.org, jQuery) through
jsdelivr/cdnjs.
Blocked — do not use (they throw or silently fail):
- Storage:
localStorage,sessionStorage,indexedDB,document.cookie, Cache API → keep all state in memory. - Network:
fetch,XMLHttpRequest,WebSocket,EventSource,sendBeacon—connect-srcis'none'. Inline your data into the page instead of fetching it. - Frames/objects/forms: nested
<iframe>,<object>,<embed>,<form>submission,<base>. - Workers, popups, dialogs, downloads, camera/geolocation/fullscreen, navigating the parent
frame, and ordinary link navigation — an
<a href>won't open on its own; route clicks throughOPEN_URL(see Opening links below).
Theme & language — read them from the query string:
const theme = new URLSearchParams(location.search).get('theme'); // 'light' | 'dark' | 'system'
const lang = new URLSearchParams(location.search).get('lang'); // 'ru' | 'en'
When designing and generating HTML, try to create a page that supports available themes, languages and also adaptive: some users will view them via mobile web version of the DataLens.
Exporting a file — the download APIs are blocked; hand data to the host instead. The host
verifies event.source, applies a MIME allowlist + size cap, sanitizes the filename, and creates
the download:
parent.postMessage({ code: 'EXPORT', data: { name: 'report.csv', mime: 'text/csv', data: csvString } }, '*');
Opening links — an ordinary <a href> does not navigate inside the sandbox (opaque
origin; even target="_blank" only reaches about:blank). To open a URL, ask the host: intercept
the click, preventDefault(), and post OPEN_URL. One delegated listener covers every link:
document.addEventListener('click', (e) => {
const a = e.target.closest('a[href]');
if (!a) return;
const href = a.getAttribute('href');
if (!href || href.startsWith('#')) return; // in-page anchors scroll normally — leave them
e.preventDefault();
parent.postMessage({ code: 'OPEN_URL', data: { url: a.href } }, '*');
});
Encoding & size (enforced at upload):
- Valid UTF-8; declare
<meta charset="utf-8">within the first 1024 bytes. The server detects mojibake but never repairs it. - Do not wrap the document in markdown code fences (
```html) — they prematurely close<head>. - Page size up to ~10 MB, ideally keep below ~5 MB.
See references/authoring-constraints.md for the exhaustive lists, and assets/report.template.html for a compliant starting point.
Design — before building a dashboard or report page, ask the user whether they want it styled
per the DataLens design principles (unless they already said so). If you cannot ask — a
non-interactive run with no way to get an answer — default to not applying them: style the page
plainly and say in your output that the design principles were skipped. If they agree, follow
references/design-principles.md — layout grid, chart-type
selection, colors, number formatting, and theming. It relies on the DataLens design tokens in
assets/dl-theme-tokens.css and base dashboard styles in
assets/dl-dashboard.css — inline both files' contents into the page's
<style> (the page must be self-contained) and set g-root g-root_theme_light|dark on the root
element per the theme query param. If the user declines, skip these three files and style the
page however they ask; the sandbox and CSP rules above still apply.
Validate before you upload
Lint the page against the exact CSP allowlist and sandbox constraints — a clean run means nothing will be blocked or stripped at render:
python scripts/validate_page.py report.html # errors + warnings
python scripts/validate_page.py --strict report.html # warnings fail too (CI mode)
cat report.html | python scripts/validate_page.py - # from stdin
It flags off-allowlist resource hosts, blocked APIs (storage/fetch/workers/…), blocked tags,
missing charset, mojibake, wrapping code fences, and oversize pages. Run
python scripts/validate_page.py --self-test to check the linter itself.
Serve & publish
Serving is server-side; know the shape so you author correctly:
- Presigned GET, 10–30 s TTL, minted only after a permission check (no TOCTOU gap). Don't build flows that assume a long-lived URL.
- Object stored with
Content-Type: text/html; charset=utf-8,Content-Disposition: inline,Cache-Control: no-store. Upload is server-side JSON-RPC (no presigned PUTs — the server owns CSP injection and metadata). - The iframe carries the sandbox above; the parent sends
COOP: same-origin.
Accepted risks to design around (details in
references/csp-and-sandbox.md): a URL opened top-level (within its
TTL) loses the iframe sandbox but keeps the injected CSP; a page can self-navigate via
<meta http-equiv="refresh">; allowlisted CDNs are not SRI-pinned. Because the frame is
same-origin-isolated and network-less, do not put viewer data, parameters, or live LLM output
that must stay private into the page — it is a report, not a trusted app surface.
Common pitfalls → fixes
| Symptom | Cause | Fix |
|---|---|---|
| Library never loads / CSP error in console | script/style host off the allowlist | serve it from jsdelivr / cdnjs / tailwind / yastatic |
| Data never appears | code calls fetch/XHR |
inline the dataset into the page at generation time |
| "localStorage is not available" / throws | storage API in sandbox | keep state in memory |
| Fonts don't render | font host off-allowlist | Google Fonts (fonts.googleapis.com CSS + fonts.gstatic.com files) or jsdelivr/cdnjs |
| Image is blank | http:// or off-allowlist host |
use yastatic.net, data:, or blob: |
| Download button does nothing | download APIs blocked | post {code:'EXPORT', data:{name,mime,data}} to the parent |
| Clicking a link does nothing | links don't navigate in the sandbox | intercept the click and post {code:'OPEN_URL', data:{url}} |
| Page renders as plain text / broken head | wrapping markdown code fences | remove the ``` fences |
| Upload rejected | > 10 MB or invalid UTF-8 | shrink assets; ensure UTF-8 + early <meta charset> |
Требования и возможности
Файлы версии
| Путь | Размер | SHA256 |
|---|---|---|
| SKILL.md | 9967 | 44b02ac434588ab9... |
| assets/dl-dashboard.css | 439 | 58ad1186f1373283... |
| assets/dl-theme-tokens.css | 59401 | dc78bd2e20a50549... |
| assets/report.template.html | 6567 | 909a5c9df2e08f4c... |
| references/authoring-constraints.md | 4855 | 515c43778a543e7b... |
Частые вопросы
- Как установить Yandex DataLens HTML?
- Используйте команду
npx skills add datalens-tech/datalens-skills --skill datalens-html-pagesили скачайте ZIP-архив. - Можно ли скачать Yandex DataLens HTML бесплатно?
- Да, опубликованную версию можно скачать из маркетплейса бесплатно.
Похожие инструменты
Смотреть всеВойдите, чтобы оставить комментарий.
Комментариев пока нет.